From 3b40c04071ce3c0d74d19518ef884fed5c981fd7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Jul 2011 10:39:16 +0200 Subject: wl12xx: remove wext dependencies This driver uses IW_ESSID_MAX_SIZE when it should be using IEEE80211_MAX_SSID_LEN instead. Signed-off-by: Johannes Berg Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/cmd.h | 4 ++-- drivers/net/wireless/wl12xx/main.c | 2 +- drivers/net/wireless/wl12xx/scan.h | 6 +++--- drivers/net/wireless/wl12xx/wl12xx.h | 4 ++-- drivers/net/wireless/wl12xx/wl12xx_80211.h | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 1f7037292c15..bba077ecd945 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -239,7 +239,7 @@ struct wl1271_cmd_join { u8 bss_type; u8 channel; u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ctrl; /* JOIN_CMD_CTRL_* */ u8 reserved[3]; } __packed; @@ -528,7 +528,7 @@ struct wl1271_cmd_bss_start { /* wl1271_ssid_type */ u8 ssid_type; u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 padding_1[2]; /* Basic rate set */ diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e58c22d21e39..3418299e17c8 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1997,7 +1997,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl1271_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); - memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); + memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); wl->ssid_len = 0; wl->bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE; diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index d882e4da71b7..0b2a2987439d 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h @@ -77,7 +77,7 @@ struct basic_scan_params { u8 ssid_len; /* in order to align */ u8 padding1[2]; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; /* Band to scan */ u8 band; u8 use_ssid_list; @@ -167,7 +167,7 @@ struct wl1271_cmd_sched_scan_config { u8 filter_type; u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 n_probe_reqs; /* Number of probes requests per channel */ @@ -194,7 +194,7 @@ enum { struct wl1271_ssid { u8 type; u8 len; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; /* u8 padding[2]; */ } __packed; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 1a8751eb8140..0bc29356ebe4 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -309,7 +309,7 @@ struct wl1271_scan { unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; bool failed; u8 state; - u8 ssid[IW_ESSID_MAX_SIZE+1]; + u8 ssid[IEEE80211_MAX_SSID_LEN+1]; size_t ssid_len; }; @@ -415,7 +415,7 @@ struct wl1271 { u8 mac_addr[ETH_ALEN]; u8 bss_type; u8 set_bss_type; - u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; int channel; diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index 18fe542360f2..f334ea081722 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -77,7 +77,7 @@ struct wl12xx_ie_header { struct wl12xx_ie_ssid { struct wl12xx_ie_header header; - char ssid[IW_ESSID_MAX_SIZE]; + char ssid[IEEE80211_MAX_SSID_LEN]; } __packed; struct wl12xx_ie_rates { -- cgit v1.2.3 From 0a1d3abcc43231e341b6890b873dc27cba848218 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Thu, 14 Jul 2011 11:50:27 +0300 Subject: wl12xx: Add support to RX packets payload alignment In case of QoS packets the packet payload isn't aligned to 4 bytes. In that case the mac80211 layer take care of that via memmove() in ieee80211_deliver_skb(). Add support of copy packets from aggregation buffer to the skbs with packet payload aligned care. In case of QoS packets copy the packets in offset of 2 bytes guarantee payload aligned to 4 bytes. Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/rx.c | 39 +++++++++++++++++++++++++++++++-------- drivers/net/wireless/wl12xx/rx.h | 8 +++++--- 2 files changed, 36 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 0450fb49dbb1..46f4af6ca723 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -38,12 +38,20 @@ static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status, } static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status, - u32 drv_rx_counter) + 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 bool wl1271_rx_get_unaligned(struct wl1271_fw_common_status *status, + u32 drv_rx_counter) +{ + /* Convert the value to bool */ + return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & + RX_BUF_UNALIGNED_PAYLOAD); +} + static void wl1271_rx_status(struct wl1271 *wl, struct wl1271_rx_descriptor *desc, struct ieee80211_rx_status *status, @@ -89,7 +97,8 @@ static void wl1271_rx_status(struct wl1271 *wl, } } -static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) +static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, + bool unaligned) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; @@ -97,6 +106,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) u8 *buf; u8 beacon = 0; u8 is_data = 0; + u8 reserved = unaligned ? NET_IP_ALIGN : 0; /* * In PLT mode we seem to get frames and mac80211 warns about them, @@ -131,17 +141,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) return -EINVAL; } - skb = __dev_alloc_skb(length, GFP_KERNEL); + /* skb length not included rx descriptor */ + skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } - buf = skb_put(skb, length); - memcpy(buf, data, length); + /* reserve the unaligned payload(if any) */ + skb_reserve(skb, reserved); + + buf = skb_put(skb, length - sizeof(*desc)); - /* now we pull the descriptor out of the buffer */ - skb_pull(skb, sizeof(*desc)); + /* + * Copy packets from aggregation buffer to the skbs without rx + * descriptor and with packet payload aligned care. In case of unaligned + * packets copy the packets in offset of 2 bytes guarantee IP header + * payload aligned to 4 bytes. + */ + memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) @@ -175,6 +193,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) u32 pkt_offset; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool had_data = false; + bool unaligned = false; while (drv_rx_counter != fw_rx_counter) { buf_size = 0; @@ -222,6 +241,10 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) while (pkt_offset < buf_size) { pkt_length = wl1271_rx_get_buf_size(status, drv_rx_counter); + + unaligned = wl1271_rx_get_unaligned(status, + drv_rx_counter); + /* * the handle data call can only fail in memory-outage * conditions, in that case the received frame will just @@ -229,7 +252,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) */ if (wl1271_rx_handle_data(wl, wl->aggr_buf + pkt_offset, - pkt_length) == 1) + pkt_length, unaligned) == 1) had_data = true; wl->rx_counter++; diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index c88e3fa1d603..0325b9de612e 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -93,9 +93,11 @@ #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 +#define RX_MEM_BLOCK_MASK 0xFF +#define RX_BUF_SIZE_MASK 0xFFF00 +#define RX_BUF_SIZE_SHIFT_DIV 6 +/* If set, the start of IP payload is not 4 bytes aligned */ +#define RX_BUF_UNALIGNED_PAYLOAD BIT(20) enum { WL12XX_RX_CLASS_UNKNOWN, -- cgit v1.2.3 From 6f07b72adaeddc9a90306ab4f2237b90967fd3ce Mon Sep 17 00:00:00 2001 From: Gery Kahn Date: Mon, 18 Jul 2011 14:21:49 +0300 Subject: wl12xx: fixes for hw_pg_ver and chip id reporting Fix the value of PG version for 128x at sysfs, remove write permissions from PG version (hw_pg_ver) in sysfs and add remove files (hw_pg_ver,bt_coex_state) from sysfs while freeing hardware. New macro names for register Fuse_data_2_1 depend on architecture. Propagate chip id through wiphy in PLT mode which still not work of a bug in ethtool. Signed-off-by: Gery Kahn Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 13 ++++++++----- drivers/net/wireless/wl12xx/boot.h | 3 ++- drivers/net/wireless/wl12xx/main.c | 12 +++++++++++- 3 files changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 5ebc64d89407..a816f2ffa6a9 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -549,13 +549,13 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) { u32 fuse; - fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1); + if (wl->chip.id == CHIP_ID_1283_PG20) + fuse = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); + else + fuse = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); 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; } static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) @@ -696,7 +696,8 @@ static int wl127x_boot_clk(struct wl1271 *wl) u32 pause; u32 clk; - wl1271_boot_hw_version(wl); + if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3) + wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; if (wl->ref_clock == CONF_REF_CLK_19_2_E || wl->ref_clock == CONF_REF_CLK_38_4_E || @@ -750,6 +751,8 @@ int wl1271_load_firmware(struct wl1271 *wl) u32 tmp, clk; int selected_clock = -1; + wl1271_boot_hw_version(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) { ret = wl128x_boot_clk(wl, &selected_clock); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index e8f8255bbabe..06dad9380fa7 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -55,7 +55,8 @@ struct wl1271_static_data { #define OCP_REG_CLK_POLARITY 0x0cb2 #define OCP_REG_CLK_PULL 0x0cb4 -#define REG_FUSE_DATA_2_1 0x050a +#define WL127X_REG_FUSE_DATA_2_1 0x050a +#define WL128X_REG_FUSE_DATA_2_1 0x2152 #define PG_VER_MASK 0x3c #define PG_VER_OFFSET 2 diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3418299e17c8..98258fe0e29d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1395,6 +1395,7 @@ out: int wl1271_plt_start(struct wl1271 *wl) { int retries = WL1271_BOOT_RETRIES; + struct wiphy *wiphy = wl->hw->wiphy; int ret; mutex_lock(&wl->mutex); @@ -1428,6 +1429,11 @@ int wl1271_plt_start(struct wl1271 *wl) wl1271_notice("firmware booted in PLT mode (%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_str, + sizeof(wiphy->fw_version)); + goto out; irq_disable: @@ -4126,7 +4132,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, return len; } -static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(hw_pg_ver, S_IRUGO, wl1271_sysfs_show_hw_pg_ver, NULL); static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, @@ -4522,6 +4528,10 @@ int wl1271_free_hw(struct wl1271 *wl) mutex_unlock(&wl->mutex); device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr); + + device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); + + device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); platform_device_unregister(wl->plat_dev); free_page((unsigned long)wl->fwlog); dev_kfree_skb(wl->dummy_packet); -- cgit v1.2.3 From 7bb5d6ce9e6ebb3bb71915cb0224523d3c284b4f Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:00 +0300 Subject: wl12xx: Revert "wl12xx: schedule TX packets according to FW occupancy" This does not make sense in fw >= 6/7.3.0.0.75 (wl127x/wl128x) - we don't use Tx blocks to measure FW occupancy anymore. This reverts commit 9e374a37b6fa2310b71d3c5657cd0c1e693120c6. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/debugfs.c | 5 +-- drivers/net/wireless/wl12xx/main.c | 30 +++++----------- drivers/net/wireless/wl12xx/tx.c | 68 ++++++++++++----------------------- drivers/net/wireless/wl12xx/wl12xx.h | 2 +- 4 files changed, 33 insertions(+), 72 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 37934b5601cd..3b5f240d7031 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -339,10 +339,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, #define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x") DRIVER_STATE_PRINT_INT(tx_blocks_available); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks); DRIVER_STATE_PRINT_INT(tx_frames_cnt); DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); DRIVER_STATE_PRINT_INT(tx_queue_count[0]); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 98258fe0e29d..f91875e379a2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -824,24 +824,13 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl, } } -static u32 wl1271_tx_allocated_blocks(struct wl1271 *wl) -{ - int i; - u32 total_alloc_blocks = 0; - - for (i = 0; i < NUM_TX_QUEUES; i++) - total_alloc_blocks += wl->tx_allocated_blocks[i]; - - return total_alloc_blocks; -} - static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_full_status *full_status) { struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; u32 old_tx_blk_count = wl->tx_blocks_available; - u32 freed_blocks = 0, ac_freed_blocks; + u32 freed_blocks = 0; int i; if (wl->bss_type == BSS_TYPE_AP_BSS) { @@ -861,23 +850,21 @@ static void wl1271_fw_status(struct wl1271 *wl, /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - ac_freed_blocks = le32_to_cpu(status->tx_released_blks[i]) - - wl->tx_blocks_freed[i]; - freed_blocks += ac_freed_blocks; - - wl->tx_allocated_blocks[i] -= ac_freed_blocks; + freed_blocks += 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_allocated_blocks -= freed_blocks; + if (wl->bss_type == BSS_TYPE_AP_BSS) { /* Update num of allocated TX blocks per link and ps status */ wl1271_irq_update_links_status(wl, &full_status->ap); wl->tx_blocks_available += freed_blocks; } else { - int avail = full_status->sta.tx_total - - wl1271_tx_allocated_blocks(wl); + int avail = full_status->sta.tx_total - wl->tx_allocated_blocks; /* * The FW might change the total number of TX memblocks before @@ -2013,6 +2000,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; + wl->tx_allocated_blocks = 0; wl->tx_results_count = 0; wl->tx_packets_count = 0; wl->time_offset = 0; @@ -2033,10 +2021,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, */ wl->flags = 0; - for (i = 0; i < NUM_TX_QUEUES; i++) { + for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; - wl->tx_allocated_blocks[i] = 0; - } wl1271_debugfs_reset(wl); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 48fde96ce0d4..0696aedaf806 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -168,7 +168,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 len; u32 total_blocks; - int id, ret = -EBUSY, ac; + int id, ret = -EBUSY; u32 spare_blocks; if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) @@ -206,9 +206,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, desc->id = id; wl->tx_blocks_available -= total_blocks; - - ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - wl->tx_allocated_blocks[ac] += total_blocks; + wl->tx_allocated_blocks += total_blocks; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->links[hlid].allocated_blks += total_blocks; @@ -459,41 +457,21 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl) } } -static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, - struct sk_buff_head *queues) -{ - int i, q = -1; - u32 min_blks = 0xffffffff; - - /* - * Find a non-empty ac where: - * 1. There are packets to transmit - * 2. The FW has the least allocated blocks - */ - for (i = 0; i < NUM_TX_QUEUES; i++) - if (!skb_queue_empty(&queues[i]) && - (wl->tx_allocated_blocks[i] < min_blks)) { - q = i; - min_blks = wl->tx_allocated_blocks[q]; - } - - if (q == -1) - return NULL; - - return &queues[q]; -} - static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) { struct sk_buff *skb = NULL; unsigned long flags; - struct sk_buff_head *queue; - queue = wl1271_select_queue(wl, wl->tx_queue); - if (!queue) + skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]); + if (skb) goto out; - - skb = skb_dequeue(queue); + skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]); + if (skb) + goto out; + skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]); + if (skb) + goto out; + skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]); out: if (skb) { @@ -511,7 +489,6 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) struct sk_buff *skb = NULL; unsigned long flags; int i, h, start_hlid; - struct sk_buff_head *queue; /* start from the link after the last one */ start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; @@ -520,20 +497,21 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) for (i = 0; i < AP_MAX_LINKS; i++) { h = (start_hlid + i) % AP_MAX_LINKS; - /* only consider connected stations */ - if (h >= WL1271_AP_STA_HLID_START && - !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map)) - continue; - - queue = wl1271_select_queue(wl, wl->links[h].tx_queue); - if (!queue) - continue; - - skb = skb_dequeue(queue); + skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]); if (skb) - break; + goto out; + skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]); + if (skb) + goto out; + skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]); + if (skb) + goto out; + skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]); + if (skb) + goto out; } +out: if (skb) { int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); wl->last_tx_hlid = h; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 0bc29356ebe4..5b00a84acab2 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -424,7 +424,7 @@ struct wl1271 { /* Accounting for allocated / available TX blocks on HW */ u32 tx_blocks_freed[NUM_TX_QUEUES]; u32 tx_blocks_available; - u32 tx_allocated_blocks[NUM_TX_QUEUES]; + u32 tx_allocated_blocks; u32 tx_results_count; /* Transmitted TX packets counter for chipset interface */ -- cgit v1.2.3 From c302b2c959164622558474871ae942da0e484a38 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 17 Aug 2011 10:45:48 +0300 Subject: wl12xx: Use a single fw for both STA and AP roles Firmware >= 6/7.3.0.0.75 (wl127x/wl128x) supports both STA and AP roles. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 31 +++++-------------------------- drivers/net/wireless/wl12xx/sdio.c | 4 +--- drivers/net/wireless/wl12xx/spi.c | 4 +--- drivers/net/wireless/wl12xx/wl12xx.h | 7 ++----- 4 files changed, 9 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index f91875e379a2..7b29573ef244 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1043,25 +1043,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) const char *fw_name; int ret; - switch (wl->bss_type) { - case BSS_TYPE_AP_BSS: - if (wl->chip.id == CHIP_ID_1283_PG20) - fw_name = WL128X_AP_FW_NAME; - else - fw_name = WL127X_AP_FW_NAME; - break; - case BSS_TYPE_IBSS: - case BSS_TYPE_STA_BSS: - if (wl->chip.id == CHIP_ID_1283_PG20) - fw_name = WL128X_FW_NAME; - else - fw_name = WL1271_FW_NAME; - break; - default: - wl1271_error("no compatible firmware for bss_type %d", - wl->bss_type); - return -EINVAL; - } + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_FW_NAME; + else + fw_name = WL127X_FW_NAME; wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); @@ -1090,7 +1075,6 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) } memcpy(wl->fw, fw->data, wl->fw_len); - wl->fw_bss_type = wl->bss_type; ret = 0; out: @@ -1361,8 +1345,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) goto out; } - /* Make sure the firmware type matches the BSS type */ - if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) { + if (wl->fw == NULL) { ret = wl1271_fetch_firmware(wl); if (ret < 0) goto out; @@ -1796,9 +1779,6 @@ static int wl1271_op_start(struct ieee80211_hw *hw) * * The MAC address is first known when the corresponding interface * is added. That is where we will initialize the hardware. - * - * In addition, we currently have different firmwares for AP and managed - * operation. We will know which to boot according to interface type. */ return 0; @@ -4393,7 +4373,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->hw_pg_ver = -1; wl->bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE; - wl->fw_bss_type = MAX_BSS_TYPE; wl->last_tx_hlid = 0; wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 5cf18c2c23f0..ac2e5661397c 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -412,7 +412,5 @@ module_exit(wl1271_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); -MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL127X_FW_NAME); MODULE_FIRMWARE(WL128X_FW_NAME); -MODULE_FIRMWARE(WL127X_AP_FW_NAME); -MODULE_FIRMWARE(WL128X_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index e0b3736d7e19..0f9718677860 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -486,8 +486,6 @@ module_exit(wl1271_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); -MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL127X_FW_NAME); MODULE_FIRMWARE(WL128X_FW_NAME); -MODULE_FIRMWARE(WL127X_AP_FW_NAME); -MODULE_FIRMWARE(WL128X_AP_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 5b00a84acab2..dc0013e9b9f7 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -130,10 +130,8 @@ extern u32 wl12xx_debug_level; -#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin" -#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin" -#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" -#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin" +#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin" +#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin" /* * wl127x and wl128x are using the same NVS file name. However, the @@ -405,7 +403,6 @@ struct wl1271 { u8 *fw; size_t fw_len; - u8 fw_bss_type; void *nvs; size_t nvs_len; -- cgit v1.2.3 From 2920743a14764eda099700e1eca9a282393cee16 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:02 +0300 Subject: wl12xx: use 1 spare block in all cases Remove support for firmwares that require 2 spare blocks for packet TX (and delete the WL12XX_QUIRK_USE_2_SPARE_BLOCKS quirk definition) Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 10 ---------- drivers/net/wireless/wl12xx/tx.c | 7 ++----- drivers/net/wireless/wl12xx/wl12xx.h | 6 ------ 3 files changed, 2 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index a816f2ffa6a9..930a638523fb 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -107,16 +107,6 @@ static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl) unsigned int quirks = 0; unsigned int *fw_ver = wl->chip.fw_ver; - /* Only for wl127x */ - if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && - /* Check STA version */ - (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && - (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || - /* Check AP version */ - ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && - (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) - quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; - /* Only new station firmwares support routing fw logs to the host */ if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 0696aedaf806..c67340ff83c8 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -169,12 +169,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 len; u32 total_blocks; int id, ret = -EBUSY; - u32 spare_blocks; - if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) - spare_blocks = 2; - else - spare_blocks = 1; + /* we use 1 spare block */ + u32 spare_blocks = 1; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index dc0013e9b9f7..0bdeae5c802d 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -656,12 +656,6 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); /* Each RX/TX transaction requires an end-of-transaction transfer */ #define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) -/* - * Older firmwares use 2 spare TX blocks - * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47) - */ -#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) - /* WL128X requires aggregated packets to be aligned to the SDIO block size */ #define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) -- cgit v1.2.3 From dbe25cb5eb04b0ffdad582a93f9fe9edd0ed791b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:03 +0300 Subject: wl12xx: temporarily disable advanced ap functions In order to keep to driver compiling during the patchset, while avoiding one-huge-patch, temporarily disable some advanced ap functions. These changes will be reverted later in the patchset, as part of the patches for advanced ap functions support. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 4 ++++ drivers/net/wireless/wl12xx/tx.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7b29573ef244..4fa760230ac7 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -773,6 +773,7 @@ static int wl1271_plt_init(struct wl1271 *wl) return ret; } +#if 0 static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks) { bool fw_ps; @@ -823,6 +824,7 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl, wl->links[hlid].allocated_blks); } } +#endif static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_full_status *full_status) @@ -861,7 +863,9 @@ static void wl1271_fw_status(struct wl1271 *wl, if (wl->bss_type == BSS_TYPE_AP_BSS) { /* Update num of allocated TX blocks per link and ps status */ +#if 0 wl1271_irq_update_links_status(wl, &full_status->ap); +#endif wl->tx_blocks_available += freed_blocks; } else { int avail = full_status->sta.tx_total - wl->tx_allocated_blocks; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index c67340ff83c8..938af1de6c2c 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -111,6 +111,7 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, wl1271_acx_set_inconnection_sta(wl, hdr->addr1); } +#if 0 static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) { bool fw_ps; @@ -130,6 +131,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) wl1271_ps_link_start(wl, hlid, true); } +#endif u8 wl1271_tx_get_hlid(struct sk_buff *skb) { @@ -384,7 +386,9 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); +#if 0 wl1271_tx_regulate_link(wl, hlid); +#endif } else { wl1271_tx_update_filters(wl, skb); } -- cgit v1.2.3 From 08c1d1c7042330e2280a7718be4ad88c2e8f8268 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:04 +0300 Subject: wl12xx: remove rx filtering stuff The new fw doesn't support rx_filtering configuration (as a stand-alone command. the rx filtering is done automatically according to the active role). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 28 -------- drivers/net/wireless/wl12xx/acx.h | 118 ---------------------------------- drivers/net/wireless/wl12xx/boot.c | 3 - drivers/net/wireless/wl12xx/cmd.c | 4 -- drivers/net/wireless/wl12xx/debugfs.c | 3 - drivers/net/wireless/wl12xx/init.c | 12 +--- drivers/net/wireless/wl12xx/io.h | 1 - drivers/net/wireless/wl12xx/main.c | 62 ++---------------- drivers/net/wireless/wl12xx/reg.h | 75 --------------------- drivers/net/wireless/wl12xx/rx.c | 11 ---- drivers/net/wireless/wl12xx/rx.h | 1 - drivers/net/wireless/wl12xx/scan.c | 3 - drivers/net/wireless/wl12xx/tx.c | 4 +- drivers/net/wireless/wl12xx/wl12xx.h | 22 ------- 14 files changed, 8 insertions(+), 339 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 7e33f1f4f3d4..6447a0969ffe 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -183,34 +183,6 @@ out: 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; diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index d2eb86eccc04..4ae0085c58ea 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -160,94 +160,6 @@ struct acx_rx_msdu_lifetime { __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; @@ -424,35 +336,6 @@ struct acx_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) @@ -1342,7 +1225,6 @@ 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, diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 930a638523fb..41791ffd26ea 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -845,9 +845,6 @@ int wl1271_boot(struct wl1271 *wl) /* Enable firmware interrupts now */ wl1271_boot_enable_interrupts(wl); - /* set the wl1271 default filters */ - wl1271_set_default_filters(wl); - wl1271_event_mbox_config(wl); out: diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 97dd237a9580..b6ef65a57b71 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -382,8 +382,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) 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); join->supported_rate_set = cpu_to_le32(wl->rate_set); @@ -1004,8 +1002,6 @@ int wl1271_cmd_disconnect(struct wl1271 *wl) 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; diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 3b5f240d7031..fd1c301be7c7 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -366,9 +366,6 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(beacon_int); DRIVER_STATE_PRINT_INT(psm_entry_retry); DRIVER_STATE_PRINT_INT(ps_poll_failures); - DRIVER_STATE_PRINT_HEX(filters); - DRIVER_STATE_PRINT_HEX(rx_config); - DRIVER_STATE_PRINT_HEX(rx_filter); DRIVER_STATE_PRINT_INT(power_level); DRIVER_STATE_PRINT_INT(rssi_thold); DRIVER_STATE_PRINT_INT(last_rssi_event); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index c3e9a2e4410e..44cd515a057e 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -227,7 +227,7 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl) return 0; } -static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) +static int wl12xx_init_rx_config(struct wl1271 *wl) { int ret; @@ -235,10 +235,6 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) if (ret < 0) return ret; - ret = wl1271_acx_rx_config(wl, config, filter); - if (ret < 0) - return ret; - return 0; } @@ -650,11 +646,7 @@ int wl1271_hw_init(struct wl1271 *wl) 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); */ + ret = wl12xx_init_rx_config(wl); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index a2fe4f506ada..e839341dfafe 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -186,6 +186,5 @@ int wl1271_free_hw(struct wl1271 *wl); irqreturn_t wl1271_irq(int irq, void *data); bool wl1271_set_block_size(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl); -void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 4fa760230ac7..7fcdfa3ee1db 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1991,7 +1991,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; wl->vif = NULL; - wl->filters = 0; wl1271_free_ap_keys(wl); memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; @@ -2037,39 +2036,6 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, cancel_work_sync(&wl->recovery_work); } -void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) -{ - wl1271_set_default_filters(wl); - - /* 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; @@ -2079,9 +2045,6 @@ static int wl1271_dummy_join(struct wl1271 *wl) 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; @@ -2163,9 +2126,6 @@ static int wl1271_unjoin(struct wl1271 *wl) wl->tx_security_last_seq_lsb = 0; wl->tx_security_seq = 0; - /* stop filtering packets based on bssid */ - wl1271_configure_filters(wl, FIF_OTHER_BSS); - out: return ret; } @@ -2434,18 +2394,11 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, 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; + /* + * the fw doesn't provide an api to configure the filters. instead, + * the filters configuration is based on the active roles / ROC + * state. + */ out_sleep: wl1271_ps_elp_sleep(wl); @@ -3168,9 +3121,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (ret < 0) goto out; - /* filter out all packets not from this BSSID */ - wl1271_configure_filters(wl, 0); - /* Need to update the BSSID (for filtering etc) */ do_join = true; } @@ -4363,8 +4313,6 @@ 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_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/reg.h b/drivers/net/wireless/wl12xx/reg.h index 440a4ee9cb42..3f570f397586 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -296,81 +296,6 @@ ===============================================*/ #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 ------------------------------------------ diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 46f4af6ca723..7a0c5fe294b2 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -283,14 +283,3 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) jiffies + msecs_to_jiffies(timeout)); } } - -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 0325b9de612e..d3c0591665e8 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -131,6 +131,5 @@ struct wl1271_rx_descriptor { void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_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/scan.c b/drivers/net/wireless/wl12xx/scan.c index edfe01c321ca..78a9b23a41b8 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -167,9 +167,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, } 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); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 938af1de6c2c..8a745fbe0f45 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -90,9 +90,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, if (!ieee80211_is_auth(hdr->frame_control)) return 0; - wl1271_configure_filters(wl, FIF_OTHER_BSS); - - return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); + return 0; } static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 0bdeae5c802d..7707895120be 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -112,24 +112,6 @@ extern u32 wl12xx_debug_level; true); \ } while (0) -#define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN | \ - CFG_MC_FILTER_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 WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin" #define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin" @@ -532,10 +514,6 @@ struct wl1271 { struct work_struct rx_streaming_disable_work; struct timer_list rx_streaming_timer; - unsigned int filters; - unsigned int rx_config; - unsigned int rx_filter; - struct completion *elp_compl; struct completion *ps_compl; struct delayed_work elp_work; -- cgit v1.2.3 From 4d56ad9cae9e8553176427adc2335f8a7f4556b2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:05 +0300 Subject: wl12xx: update fw status struct Update the fw status struct according to the new fw api (fw >= 6/7.0.0.35). All the roles use the same struct now. The memory accounting was changed a bit according to the struct changes. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/debugfs.c | 5 +-- drivers/net/wireless/wl12xx/main.c | 82 ++++++++++++++--------------------- drivers/net/wireless/wl12xx/rx.c | 18 ++++---- drivers/net/wireless/wl12xx/rx.h | 2 +- drivers/net/wireless/wl12xx/wl12xx.h | 55 ++++++++++------------- 5 files changed, 68 insertions(+), 94 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index fd1c301be7c7..3102652c7625 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -349,10 +349,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(tx_packets_count); DRIVER_STATE_PRINT_INT(tx_results_count); DRIVER_STATE_PRINT_LHEX(flags); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed); DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb); DRIVER_STATE_PRINT_INT(rx_counter); DRIVER_STATE_PRINT_INT(session_counter); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7fcdfa3ee1db..96f76b104e75 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -826,22 +826,14 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl, } #endif -static void wl1271_fw_status(struct wl1271 *wl, - struct wl1271_fw_full_status *full_status) +static void wl12xx_fw_status(struct wl1271 *wl, + struct wl12xx_fw_status *status) { - struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; u32 old_tx_blk_count = wl->tx_blocks_available; - u32 freed_blocks = 0; - int i; + int avail, freed_blocks; - if (wl->bss_type == BSS_TYPE_AP_BSS) { - wl1271_raw_read(wl, FW_STATUS_ADDR, status, - sizeof(struct wl1271_fw_ap_status), false); - } else { - wl1271_raw_read(wl, FW_STATUS_ADDR, status, - sizeof(struct wl1271_fw_sta_status), false); - } + 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)", @@ -850,42 +842,36 @@ static void wl1271_fw_status(struct wl1271 *wl, status->drv_rx_counter, status->tx_results_counter); - /* update number of available TX blocks */ - for (i = 0; i < NUM_TX_QUEUES; i++) { - freed_blocks += 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]); - } + freed_blocks = le32_to_cpu(status->total_released_blks) - + wl->tx_blocks_freed; + wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks); wl->tx_allocated_blocks -= freed_blocks; - if (wl->bss_type == BSS_TYPE_AP_BSS) { - /* Update num of allocated TX blocks per link and ps status */ -#if 0 - wl1271_irq_update_links_status(wl, &full_status->ap); -#endif - wl->tx_blocks_available += freed_blocks; - } else { - int avail = full_status->sta.tx_total - wl->tx_allocated_blocks; + avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks; - /* - * The FW might change the total number of TX memblocks before - * we get a notification about blocks being released. Thus, the - * available blocks calculation might yield a temporary result - * which is lower than the actual available blocks. Keeping in - * mind that only blocks that were allocated can be moved from - * TX to RX, tx_blocks_available should never decrease here. - */ - wl->tx_blocks_available = max((int)wl->tx_blocks_available, - avail); - } + /* + * The FW might change the total number of TX memblocks before + * we get a notification about blocks being released. Thus, the + * available blocks calculation might yield a temporary result + * which is lower than the actual available blocks. Keeping in + * mind that only blocks that were allocated can be moved from + * TX to RX, tx_blocks_available should never decrease here. + */ + wl->tx_blocks_available = max((int)wl->tx_blocks_available, + avail); /* if more blocks are available now, tx work can be scheduled */ if (wl->tx_blocks_available > old_tx_blk_count) clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + /* for AP update num of allocated TX blocks per link and ps status */ + if (wl->bss_type == BSS_TYPE_AP_BSS) { +#if 0 + wl1271_irq_update_links_status(wl, status); +#endif + } + /* update the host-chipset time offset */ getnstimeofday(&ts); wl->time_offset = (timespec_to_ns(&ts) >> 10) - @@ -958,8 +944,8 @@ irqreturn_t wl1271_irq(int irq, void *cookie) clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); smp_mb__after_clear_bit(); - wl1271_fw_status(wl, wl->fw_status); - intr = le32_to_cpu(wl->fw_status->common.intr); + wl12xx_fw_status(wl, wl->fw_status); + intr = le32_to_cpu(wl->fw_status->intr); intr &= WL1271_INTR_MASK; if (!intr) { done = true; @@ -978,7 +964,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie) if (likely(intr & WL1271_ACX_INTR_DATA)) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); - wl1271_rx(wl, &wl->fw_status->common); + wl12xx_rx(wl, wl->fw_status); /* Check if any tx blocks were freed */ spin_lock_irqsave(&wl->wl_lock, flags); @@ -995,7 +981,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie) } /* check for tx results */ - if (wl->fw_status->common.tx_results_counter != + if (wl->fw_status->tx_results_counter != (wl->tx_results_count & 0xff)) wl1271_tx_complete(wl); @@ -1169,8 +1155,8 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) wl12xx_cmd_stop_fwlog(wl); /* Read the first memory block address */ - wl1271_fw_status(wl, wl->fw_status); - first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr); + wl12xx_fw_status(wl, wl->fw_status); + first_addr = le32_to_cpu(wl->fw_status->log_start_addr); if (!first_addr) goto out; @@ -1186,7 +1172,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) * of each memory block hold the hardware address of the next * one. The last memory block points to the first one. */ - addr = __le32_to_cpup((__le32 *)block); + addr = le32_to_cpup((__le32 *)block); if (!wl12xx_copy_fwlog(wl, block + sizeof(addr), WL12XX_HW_BLOCK_SIZE - sizeof(addr))) break; @@ -1923,7 +1909,6 @@ out: static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues) { - int i; wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); @@ -2004,8 +1989,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, */ wl->flags = 0; - for (i = 0; i < NUM_TX_QUEUES; i++) - wl->tx_blocks_freed[i] = 0; + wl->tx_blocks_freed = 0; wl1271_debugfs_reset(wl); diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 7a0c5fe294b2..78d8410da1f4 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -30,21 +30,21 @@ #include "rx.h" #include "io.h" -static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status, +static u8 wl12xx_rx_get_mem_block(struct wl12xx_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_common_status *status, - u32 drv_rx_counter) +static u32 wl12xx_rx_get_buf_size(struct wl12xx_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 bool wl1271_rx_get_unaligned(struct wl1271_fw_common_status *status, +static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status, u32 drv_rx_counter) { /* Convert the value to bool */ @@ -181,7 +181,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, return is_data; } -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) +void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; u32 buf_size; @@ -199,7 +199,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) buf_size = 0; rx_counter = drv_rx_counter; while (rx_counter != fw_rx_counter) { - pkt_length = wl1271_rx_get_buf_size(status, rx_counter); + pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) break; buf_size += pkt_length; @@ -218,7 +218,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) * 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, + mem_block = wl12xx_rx_get_mem_block(status, drv_rx_counter); wl->rx_mem_pool_addr.addr = (mem_block << 8) + @@ -239,10 +239,10 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) /* Split data into separate packets */ pkt_offset = 0; while (pkt_offset < buf_size) { - pkt_length = wl1271_rx_get_buf_size(status, + pkt_length = wl12xx_rx_get_buf_size(status, drv_rx_counter); - unaligned = wl1271_rx_get_unaligned(status, + unaligned = wl12xx_rx_get_unaligned(status, drv_rx_counter); /* diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index d3c0591665e8..00c1c1d27aaa 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -129,7 +129,7 @@ struct wl1271_rx_descriptor { u8 reserved; } __packed; -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status); +void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); #endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 7707895120be..f708cd70185a 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -137,6 +137,7 @@ extern u32 wl12xx_debug_level; #define WL1271_DEFAULT_BEACON_INT 100 #define WL1271_DEFAULT_DTIM_PERIOD 1 +#define WL12XX_MAX_LINKS 8 #define WL1271_AP_GLOBAL_HLID 0 #define WL1271_AP_BROADCAST_HLID 1 #define WL1271_AP_STA_HLID_START 2 @@ -230,23 +231,15 @@ struct wl1271_stats { /* Broadcast and Global links + links to stations */ #define AP_MAX_LINKS (AP_MAX_STATIONS + 2) -/* FW status registers common for AP/STA */ -struct wl1271_fw_common_status { +/* FW status registers */ +struct wl12xx_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; -} __packed; - -/* FW status registers for AP */ -struct wl1271_fw_ap_status { - struct wl1271_fw_common_status common; - - /* Next fields valid only in AP FW */ /* * A bitmap (where each bit represents a single HLID) @@ -254,29 +247,29 @@ struct wl1271_fw_ap_status { */ __le32 link_ps_bitmap; - /* Number of freed MBs per HLID */ - u8 tx_lnk_free_blks[AP_MAX_LINKS]; - u8 padding_1[1]; -} __packed; + /* + * A bitmap (where each bit represents a single HLID) to indicate + * if the station is in Fast mode + */ + __le32 link_fast_bitmap; -/* FW status registers for STA */ -struct wl1271_fw_sta_status { - struct wl1271_fw_common_status common; + /* Cumulative counter of total released mem blocks since FW-reset */ + __le32 total_released_blks; - u8 tx_total; - u8 reserved1; - __le16 reserved2; - __le32 log_start_addr; -} __packed; + /* Size (in Memory Blocks) of TX pool */ + __le32 tx_total; -struct wl1271_fw_full_status { - union { - struct wl1271_fw_common_status common; - struct wl1271_fw_sta_status sta; - struct wl1271_fw_ap_status ap; - }; -} __packed; + /* Cumulative counter of released mem-blocks per AC */ + u8 tx_released_blks[NUM_TX_QUEUES]; + /* Cumulative counter of freed MBs per HLID */ + u8 tx_lnk_free_blks[WL12XX_MAX_LINKS]; + + /* Cumulative counter of released Voice memory blocks */ + u8 tx_voice_released_blks; + u8 padding_1[7]; + __le32 log_start_addr; +} __packed; struct wl1271_rx_mem_pool_addr { u32 addr; @@ -401,7 +394,7 @@ struct wl1271 { 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_freed; u32 tx_blocks_available; u32 tx_allocated_blocks; u32 tx_results_count; @@ -537,7 +530,7 @@ struct wl1271 { u32 buffer_cmd; u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; - struct wl1271_fw_full_status *fw_status; + struct wl12xx_fw_status *fw_status; struct wl1271_tx_hw_res_if *tx_res_if; struct ieee80211_vif *vif; -- cgit v1.2.3 From 7f097988f1bff42177b99cb4c8ec62e818d0b1a6 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:06 +0300 Subject: wl12xx: update acx commands Update the acx commands according to the new fw api (fw >= 6/7.3.0.0.75). The main change in most of the ACXs is the addition of a new role_id/link_id field, which is required for multi-role operation. Currently, we don't really support multi-role, as most of our data (inside wl) is global. As the current fw doesn't support concurrent roles yet, keep it this way and add wl->role_id and wl->sta_hlid to save the active role/link. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 113 ++++++++++++---------------- drivers/net/wireless/wl12xx/acx.h | 142 +++++++++++++++++++---------------- drivers/net/wireless/wl12xx/init.c | 4 +- drivers/net/wireless/wl12xx/main.c | 5 +- drivers/net/wireless/wl12xx/wl12xx.h | 4 + 5 files changed, 138 insertions(+), 130 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 6447a0969ffe..dfb1cbb35acd 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -46,6 +46,7 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl) goto out; } + wake_up->role_id = wl->role_id; wake_up->wake_up_event = wl->conf.conn.wake_up_event; wake_up->listen_interval = wl->conf.conn.listen_interval; @@ -101,6 +102,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) goto out; } + acx->role_id = wl->role_id; acx->current_tx_power = power * 10; ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); @@ -128,6 +130,7 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl) } /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->role_id = wl->role_id; feature->data_flow_options = 0; feature->options = 0; @@ -222,6 +225,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) goto out; } + slot->role_id = wl->role_id; slot->wone_index = STATION_WONE_INDEX; slot->slot_time = slot_time; @@ -251,6 +255,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, } /* MAC filtering */ + acx->role_id = wl->role_id; acx->enabled = enable; acx->num_groups = mc_list_len; memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); @@ -280,6 +285,7 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl) wl1271_debug(DEBUG_ACX, "acx service period timeout"); + rx_timeout->role_id = wl->role_id; 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); @@ -316,6 +322,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold) goto out; } + rts->role_id = wl->role_id; rts->threshold = cpu_to_le16((u16)rts_threshold); ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); @@ -375,6 +382,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) goto out; } + beacon_filter->role_id = wl->role_id; beacon_filter->enable = enable_filter; /* @@ -411,6 +419,7 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl) } /* configure default beacon pass-through rules */ + ie_table->role_id = wl->role_id; 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]); @@ -472,6 +481,7 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable) timeout = wl->conf.conn.bss_lose_timeout; } + acx->role_id = wl->role_id; acx->synch_fail_thold = cpu_to_le32(threshold); acx->bss_lose_timeout = cpu_to_le32(timeout); @@ -619,6 +629,7 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) goto out; } + bb->role_id = wl->role_id; 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; @@ -648,6 +659,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid) goto out; } + acx_aid->role_id = wl->role_id; acx_aid->aid = cpu_to_le16(aid); ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); @@ -703,6 +715,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) goto out; } + acx->role_id = wl->role_id; acx->preamble = preamble; ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); @@ -730,6 +743,7 @@ int wl1271_acx_cts_protect(struct wl1271 *wl, goto out; } + acx->role_id = wl->role_id; acx->ctsprotect = ctsprotect; ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); @@ -761,9 +775,8 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) int wl1271_acx_sta_rate_policies(struct wl1271 *wl) { - struct acx_sta_rate_policy *acx; + struct acx_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; - int idx = 0; int ret = 0; wl1271_debug(DEBUG_ACX, "acx rate policies"); @@ -775,25 +788,30 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl) goto out; } + wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", + wl->basic_rate, wl->rate_set); + /* 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; + acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE); + acx->rate_policy.enabled_rates = cpu_to_le32(wl->basic_rate); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; + + 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; + } /* 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_policy_idx = cpu_to_le32(ACX_TX_AP_FULL_RATE); + acx->rate_policy.enabled_rates = cpu_to_le32(wl->rate_set); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; - acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); - wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", - acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates, - acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates); ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { @@ -809,7 +827,7 @@ out: int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, u8 idx) { - struct acx_ap_rate_policy *acx; + struct acx_rate_policy *acx; int ret = 0; wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", @@ -855,6 +873,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, goto out; } + acx->role_id = wl->role_id; acx->ac = ac; acx->cw_min = cw_min; acx->cw_max = cpu_to_le16(cw_max); @@ -888,6 +907,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, goto out; } + acx->role_id = wl->role_id; acx->queue_id = queue_id; acx->channel_type = channel_type; acx->tsid = tsid; @@ -967,52 +987,9 @@ out: return ret; } -int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) -{ - struct wl1271_acx_ap_config_memory *mem_conf; - struct conf_memory_settings *mem; - int ret; - - wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - if (wl->chip.id == CHIP_ID_1283_PG20) - /* - * FIXME: The 128x AP FW does not yet support dynamic memory. - * Use the base memory configuration for 128x for now. This - * should be fine tuned in the future. - */ - mem = &wl->conf.mem_wl128x; - else - mem = &wl->conf.mem_wl127x; - - /* memory config */ - mem_conf->num_stations = mem->num_stations; - mem_conf->rx_mem_block_num = mem->rx_block_num; - mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; - mem_conf->num_ssid_profiles = mem->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_sta_mem_cfg(struct wl1271 *wl) +int wl12xx_acx_mem_cfg(struct wl1271 *wl) { - struct wl1271_acx_sta_config_memory *mem_conf; + struct wl12xx_acx_config_memory *mem_conf; struct conf_memory_settings *mem; int ret; @@ -1155,6 +1132,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) goto out; } + acx->role_id = wl->role_id; acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; acx->max_consecutive = wl->conf.conn.bet_max_consecutive; @@ -1182,6 +1160,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address) goto out; } + acx->role_id = wl->role_id; acx->version = ACX_IPV4_VERSION; acx->enable = enable; @@ -1241,6 +1220,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) goto out; } + acx->role_id = wl->role_id; acx->enabled = enable; ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); @@ -1267,6 +1247,7 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) goto out; } + acx->role_id = wl->role_id; acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); acx->index = index; acx->tpl_validation = tpl_valid; @@ -1300,6 +1281,7 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, wl->last_rssi_event = -1; + acx->role_id = wl->role_id; 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; @@ -1338,6 +1320,7 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) goto out; } + acx->role_id = wl->role_id; acx->rssi_beacon = c->avg_weight_rssi_beacon; acx->rssi_data = c->avg_weight_rssi_data; acx->snr_beacon = c->avg_weight_snr_beacon; @@ -1359,7 +1342,6 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, bool allow_ht_operation) { struct wl1271_acx_ht_capabilities *acx; - u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int ret = 0; u32 ht_capabilites = 0; @@ -1390,7 +1372,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, acx->ampdu_min_spacing = ht_cap->ampdu_density; } - memcpy(acx->mac_address, mac_address, ETH_ALEN); + acx->hlid = wl->sta_hlid; acx->ht_capabilites = cpu_to_le32(ht_capabilites); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); @@ -1418,6 +1400,7 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl, goto out; } + acx->role_id = wl->role_id; acx->ht_protection = (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); acx->rifs_mode = 0; @@ -1578,6 +1561,7 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable) if (!(conf_queues & BIT(i))) continue; + rx_streaming->role_id = wl->role_id; rx_streaming->tid = i; rx_streaming->enable = enable_queues & BIT(i); rx_streaming->period = wl->conf.rx_streaming.interval; @@ -1607,6 +1591,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) if (!acx) return -ENOMEM; + acx->role_id = wl->role_id; acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 4ae0085c58ea..67258a15de21 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -101,6 +101,17 @@ struct acx_error_counter { __le32 seq_num_miss; } __packed; +enum wl12xx_role { + WL1271_ROLE_STA = 0, + WL1271_ROLE_IBSS, + WL1271_ROLE_AP, + WL1271_ROLE_DEVICE, + WL1271_ROLE_P2P_CL, + WL1271_ROLE_P2P_GO, + + WL12XX_INVALID_ROLE_TYPE = 0xff +}; + enum wl1271_psm_mode { /* Active mode */ WL1271_PSM_CAM = 0, @@ -179,9 +190,10 @@ enum acx_slot_type { struct acx_slot { struct acx_header header; + u8 role_id; u8 wone_index; /* Reserved */ u8 slot_time; - u8 reserved[6]; + u8 reserved[5]; } __packed; @@ -191,29 +203,35 @@ struct acx_slot { struct acx_dot11_grp_addr_tbl { struct acx_header header; + u8 role_id; u8 enabled; u8 num_groups; - u8 pad[2]; + u8 pad[1]; u8 mac_table[ADDRESS_GROUP_MAX_LEN]; } __packed; struct acx_rx_timeout { struct acx_header header; + u8 role_id; + u8 reserved; __le16 ps_poll_timeout; __le16 upsd_timeout; + u8 padding[2]; } __packed; struct acx_rts_threshold { struct acx_header header; + u8 role_id; + u8 reserved; __le16 threshold; - u8 pad[2]; } __packed; struct acx_beacon_filter_option { struct acx_header header; + u8 role_id; u8 enable; /* * The number of beacons without the unicast TIM @@ -223,7 +241,7 @@ struct acx_beacon_filter_option { * without the unicast TIM bit set are dropped. */ u8 max_num_beacons; - u8 pad[2]; + u8 pad[1]; } __packed; /* @@ -262,14 +280,17 @@ struct acx_beacon_filter_option { struct acx_beacon_filter_ie_table { struct acx_header header; + u8 role_id; u8 num_ie; - u8 pad[3]; + u8 pad[2]; u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; } __packed; struct acx_conn_monit_params { struct acx_header header; + u8 role_id; + u8 padding[3]; __le32 synch_fail_thold; /* number of beacons missed */ __le32 bss_lose_timeout; /* number of TU's from synch fail */ } __packed; @@ -318,15 +339,16 @@ struct acx_energy_detection { struct acx_beacon_broadcast { struct acx_header header; - __le16 beacon_rx_timeout; - __le16 broadcast_timeout; - + u8 role_id; /* Enables receiving of broadcast packets in PS mode */ u8 rx_broadcast_in_ps; + __le16 beacon_rx_timeout; + __le16 broadcast_timeout; + /* Consecutive PS Poll failures before updating the host */ u8 ps_poll_threshold; - u8 pad[2]; + u8 pad[1]; } __packed; struct acx_event_mask { @@ -348,6 +370,8 @@ struct acx_event_mask { struct acx_feature_config { struct acx_header header; + u8 role_id; + u8 padding[3]; __le32 options; __le32 data_flow_options; } __packed; @@ -355,16 +379,18 @@ struct acx_feature_config { struct acx_current_tx_power { struct acx_header header; + u8 role_id; u8 current_tx_power; - u8 padding[3]; + u8 padding[2]; } __packed; struct acx_wake_up_condition { struct acx_header header; + u8 role_id; u8 wake_up_event; /* Only one bit can be set */ u8 listen_interval; - u8 pad[2]; + u8 pad[1]; } __packed; struct acx_aid { @@ -373,8 +399,9 @@ struct acx_aid { /* * To be set when associated with an AP. */ + u8 role_id; + u8 reserved; __le16 aid; - u8 pad[2]; } __packed; enum acx_preamble_type { @@ -389,8 +416,9 @@ struct acx_preamble { * When set, the WiLink transmits the frames with a short preamble and * when cleared, the WiLink transmits the frames with a long preamble. */ + u8 role_id; u8 preamble; - u8 padding[3]; + u8 padding[2]; } __packed; enum acx_ctsprotect_type { @@ -400,8 +428,9 @@ enum acx_ctsprotect_type { struct acx_ctsprotect { struct acx_header header; + u8 role_id; u8 ctsprotect; - u8 padding[3]; + u8 padding[2]; } __packed; struct acx_tx_statistics { @@ -636,18 +665,9 @@ struct acx_rate_class { #define ACX_TX_BASIC_RATE 0 #define ACX_TX_AP_FULL_RATE 1 -#define ACX_TX_RATE_POLICY_CNT 2 -struct acx_sta_rate_policy { - struct acx_header header; - - __le32 rate_class_cnt; - struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; -} __packed; - - #define ACX_TX_AP_MODE_MGMT_RATE 4 #define ACX_TX_AP_MODE_BCST_RATE 5 -struct acx_ap_rate_policy { +struct acx_rate_policy { struct acx_header header; __le32 rate_policy_idx; @@ -656,22 +676,23 @@ struct acx_ap_rate_policy { struct acx_ac_cfg { struct acx_header header; + u8 role_id; u8 ac; + u8 aifsn; u8 cw_min; __le16 cw_max; - u8 aifsn; - u8 reserved; __le16 tx_op_limit; } __packed; struct acx_tid_config { struct acx_header header; + u8 role_id; u8 queue_id; u8 channel_type; u8 tsid; u8 ps_scheme; u8 ack_policy; - u8 padding[3]; + u8 padding[2]; __le32 apsd_conf[2]; } __packed; @@ -687,19 +708,7 @@ struct acx_tx_config_options { __le16 tx_compl_threshold; /* number of packets */ } __packed; -#define ACX_TX_DESCRIPTORS 32 - -struct wl1271_acx_ap_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_sta_config_memory { +struct wl12xx_acx_config_memory { struct acx_header header; u8 rx_mem_block_num; @@ -773,9 +782,10 @@ struct wl1271_acx_rx_config_opt { struct wl1271_acx_bet_enable { struct acx_header header; + u8 role_id; u8 enable; u8 max_consecutive; - u8 padding[2]; + u8 padding[1]; } __packed; #define ACX_IPV4_VERSION 4 @@ -788,9 +798,10 @@ struct wl1271_acx_bet_enable { struct wl1271_acx_arp_filter { struct acx_header header; + u8 role_id; u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ u8 enable; /* bitmap of enabled ARP filtering features */ - u8 padding[2]; + u8 padding[1]; 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 @@ -808,8 +819,9 @@ struct wl1271_acx_pm_config { struct wl1271_acx_keep_alive_mode { struct acx_header header; + u8 role_id; u8 enabled; - u8 padding[3]; + u8 padding[2]; } __packed; enum { @@ -825,11 +837,11 @@ enum { struct wl1271_acx_keep_alive_config { struct acx_header header; - __le32 period; + u8 role_id; u8 index; u8 tpl_validation; u8 trigger; - u8 padding; + __le32 period; } __packed; #define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) @@ -873,20 +885,23 @@ enum { struct wl1271_acx_rssi_snr_trigger { struct acx_header header; - __le16 threshold; - __le16 pacing; /* 0 - 60000 ms */ + u8 role_id; u8 metric; u8 type; u8 dir; + __le16 threshold; + __le16 pacing; /* 0 - 60000 ms */ u8 hysteresis; u8 index; u8 enable; - u8 padding[2]; + u8 padding[1]; }; struct wl1271_acx_rssi_snr_avg_weights { struct acx_header header; + u8 role_id; + u8 padding[3]; u8 rssi_beacon; u8 rssi_data; u8 snr_beacon; @@ -916,13 +931,8 @@ struct wl1271_acx_ht_capabilities { */ __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]; + /* Indicates to which link these capabilities apply. */ + u8 hlid; /* * This the maximum A-MPDU length supported by the AP. The FW may not @@ -932,6 +942,8 @@ struct wl1271_acx_ht_capabilities { /* This is the minimal spacing required when sending A-MPDUs to the AP*/ u8 ampdu_min_spacing; + + u8 padding; } __packed; /* HT Capabilites Fw Bit Mask Mapping */ @@ -950,6 +962,8 @@ struct wl1271_acx_ht_capabilities { struct wl1271_acx_ht_information { struct acx_header header; + u8 role_id; + /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ u8 rifs_mode; @@ -971,7 +985,7 @@ struct wl1271_acx_ht_information { */ u8 dual_cts_protection; - u8 padding[3]; + u8 padding[2]; } __packed; #define RX_BA_WIN_SIZE 8 @@ -1041,6 +1055,7 @@ struct wl1271_acx_fw_tsf_information { struct wl1271_acx_ps_rx_streaming { struct acx_header header; + u8 role_id; u8 tid; u8 enable; @@ -1049,17 +1064,20 @@ struct wl1271_acx_ps_rx_streaming { /* timeout before first trigger (0-200 msec) */ u8 timeout; + u8 padding[3]; } __packed; struct wl1271_acx_ap_max_tx_retry { struct acx_header header; + u8 role_id; + u8 padding_1; + /* * the number of frames transmission failures before * issuing the aging event. */ __le16 max_tx_retry; - u8 padding_1[2]; } __packed; struct wl1271_acx_config_ps { @@ -1151,10 +1169,7 @@ enum { 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, @@ -1170,7 +1185,6 @@ enum { 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, @@ -1202,6 +1216,9 @@ enum { ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, + ACX_BURST_MODE = 0x005C, + ACX_SET_RATE_MGMT_PARAMS = 0x005D, + ACX_SET_RATE_ADAPT_PARAMS = 0x0060, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, ACX_GEN_FW_CMD = 0x0070, ACX_HOST_IF_CFG_BITMAP = 0x0071, @@ -1256,8 +1273,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, u32 apsd_conf0, u32 apsd_conf1); int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); int wl1271_acx_tx_config_options(struct wl1271 *wl); -int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); -int wl1271_acx_sta_mem_cfg(struct wl1271 *wl); +int wl12xx_acx_mem_cfg(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl); int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 44cd515a057e..5a3325761d04 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -388,7 +388,7 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_sta_mem_cfg(wl); + ret = wl12xx_acx_mem_cfg(wl); if (ret < 0) return ret; @@ -447,7 +447,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_ap_mem_cfg(wl); + ret = wl12xx_acx_mem_cfg(wl); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 96f76b104e75..07d50b761610 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -718,7 +718,7 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - ret = wl1271_acx_sta_mem_cfg(wl); + ret = wl12xx_acx_mem_cfg(wl); if (ret < 0) goto out_free_memmap; @@ -1981,6 +1981,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; wl->sched_scanning = false; + wl->role_id = WL12XX_INVALID_ROLE_ID; /* * this is performed after the cancel_work calls and the associated @@ -4317,6 +4318,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->sched_scanning = false; wl->tx_security_seq = 0; wl->tx_security_last_seq_lsb = 0; + wl->role_id = WL12XX_INVALID_ROLE_ID; + wl->sta_hlid = WL12XX_INVALID_LINK_ID; setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, (unsigned long) wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index f708cd70185a..9f71dc75a01b 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -138,6 +138,8 @@ extern u32 wl12xx_debug_level; #define WL1271_DEFAULT_DTIM_PERIOD 1 #define WL12XX_MAX_LINKS 8 +#define WL12XX_INVALID_ROLE_ID 0xff +#define WL12XX_INVALID_LINK_ID 0xff #define WL1271_AP_GLOBAL_HLID 0 #define WL1271_AP_BROADCAST_HLID 1 #define WL1271_AP_STA_HLID_START 2 @@ -390,6 +392,8 @@ struct wl1271 { u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; int channel; + u8 role_id; + u8 sta_hlid; struct wl1271_acx_mem_map *target_mem_map; -- cgit v1.2.3 From c690ec816f9fa2ab2b6200c5b79b6933acca49a4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:07 +0300 Subject: wl12xx: update commands & events Change the commands and events according to the new fw api (fw >= 6/7.3.0.0.75). The main change is the replacement of JOIN/DISCONNECT commands, with ROLE_START/ROLE_STOP commands. The use of these commands should be preceded by the ROLE_ENABLE command (allocating role resources), and followed by the ROLE_DISABLE command (freeing role resources). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 17 +- drivers/net/wireless/wl12xx/cmd.c | 515 ++++++++++++++++++++--------------- drivers/net/wireless/wl12xx/cmd.h | 314 +++++++++++---------- drivers/net/wireless/wl12xx/event.c | 4 +- drivers/net/wireless/wl12xx/event.h | 80 +++--- drivers/net/wireless/wl12xx/init.c | 6 - drivers/net/wireless/wl12xx/main.c | 26 +- drivers/net/wireless/wl12xx/tx.c | 5 +- drivers/net/wireless/wl12xx/wl12xx.h | 5 + 9 files changed, 527 insertions(+), 445 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 41791ffd26ea..cc70422c0575 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -494,21 +494,18 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) 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 | PERIODIC_SCAN_REPORT_EVENT_ID | - PERIODIC_SCAN_COMPLETE_EVENT_ID; - - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID | - INACTIVE_STA_EVENT_ID | - MAX_TX_RETRY_EVENT_ID; - else - wl->event_mask |= DUMMY_PACKET_EVENT_ID | - BA_SESSION_RX_CONSTRAINT_EVENT_ID; + PERIODIC_SCAN_COMPLETE_EVENT_ID | + DUMMY_PACKET_EVENT_ID | + PEER_REMOVE_COMPLETE_EVENT_ID | + BA_SESSION_RX_CONSTRAINT_EVENT_ID | + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | + INACTIVE_STA_EVENT_ID | + MAX_TX_RETRY_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index b6ef65a57b71..b13eed129a92 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -363,61 +363,294 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) return 0; } -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) +int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id) { - struct wl1271_cmd_join *join; - int ret, i; - u8 *bssid; + struct wl12xx_cmd_role_enable *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role enable"); + + if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID)) + return -EBUSY; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + /* get role id */ + cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES); + if (cmd->role_id >= WL12XX_MAX_ROLES) { + ret = -EBUSY; + goto out_free; + } + + memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN); + cmd->role_type = role_type; + + ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto out_free; + } + + __set_bit(cmd->role_id, wl->roles_map); + *role_id = cmd->role_id; - join = kzalloc(sizeof(*join), GFP_KERNEL); - if (!join) { +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id) +{ + struct wl12xx_cmd_role_disable *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role disable"); + + if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID)) + return -ENOENT; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { ret = -ENOMEM; goto out; } + cmd->role_id = *role_id; + + ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role disable"); + goto out_free; + } - wl1271_debug(DEBUG_CMD, "cmd join"); + __clear_bit(*role_id, wl->roles_map); + *role_id = WL12XX_INVALID_ROLE_ID; - /* Reverse order BSSID */ - bssid = (u8 *) &join->bssid_lsb; - for (i = 0; i < ETH_ALEN; i++) - bssid[i] = wl->bssid[ETH_ALEN - i - 1]; +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl12xx_allocate_link(struct wl1271 *wl, u8 *hlid) +{ + u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); + if (link >= WL12XX_MAX_LINKS) + return -EBUSY; + + __set_bit(link, wl->links_map); + *hlid = link; + return 0; +} + +static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid) +{ + if (*hlid == WL12XX_INVALID_LINK_ID) + return; + + __clear_bit(*hlid, wl->links_map); + *hlid = WL12XX_INVALID_LINK_ID; +} + +int wl12xx_cmd_role_start_sta(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + int ret; - join->bss_type = bss_type; - join->basic_rate_set = cpu_to_le32(wl->basic_rate_set); - join->supported_rate_set = cpu_to_le32(wl->rate_set); + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id); + + cmd->role_id = wl->role_id; if (wl->band == IEEE80211_BAND_5GHZ) - join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; + cmd->band = WL12XX_BAND_5GHZ; + cmd->channel = wl->channel; + cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set); + cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; + cmd->sta.ssid_len = wl->ssid_len; + memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len); + memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wl->rate_set); + + if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, &wl->sta_hlid); + if (ret) + goto out_free; + } + cmd->sta.hlid = wl->sta_hlid; + cmd->sta.session = wl->session_counter; + cmd->sta.remote_rates = cpu_to_le32(wl->rate_set); + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " + "basic_rate_set: 0x%x, remote_rates: 0x%x", + wl->role_id, cmd->sta.hlid, cmd->sta.session, + wl->basic_rate_set, wl->rate_set); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role start sta"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error. */ + wl12xx_free_link(wl, &wl->sta_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} - join->beacon_interval = cpu_to_le16(wl->beacon_int); - join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wl->sta_hlid == WL12XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } - join->channel = wl->channel; - join->ssid_len = wl->ssid_len; - memcpy(join->ssid, wl->ssid, wl->ssid_len); + wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wl->role_id); - join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; + cmd->role_id = wl->role_id; + cmd->disc_type = DISCONNECT_IMMEDIATE; + cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); - wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x", - join->basic_rate_set, join->supported_rate_set); + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop sta"); + goto out_free; + } - ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0); + ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); if (ret < 0) { - wl1271_error("failed to initiate cmd join"); + wl1271_error("cmd role stop sta event completion error"); goto out_free; } - ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID); - if (ret < 0) - wl1271_error("cmd join event completion error"); + wl12xx_free_link(wl, &wl->sta_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_start_ap(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id); + + /* + * We currently do not support hidden SSID. The real SSID + * should be fetched from mac80211 first. + */ + if (wl->ssid_len == 0) { + wl1271_warning("Hidden SSID currently not supported for AP"); + ret = -EINVAL; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = wl->role_id; + cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); + cmd->ap.bss_index = WL1271_AP_BSS_INDEX; + cmd->ap.global_hlid = WL1271_AP_GLOBAL_HLID; + cmd->ap.broadcast_hlid = WL1271_AP_BROADCAST_HLID; + cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set); + cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->ap.dtim_interval = bss_conf->dtim_period; + cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; + cmd->channel = wl->channel; + cmd->ap.ssid_len = wl->ssid_len; + cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; + memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len); + cmd->ap.local_rates = cpu_to_le32(0xffffffff); + + switch (wl->band) { + case IEEE80211_BAND_2GHZ: + cmd->band = RADIO_BAND_2_4GHZ; + break; + case IEEE80211_BAND_5GHZ: + cmd->band = RADIO_BAND_5GHZ; + break; + default: + wl1271_warning("ap start - unknown band: %d", (int)wl->band); + cmd->band = RADIO_BAND_2_4GHZ; + break; + } + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role start ap"); + goto out_free; + } out_free: - kfree(join); + kfree(cmd); out: return ret; } +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wl->role_id); + + cmd->role_id = wl->role_id; + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop ap"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + + /** * send test command to firmware * @@ -565,6 +798,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) goto out; } + ps_params->role_id = wl->role_id; ps_params->ps_mode = ps_mode; ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, @@ -811,9 +1045,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) wl->basic_rate); } -int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) +int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid) { - struct wl1271_cmd_set_sta_keys *cmd; + struct wl1271_cmd_set_keys *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); @@ -824,36 +1058,7 @@ int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) 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_ap_default_wep_key(struct wl1271 *wl, u8 id) -{ - struct wl1271_cmd_set_ap_keys *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->hlid = WL1271_AP_BROADCAST_HLID; + cmd->hlid = hlid; cmd->key_id = id; cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; cmd->key_action = cpu_to_le16(KEY_SET_ID); @@ -861,7 +1066,7 @@ int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id) ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret); + wl1271_warning("cmd set_default_wep_key failed: %d", ret); goto out; } @@ -875,7 +1080,7 @@ int wl1271_cmd_set_sta_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_sta_keys *cmd; + struct wl1271_cmd_set_keys *cmd; int ret = 0; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -884,8 +1089,14 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, goto out; } - if (key_type != KEY_WEP) - memcpy(cmd->addr, addr, ETH_ALEN); + cmd->hlid = wl->sta_hlid; + + if (key_type == KEY_WEP) + cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; + else if (is_broadcast_ether_addr(addr)) + cmd->lid_key_type = BROADCAST_LID_TYPE; + else + cmd->lid_key_type = UNICAST_LID_TYPE; cmd->key_action = cpu_to_le16(action); cmd->key_size = key_size; @@ -894,10 +1105,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 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; + cmd->key_id = id; if (key_type == KEY_TKIP) { /* @@ -928,11 +1136,15 @@ out: return ret; } +/* + * TODO: merge with sta/ibss into 1 set_key function. + * note there are slight diffs + */ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16) { - struct wl1271_cmd_set_ap_keys *cmd; + struct wl1271_cmd_set_keys *cmd; int ret = 0; u8 lid_type; @@ -989,45 +1201,12 @@ out: 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; - } - - /* 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) +int wl12xx_cmd_set_peer_state(struct wl1271 *wl) { - struct wl1271_cmd_set_sta_state *cmd; + struct wl12xx_cmd_set_peer_state *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd set sta state"); + wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", wl->sta_hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1035,11 +1214,12 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl) goto out; } + cmd->hlid = wl->sta_hlid; cmd->state = WL1271_CMD_STA_STATE_CONNECTED; - ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to send set STA state command"); + wl1271_error("failed to send set peer state command"); goto out_free; } @@ -1049,106 +1229,12 @@ out_free: out: return ret; } - -int wl1271_cmd_start_bss(struct wl1271 *wl) -{ - struct wl1271_cmd_bss_start *cmd; - struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd start bss"); - - /* - * FIXME: We currently do not support hidden SSID. The real SSID - * should be fetched from mac80211 first. - */ - if (wl->ssid_len == 0) { - wl1271_warning("Hidden SSID currently not supported for AP"); - ret = -EINVAL; - goto out; - } - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); - - cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); - cmd->bss_index = WL1271_AP_BSS_INDEX; - cmd->global_hlid = WL1271_AP_GLOBAL_HLID; - cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; - cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set); - cmd->beacon_interval = cpu_to_le16(wl->beacon_int); - cmd->dtim_interval = bss_conf->dtim_period; - cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP; - cmd->channel = wl->channel; - cmd->ssid_len = wl->ssid_len; - cmd->ssid_type = SSID_TYPE_PUBLIC; - memcpy(cmd->ssid, wl->ssid, wl->ssid_len); - - switch (wl->band) { - case IEEE80211_BAND_2GHZ: - cmd->band = RADIO_BAND_2_4GHZ; - break; - case IEEE80211_BAND_5GHZ: - cmd->band = RADIO_BAND_5GHZ; - break; - default: - wl1271_warning("bss start - unknown band: %d", (int)wl->band); - cmd->band = RADIO_BAND_2_4GHZ; - break; - } - - ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd start bss"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl1271_cmd_stop_bss(struct wl1271 *wl) -{ - struct wl1271_cmd_bss_start *cmd; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd stop bss"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->bss_index = WL1271_AP_BSS_INDEX; - - ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd stop bss"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) { - struct wl1271_cmd_add_sta *cmd; + struct wl12xx_cmd_add_peer *cmd; int ret; - wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid); + wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1168,11 +1254,11 @@ int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta->supp_rates[wl->band])); - wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates); + wl1271_debug(DEBUG_CMD, "new peer rates: 0x%x", cmd->supported_rates); - ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to initiate cmd add sta"); + wl1271_error("failed to initiate cmd add peer"); goto out_free; } @@ -1183,12 +1269,12 @@ out: return ret; } -int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) +int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) { - struct wl1271_cmd_remove_sta *cmd; + struct wl12xx_cmd_remove_peer *cmd; int ret; - wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid); + wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1201,9 +1287,9 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) cmd->reason_opcode = 0; cmd->send_deauth_flag = 0; - ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to initiate cmd remove sta"); + wl1271_error("failed to initiate cmd remove peer"); goto out_free; } @@ -1211,7 +1297,8 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) * We are ok with a timeout here. The event is sometimes not sent * due to a firmware bug. */ - wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID); + wl1271_cmd_wait_for_event_or_timeout(wl, + PEER_REMOVE_COMPLETE_EVENT_ID); out_free: kfree(cmd); diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index bba077ecd945..16e0a877bf57 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -36,7 +36,14 @@ int wl128x_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); int wl128x_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 wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id); +int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); +int wl12xx_cmd_role_start_dev(struct wl1271 *wl); +int wl12xx_cmd_role_stop_dev(struct wl1271 *wl); +int wl12xx_cmd_role_start_sta(struct wl1271 *wl); +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl); +int wl12xx_cmd_role_start_ap(struct wl1271 *wl); +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl); 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); @@ -56,20 +63,16 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr); int wl1271_build_qos_null_data(struct wl1271 *wl); int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); -int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id); -int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id); +int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid); int wl1271_cmd_set_sta_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_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16); -int wl1271_cmd_disconnect(struct wl1271 *wl); -int wl1271_cmd_set_sta_state(struct wl1271 *wl); -int wl1271_cmd_start_bss(struct wl1271 *wl); -int wl1271_cmd_stop_bss(struct wl1271 *wl); -int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); -int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid); +int wl12xx_cmd_set_peer_state(struct wl1271 *wl); +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); +int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); @@ -83,25 +86,21 @@ enum wl1271_commands { 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_QUIET_ELEMENT_SET_STATE = 29, 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, @@ -109,16 +108,30 @@ enum wl1271_commands { CMD_CONNECTION_SCAN_SSID_CFG = 49, CMD_START_PERIODIC_SCAN = 50, CMD_STOP_PERIODIC_SCAN = 51, - CMD_SET_STA_STATE = 52, - CMD_CONFIG_FWLOGGER = 53, - CMD_START_FWLOGGER = 54, - CMD_STOP_FWLOGGER = 55, + CMD_SET_PEER_STATE = 52, + CMD_REMAIN_ON_CHANNEL = 53, + CMD_CANCEL_REMAIN_ON_CHANNEL = 54, - /* AP mode commands */ - CMD_BSS_START = 60, - CMD_BSS_STOP = 61, - CMD_ADD_STA = 62, - CMD_REMOVE_STA = 63, + CMD_CONFIG_FWLOGGER = 55, + CMD_START_FWLOGGER = 56, + CMD_STOP_FWLOGGER = 57, + + /* AP commands */ + CMD_ADD_PEER = 62, + CMD_REMOVE_PEER = 63, + + /* Role API */ + CMD_ROLE_ENABLE = 70, + CMD_ROLE_DISABLE = 71, + CMD_ROLE_START = 72, + CMD_ROLE_STOP = 73, + + /* WIFI Direct */ + CMD_WFD_START_DISCOVERY = 80, + CMD_WFD_STOP_DISCOVERY = 81, + CMD_WFD_ATTRIBUTE_CONFIG = 82, + + CMD_NOP = 100, NUM_COMMANDS, MAX_COMMAND_ID = 0xFFFF, @@ -147,14 +160,12 @@ enum cmd_templ { CMD_TEMPL_CTS, /* * For CTS-to-self (FastCTS) mechanism * for BT/WLAN coexistence (SoftGemini). */ - CMD_TEMPL_ARP_RSP, - CMD_TEMPL_LINK_MEASUREMENT_REPORT, - - /* AP-mode specific */ - CMD_TEMPL_AP_BEACON = 13, + CMD_TEMPL_AP_BEACON, CMD_TEMPL_AP_PROBE_RESPONSE, - CMD_TEMPL_AP_ARP_RSP, + CMD_TEMPL_ARP_RSP, CMD_TEMPL_DEAUTH_AP, + CMD_TEMPL_TEMPORARY, + CMD_TEMPL_LINK_MEASUREMENT_REPORT, CMD_TEMPL_MAX = 0xff }; @@ -193,6 +204,7 @@ enum { CMD_STATUS_WRONG_NESTING = 19, CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + CMD_STATUS_TEMPLATE_OOM = 23, MAX_COMMAND_STATUS = 0xff }; @@ -210,38 +222,114 @@ enum { #define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 #define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 -struct wl1271_cmd_join { +struct wl12xx_cmd_role_enable { struct wl1271_cmd_header header; - __le32 bssid_lsb; - __le16 bssid_msb; - __le16 beacon_interval; /* in TBTTs */ - __le32 rx_config_options; - __le32 rx_filter_options; + u8 role_id; + u8 role_type; + u8 mac_address[ETH_ALEN]; +} __packed; - /* - * 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; - __le32 supported_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; +struct wl12xx_cmd_role_disable { + struct wl1271_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +enum wl12xx_band { + WL12XX_BAND_2_4GHZ = 0, + WL12XX_BAND_5GHZ = 1, + WL12XX_BAND_JAPAN_4_9_GHZ = 2, + WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ, + WL12XX_BAND_INVALID = 0x7E, + WL12XX_BAND_MAX_RADIO = 0x7F, +}; + +struct wl12xx_cmd_role_start { + struct wl1271_cmd_header header; + + u8 role_id; + u8 band; u8 channel; - u8 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ctrl; /* JOIN_CMD_CTRL_* */ - u8 reserved[3]; + u8 padding; + + union { + struct { + u8 hlid; + u8 session; + u8 padding_1[54]; + } __packed device; + /* sta & p2p_cli use the same struct */ + struct { + u8 bssid[ETH_ALEN]; + u8 hlid; /* data hlid */ + u8 session; + __le32 remote_rates; /* remote supported rates */ + + /* + * 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; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + } __packed sta; + struct { + u8 bssid[ETH_ALEN]; + u8 hlid; /* data hlid */ + u8 dtim_interval; + __le32 remote_rates; /* remote supported rates */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + + u8 padding_1[4]; + } __packed ibss; + /* ap & p2p_go use the same struct */ + struct { + __le16 aging_period; /* in secs */ + u8 beacon_expiry; /* in ms */ + u8 bss_index; + /* The host link id for the AP's global queue */ + u8 global_hlid; + /* The host link id for the AP's broadcast queue */ + u8 broadcast_hlid; + + __le16 beacon_interval; /* in TBTTs */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 dtim_interval; + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + u8 padding_1[5]; + } __packed ap; + }; +} __packed; + +struct wl12xx_cmd_role_stop { + struct wl1271_cmd_header header; + + u8 role_id; + u8 disc_type; /* only STA and P2P_CLI */ + __le16 reason; /* only STA and P2P_CLI */ } __packed; struct cmd_enabledisable_path { @@ -287,8 +375,9 @@ enum wl1271_cmd_ps_mode { struct wl1271_cmd_ps_params { struct wl1271_cmd_header header; + u8 role_id; u8 ps_mode; /* STATION_* */ - u8 padding[3]; + u8 padding[2]; } __packed; /* HW encryption keys */ @@ -301,6 +390,12 @@ enum wl1271_cmd_key_action { MAX_KEY_ACTION = 0xffff, }; +enum wl1271_cmd_lid_key_type { + UNICAST_LID_TYPE = 0, + BROADCAST_LID_TYPE = 1, + WEP_DEFAULT_LID_TYPE = 2 +}; + enum wl1271_cmd_key_type { KEY_NONE = 0, KEY_WEP = 1, @@ -309,44 +404,7 @@ enum wl1271_cmd_key_type { KEY_GEM = 4, }; -/* FIXME: Add description for key-types */ - -struct wl1271_cmd_set_sta_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; - -enum wl1271_cmd_lid_key_type { - UNICAST_LID_TYPE = 0, - BROADCAST_LID_TYPE = 1, - WEP_DEFAULT_LID_TYPE = 2 -}; - -struct wl1271_cmd_set_ap_keys { +struct wl1271_cmd_set_keys { struct wl1271_cmd_header header; /* @@ -496,69 +554,23 @@ enum wl1271_disconnect_type { 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 wl12xx_cmd_set_peer_state { struct wl1271_cmd_header header; + u8 hlid; u8 state; - u8 padding[3]; + u8 padding[2]; } __packed; -enum wl1271_ssid_type { - SSID_TYPE_PUBLIC = 0, - SSID_TYPE_HIDDEN = 1 +enum wl12xx_ssid_type { + WL12XX_SSID_TYPE_PUBLIC = 0, + WL12XX_SSID_TYPE_HIDDEN = 1, + WL12XX_SSID_TYPE_ANY = 2, }; -struct wl1271_cmd_bss_start { - struct wl1271_cmd_header header; - - /* wl1271_ssid_type */ - u8 ssid_type; - u8 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 padding_1[2]; - - /* Basic rate set */ - __le32 basic_rate_set; - /* Aging period in seconds*/ - __le16 aging_period; - - /* - * This field specifies the time between target beacon - * transmission times (TBTTs), in time units (TUs). - * Valid values are 1 to 1024. - */ - __le16 beacon_interval; - u8 bssid[ETH_ALEN]; - u8 bss_index; - /* Radio band */ - u8 band; - u8 channel; - /* The host link id for the AP's global queue */ - u8 global_hlid; - /* The host link id for the AP's broadcast queue */ - u8 broadcast_hlid; - /* DTIM count */ - u8 dtim_interval; - /* Beacon expiry time in ms */ - u8 beacon_expiry; - u8 padding_2[3]; -} __packed; - -struct wl1271_cmd_add_sta { +struct wl12xx_cmd_add_peer { struct wl1271_cmd_header header; u8 addr[ETH_ALEN]; @@ -572,7 +584,7 @@ struct wl1271_cmd_add_sta { u8 padding1; } __packed; -struct wl1271_cmd_remove_sta { +struct wl12xx_cmd_remove_peer { struct wl1271_cmd_header header; u8 hlid; diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 304aaa2ee011..431ceae6c1c8 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -285,10 +285,10 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " - "ba_allowed = 0x%x", mbox->ba_allowed); + "ba_allowed = 0x%x", mbox->rx_ba_allowed); if (wl->vif) - wl1271_stop_ba_event(wl, mbox->ba_allowed); + wl1271_stop_ba_event(wl, mbox->rx_ba_allowed); } if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index e524ad6fe4e3..49c1a0ede5b1 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -49,32 +49,27 @@ enum { 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), + WFD_DISCOVERY_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), + /* BIT(16) is reserved */ CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), MAX_TX_RETRY_EVENT_ID = BIT(20), - /* STA: dummy paket for dynamic mem blocks */ - DUMMY_PACKET_EVENT_ID = BIT(21), - /* AP: STA remove complete */ - STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), + DUMMY_PACKET_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), - /* STA: SG prediction */ - SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), - /* AP: Inactive STA */ - INACTIVE_STA_EVENT_ID = BIT(23), + CHANGE_AUTO_MODE_TIMEOUT_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), + INACTIVE_STA_EVENT_ID = BIT(26), + PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27), PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31), EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, }; @@ -83,15 +78,6 @@ enum { EVENT_ENTER_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 { @@ -100,49 +86,45 @@ struct event_mailbox { __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; + u8 completed_scan_status; + u8 reserved_3; - __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; + /* tuned channel (roc) */ + u8 roc_channel; - /* AP FW only */ - u8 hlid_removed; + __le16 hlid_removed_bitmap; - /* a bitmap of hlids for stations that have been inactive too long */ + /* bitmap of aged stations (by HLID) */ __le16 sta_aging_status; - /* a bitmap of hlids for stations which didn't respond to TX */ + /* bitmap of stations (by HLID) which exceeded max tx retries */ __le16 sta_tx_retry_exceeded; - /* - * Bitmap, Each bit set represents the Role ID for which this constraint - * is set. Range: 0 - FF, FF means ANY role - */ - u8 ba_role_id; - /* - * Bitmap, Each bit set represents the Link ID for which this constraint - * is set. Not applicable if ba_role_id is set to ANY role (FF). - * Range: 0 - FFFF, FFFF means ANY link in that role - */ - u8 ba_link_id; - u8 ba_allowed; - - u8 reserved_5[21]; + /* discovery completed results */ + u8 discovery_tag; + u8 number_of_preq_results; + u8 number_of_prsp_results; + u8 reserved_5; + + /* rx ba constraint */ + u8 role_id; /* 0xFF means any role. */ + u8 rx_ba_allowed; + u8 reserved_6[2]; + + u8 ps_poll_delivery_failure_role_ids; + u8 stopped_role_ids; + u8 started_role_ids; + u8 change_auto_mode_timeout; + + u8 reserved_7[12]; } __packed; int wl1271_event_unmask(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 5a3325761d04..76e6f37b87ad 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -404,12 +404,6 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) { int ret, i; - ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key); - if (ret < 0) { - wl1271_warning("couldn't set default key"); - return ret; - } - /* disable all keep-alive templates */ for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { ret = wl1271_acx_keep_alive_config(wl, i, diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 07d50b761610..4689d0bccf6d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -415,7 +415,7 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate) if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) return 0; - ret = wl1271_cmd_set_sta_state(wl); + ret = wl12xx_cmd_set_peer_state(wl); if (ret < 0) return ret; @@ -1982,6 +1982,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl->ap_ps_map = 0; wl->sched_scanning = false; wl->role_id = WL12XX_INVALID_ROLE_ID; + memset(wl->roles_map, 0, sizeof(wl->roles_map)); + memset(wl->links_map, 0, sizeof(wl->links_map)); /* * this is performed after the cancel_work calls and the associated @@ -2030,7 +2032,7 @@ static int wl1271_dummy_join(struct wl1271 *wl) memcpy(wl->bssid, dummy_bssid, ETH_ALEN); - ret = wl1271_cmd_join(wl, wl->set_bss_type); + ret = wl12xx_cmd_role_start_sta(wl); if (ret < 0) goto out; @@ -2059,7 +2061,7 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) if (set_assoc) set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); - ret = wl1271_cmd_join(wl, wl->set_bss_type); + ret = wl12xx_cmd_role_start_sta(wl); if (ret < 0) goto out; @@ -2100,7 +2102,7 @@ static int wl1271_unjoin(struct wl1271 *wl) int ret; /* to stop listening to a channel, we disconnect */ - ret = wl1271_cmd_disconnect(wl); + ret = wl12xx_cmd_role_stop_sta(wl); if (ret < 0) goto out; @@ -2472,7 +2474,8 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl) } if (wep_key_added) { - ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key); + ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key, + WL1271_AP_BROADCAST_HLID); if (ret < 0) goto out; } @@ -2550,8 +2553,9 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, /* the default WEP key needs to be configured at least once */ if (key_type == KEY_WEP) { - ret = wl1271_cmd_set_sta_default_wep_key(wl, - wl->default_key); + ret = wl12xx_cmd_set_default_wep_key(wl, + wl->default_key, + wl->sta_hlid); if (ret < 0) return ret; } @@ -3008,7 +3012,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BEACON_ENABLED)) { if (bss_conf->enable_beacon) { if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { - ret = wl1271_cmd_start_bss(wl); + ret = wl12xx_cmd_role_start_ap(wl); if (ret < 0) goto out; @@ -3021,7 +3025,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, } } else { if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { - ret = wl1271_cmd_stop_bss(wl); + ret = wl12xx_cmd_role_stop_ap(wl); if (ret < 0) goto out; @@ -3532,7 +3536,7 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, if (ret < 0) goto out_free_sta; - ret = wl1271_cmd_add_sta(wl, sta, hlid); + ret = wl12xx_cmd_add_peer(wl, sta, hlid); if (ret < 0) goto out_sleep; @@ -3575,7 +3579,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid); + ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); if (ret < 0) goto out_sleep; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 8a745fbe0f45..f4973366a88b 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -37,9 +37,10 @@ static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); if (is_ap) - ret = wl1271_cmd_set_ap_default_wep_key(wl, id); + ret = wl12xx_cmd_set_default_wep_key(wl, id, + WL1271_AP_BROADCAST_HLID); else - ret = wl1271_cmd_set_sta_default_wep_key(wl, id); + ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 9f71dc75a01b..3d43875163e1 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -137,6 +137,7 @@ extern u32 wl12xx_debug_level; #define WL1271_DEFAULT_BEACON_INT 100 #define WL1271_DEFAULT_DTIM_PERIOD 1 +#define WL12XX_MAX_ROLES 4 #define WL12XX_MAX_LINKS 8 #define WL12XX_INVALID_ROLE_ID 0xff #define WL12XX_INVALID_LINK_ID 0xff @@ -394,6 +395,10 @@ struct wl1271 { int channel; u8 role_id; u8 sta_hlid; + u8 dev_hlid; + + unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; + unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; struct wl1271_acx_mem_map *target_mem_map; -- cgit v1.2.3 From b78b47eb73fcf4f04226ab8014aa8dadf11675d9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:08 +0300 Subject: wl12xx: enable/disable role on interface add/remove According to the new multi-role flow, we have to enable the role before using (starting) it, and disable it on cleanup (after it's no longer needed). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 4689d0bccf6d..3e77f59e3397 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1779,6 +1779,21 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); } +static u8 wl12xx_get_role_type(struct wl1271 *wl) +{ + switch (wl->bss_type) { + case BSS_TYPE_AP_BSS: + return WL1271_ROLE_AP; + + case BSS_TYPE_STA_BSS: + return WL1271_ROLE_STA; + + default: + wl1271_error("invalid bss_type: %d", wl->bss_type); + } + return WL12XX_INVALID_ROLE_TYPE; +} + static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1786,6 +1801,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct wiphy *wiphy = hw->wiphy; int retries = WL1271_BOOT_RETRIES; int ret = 0; + u8 role_type; bool booted = false; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", @@ -1826,6 +1842,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } + role_type = wl12xx_get_role_type(wl); + if (role_type == WL12XX_INVALID_ROLE_TYPE) { + ret = -EINVAL; + goto out; + } memcpy(wl->mac_addr, vif->addr, ETH_ALEN); if (wl->state != WL1271_STATE_OFF) { @@ -1845,6 +1866,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, if (ret < 0) goto power_off; + ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id); + if (ret < 0) + goto irq_disable; + ret = wl1271_hw_init(wl); if (ret < 0) goto irq_disable; @@ -1909,6 +1934,7 @@ out: static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues) { + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); @@ -1933,6 +1959,21 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ieee80211_scan_completed(wl->hw, true); } + if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { + /* disable active roles */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto deinit; + + ret = wl12xx_cmd_role_disable(wl, &wl->role_id); + if (ret < 0) + goto deinit; + + wl1271_ps_elp_sleep(wl); + } +deinit: + wl->sta_hlid = WL12XX_INVALID_LINK_ID; + /* * this must be before the cancel_work calls below, so that the work * functions don't perform further work. -- cgit v1.2.3 From 04e8079c69d6fa1aa023b0b6f58f818f965c10bb Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:09 +0300 Subject: wl12xx: add device role commands The device role is a special role used for rx and tx frames prior to association (as the STA role can get packets only from its associated bssid) Since this role is required for the sta association process, we enable it when a new sta interface is created. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 91 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/main.c | 25 +++++++++- drivers/net/wireless/wl12xx/wl12xx.h | 1 + 3 files changed, 116 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index b13eed129a92..e29343ed6ea2 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -458,6 +458,97 @@ static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid) *hlid = WL12XX_INVALID_LINK_ID; } +int wl12xx_cmd_role_start_dev(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id); + + cmd->role_id = wl->dev_role_id; + if (wl->band == IEEE80211_BAND_5GHZ) + cmd->band = WL12XX_BAND_5GHZ; + cmd->channel = wl->channel; + + if (wl->dev_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, &wl->dev_hlid); + if (ret) + goto out_free; + } + cmd->device.hlid = wl->dev_hlid; + cmd->device.session = wl->session_counter; + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", + cmd->role_id, cmd->device.hlid, cmd->device.session); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error */ + __clear_bit(wl->dev_hlid, wl->links_map); + wl->dev_hlid = WL12XX_INVALID_LINK_ID; + + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_stop_dev(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wl->dev_hlid == WL12XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop dev"); + + cmd->role_id = wl->dev_role_id; + cmd->disc_type = DISCONNECT_IMMEDIATE; + cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop"); + goto out_free; + } + + ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); + if (ret < 0) { + wl1271_error("cmd role stop dev event completion error"); + goto out_free; + } + + wl12xx_free_link(wl, &wl->dev_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + int wl12xx_cmd_role_start_sta(struct wl1271 *wl) { struct wl12xx_cmd_role_start *cmd; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3e77f59e3397..7b0b7c34ef76 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1866,6 +1866,20 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, if (ret < 0) goto power_off; + if (wl->bss_type == BSS_TYPE_STA_BSS) { + /* + * The device role is a special role used for + * rx and tx frames prior to association (as + * the STA role can get packets only from + * its associated bssid) + */ + ret = wl12xx_cmd_role_enable(wl, + WL1271_ROLE_DEVICE, + &wl->dev_role_id); + if (ret < 0) + goto irq_disable; + } + ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id); if (ret < 0) goto irq_disable; @@ -1965,6 +1979,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, if (ret < 0) goto deinit; + if (wl->bss_type == BSS_TYPE_STA_BSS) { + ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id); + if (ret < 0) + goto deinit; + } + ret = wl12xx_cmd_role_disable(wl, &wl->role_id); if (ret < 0) goto deinit; @@ -1973,6 +1993,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, } deinit: wl->sta_hlid = WL12XX_INVALID_LINK_ID; + wl->dev_hlid = WL12XX_INVALID_LINK_ID; /* * this must be before the cancel_work calls below, so that the work @@ -2023,6 +2044,7 @@ deinit: wl->ap_ps_map = 0; wl->sched_scanning = false; wl->role_id = WL12XX_INVALID_ROLE_ID; + wl->dev_role_id = WL12XX_INVALID_ROLE_ID; memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->links_map, 0, sizeof(wl->links_map)); @@ -4365,7 +4387,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->tx_security_last_seq_lsb = 0; wl->role_id = WL12XX_INVALID_ROLE_ID; wl->sta_hlid = WL12XX_INVALID_LINK_ID; - + wl->dev_role_id = WL12XX_INVALID_ROLE_ID; + wl->dev_hlid = WL12XX_INVALID_LINK_ID; setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, (unsigned long) wl); wl->fwlog_size = 0; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 3d43875163e1..ab46664969ec 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -394,6 +394,7 @@ struct wl1271 { u8 ssid_len; int channel; u8 role_id; + u8 dev_role_id; u8 sta_hlid; u8 dev_hlid; -- cgit v1.2.3 From a4e02f330a69a305c4f7bc98d56e72aa0d4b6032 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:10 +0300 Subject: wl12xx: update scan cmd api Update the scan command to use the new fw api (fw 6/7.3.0.0.75). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 8 +++++++- drivers/net/wireless/wl12xx/scan.h | 25 ++++++++++++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 78a9b23a41b8..54a4e75a37fe 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -156,6 +156,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, if (passive || wl->scan.req->n_ssids == 0) scan_options |= WL1271_SCAN_OPT_PASSIVE; + if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { + ret = -EINVAL; + goto out; + } + cmd->params.role_id = wl->role_id; cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, @@ -167,7 +172,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, } cmd->params.tx_rate = cpu_to_le32(basic_rate); - 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; @@ -183,6 +187,8 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); } + memcpy(cmd->addr, wl->mac_addr, ETH_ALEN); + ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, wl->scan.req->ie_len, band); diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index 0b2a2987439d..92115156522f 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h @@ -46,7 +46,10 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl); #define WL1271_SCAN_CURRENT_TX_PWR 0 #define WL1271_SCAN_OPT_ACTIVE 0 #define WL1271_SCAN_OPT_PASSIVE 1 +#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2 #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 +/* scan even if we fail to enter psm */ +#define WL1271_SCAN_OPT_FORCE 8 #define WL1271_SCAN_BAND_2_4_GHZ 0 #define WL1271_SCAN_BAND_5_GHZ 1 @@ -62,27 +65,27 @@ enum { }; struct basic_scan_params { - __le32 rx_config_options; - __le32 rx_filter_options; /* Scan option flags (WL1271_SCAN_OPT_*) */ __le16 scan_options; + u8 role_id; /* 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 use_ssid_list; + + /* Rate bit field for sending the probes */ + __le32 tx_rate; + u8 ssid[IEEE80211_MAX_SSID_LEN]; /* Band to scan */ u8 band; - u8 use_ssid_list; + u8 scan_tag; - u8 padding2; + u8 padding2[2]; } __packed; struct basic_scan_channel_params { @@ -105,6 +108,10 @@ struct wl1271_cmd_scan { struct basic_scan_params params; struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; + + /* src mac address */ + u8 addr[ETH_ALEN]; + u8 padding[2]; } __packed; struct wl1271_cmd_trigger_scan_to { @@ -184,7 +191,7 @@ struct wl1271_cmd_sched_scan_config { } __packed; -#define SCHED_SCAN_MAX_SSIDS 8 +#define SCHED_SCAN_MAX_SSIDS 16 enum { SCAN_SSID_TYPE_PUBLIC = 0, -- cgit v1.2.3 From 79b122dc51797b650201f21360481a0450e9b7e4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:11 +0300 Subject: wl12xx: update rx/tx Update the rx/tx descriptors according to the new fw api (fw >= 6/7.3.0.0.75) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/rx.h | 7 ++----- drivers/net/wireless/wl12xx/tx.c | 15 +++++++++++---- drivers/net/wireless/wl12xx/tx.h | 14 ++++---------- drivers/net/wireless/wl12xx/wl12xx.h | 2 +- 4 files changed, 18 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index 00c1c1d27aaa..86ba6b1d0cdc 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -86,7 +86,7 @@ * Bits 3-5 - process_id tag (AP mode FW) * Bits 6-7 - reserved */ -#define WL1271_RX_DESC_STATUS_MASK 0x07 +#define WL1271_RX_DESC_STATUS_MASK 0x03 #define WL1271_RX_DESC_SUCCESS 0x00 #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 @@ -121,10 +121,7 @@ struct wl1271_rx_descriptor { u8 snr; __le32 timestamp; u8 packet_class; - union { - u8 process_id; /* STA FW */ - u8 hlid; /* AP FW */ - } __packed; + u8 hlid; u8 pad_len; u8 reserved; } __packed; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index f4973366a88b..23ce7aaeb4c4 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -276,9 +276,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; } - if (wl->bss_type != BSS_TYPE_AP_BSS) { - desc->aid = hlid; + desc->hlid = hlid; + if (wl->bss_type != BSS_TYPE_AP_BSS) { /* if the packets are destined for AP (have a STA entry) send them with AP rate policies, otherwise use default basic rates */ @@ -287,7 +287,6 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else rate_idx = ACX_TX_BASIC_RATE; } else { - desc->hlid = hlid; switch (hlid) { case WL1271_AP_GLOBAL_HLID: rate_idx = ACX_TX_AP_MODE_MGMT_RATE; @@ -375,7 +374,15 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) hlid = wl1271_tx_get_hlid(skb); else - hlid = TX_HW_DEFAULT_AID; + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + hlid = wl->sta_hlid; + else + hlid = wl->dev_hlid; + + if (hlid == WL12XX_INVALID_LINK_ID) { + wl1271_error("invalid hlid. dropping skb 0x%p", skb); + return -EINVAL; + } ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 5d719b5a3d1d..b712d7b058a8 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -29,9 +29,6 @@ #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 #define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000 -/* 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) @@ -116,12 +113,8 @@ struct wl1271_tx_hw_descr { u8 id; /* The packet TID value (as User-Priority) */ u8 tid; - union { - /* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */ - u8 aid; - /* AP - host link ID (HLID) */ - u8 hlid; - } __packed; + /* host link ID (HLID) */ + u8 hlid; u8 reserved; } __packed; @@ -133,7 +126,8 @@ enum wl1271_tx_hw_res_status { TX_TIMEOUT = 4, TX_KEY_NOT_FOUND = 5, TX_PEER_NOT_FOUND = 6, - TX_SESSION_MISMATCH = 7 + TX_SESSION_MISMATCH = 7, + TX_LINK_NOT_VALID = 8, }; struct wl1271_tx_hw_res_descr { diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index ab46664969ec..93e689d1f46a 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -159,7 +159,7 @@ extern u32 wl12xx_debug_level; #define WL1271_AP_BSS_INDEX 0 #define WL1271_AP_DEF_BEACON_EXP 20 -#define ACX_TX_DESCRIPTORS 32 +#define ACX_TX_DESCRIPTORS 16 #define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) -- cgit v1.2.3 From 154037d1681caaff7d33521b84017ee58b396438 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:12 +0300 Subject: wl12xx: change max/default template size The max template size was increased in the new fw. However, we should use the max size only when needed, as it consumes some of the chip's memory. Thus, by default initialize the templates to the default size. Initialize to the maximum size only when required. Use WL1271_CMD_TEMPL_DFLT_SIZE instead of some of the predefined structs, as some of them didn't account for additional IEs that might be added to the template. Delete structs defintions not used after these changes. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.h | 3 ++- drivers/net/wireless/wl12xx/init.c | 18 +++++++----------- drivers/net/wireless/wl12xx/main.c | 2 +- drivers/net/wireless/wl12xx/wl12xx_80211.h | 25 ------------------------- 4 files changed, 10 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 16e0a877bf57..6950759172f0 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -172,7 +172,8 @@ enum cmd_templ { /* unit ms */ #define WL1271_COMMAND_TIMEOUT 2000 -#define WL1271_CMD_TEMPL_MAX_SIZE 252 +#define WL1271_CMD_TEMPL_DFLT_SIZE 252 +#define WL1271_CMD_TEMPL_MAX_SIZE 548 #define WL1271_EVENT_TIMEOUT 750 struct wl1271_cmd_header { diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 76e6f37b87ad..683c8d128551 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -39,13 +39,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, + WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, + NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -70,15 +70,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, - sizeof - (struct wl12xx_probe_resp_template), + WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template), + WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -92,7 +90,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) 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_CMD_TEMPL_DFLT_SIZE, i, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -191,15 +189,13 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl) * reserve memory for later. */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, - sizeof - (struct wl12xx_probe_resp_template), + WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template), + WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7b0b7c34ef76..1389c5cba343 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4266,7 +4266,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) * should be the maximum length possible for a template, without * the IEEE80211 header of the template */ - wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - + wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - sizeof(struct ieee80211_header); /* make sure all our channels fit in the scanned_ch bitmask */ diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index f334ea081722..f7971d3b0898 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -105,18 +105,6 @@ struct wl12xx_ie_country { /* Templates */ -struct wl12xx_beacon_template { - struct ieee80211_header header; - __le32 time_stamp[2]; - __le16 beacon_interval; - __le16 capability; - struct wl12xx_ie_ssid ssid; - struct wl12xx_ie_rates rates; - struct wl12xx_ie_rates ext_rates; - struct wl12xx_ie_ds_params ds_params; - struct wl12xx_ie_country country; -} __packed; - struct wl12xx_null_data_template { struct ieee80211_header header; } __packed; @@ -146,19 +134,6 @@ struct wl12xx_arp_rsp_template { __be32 target_ip; } __packed; - -struct wl12xx_probe_resp_template { - struct ieee80211_header header; - __le32 time_stamp[2]; - __le16 beacon_interval; - __le16 capability; - struct wl12xx_ie_ssid ssid; - struct wl12xx_ie_rates rates; - struct wl12xx_ie_rates ext_rates; - struct wl12xx_ie_ds_params ds_params; - struct wl12xx_ie_country country; -} __packed; - struct wl12xx_disconn_template { struct ieee80211_header header; __le16 disconn_reason; -- cgit v1.2.3 From f42bd2cbf1d5ff4b161ad2c59ff12d66558c8374 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:13 +0300 Subject: wl12xx: use wl1271_acx_beacon_filter_opt for both sta and ap Use ACX_BEACON_FILTER_OPT for both station and ap roles (use the generic wl1271_acx_beacon_filter_opt() instead of wl1271_acx_set_ap_beacon_filter() ). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 25 ------------------------- drivers/net/wireless/wl12xx/acx.h | 9 --------- drivers/net/wireless/wl12xx/init.c | 2 +- drivers/net/wireless/wl12xx/main.c | 4 ++-- 4 files changed, 3 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index dfb1cbb35acd..968d2197ac81 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1660,31 +1660,6 @@ out: return ret; } -int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable) -{ - struct acx_ap_beacon_filter *acx = NULL; - int ret; - - wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) - return -ENOMEM; - - acx->enable = enable ? 1 : 0; - - ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx set ap beacon filter failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - int wl1271_acx_fm_coex(struct wl1271 *wl) { struct wl1271_acx_fm_coex *acx; diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 67258a15de21..3aec410634e7 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1096,13 +1096,6 @@ struct wl1271_acx_inconnection_sta { u8 padding1[2]; } __packed; -struct acx_ap_beacon_filter { - struct acx_header header; - - u8 enable; - u8 pad[3]; -} __packed; - /* * ACX_FM_COEX_CFG * set the FM co-existence parameters. @@ -1177,7 +1170,6 @@ enum { ACX_TID_CFG = 0x001A, ACX_PS_RX_STREAMING = 0x001B, ACX_BEACON_FILTER_OPT = 0x001F, - ACX_AP_BEACON_FILTER_OPT = 0x0020, ACX_NOISE_HIST = 0x0021, ACX_HDK_VERSION = 0x0022, /* ??? */ ACX_PD_THRESHOLD = 0x0023, @@ -1301,7 +1293,6 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); -int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable); int wl1271_acx_fm_coex(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 683c8d128551..3a6660901c33 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -469,7 +469,7 @@ int wl1271_ap_init_templates(struct wl1271 *wl) * when operating as AP we want to receive external beacons for * configuring ERP protection. */ - ret = wl1271_acx_set_ap_beacon_filter(wl, false); + ret = wl1271_acx_beacon_filter_opt(wl, false); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 1389c5cba343..d683bca9b308 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1639,7 +1639,7 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl) if (ret < 0) goto out_unlock; - ret = wl1271_acx_set_ap_beacon_filter(wl, true); + ret = wl1271_acx_beacon_filter_opt(wl, true); wl1271_ps_elp_sleep(wl); out_unlock: @@ -1677,7 +1677,7 @@ static void wl1271_configure_resume(struct wl1271 *wl) wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, wl->basic_rate, true); } else if (is_ap) { - wl1271_acx_set_ap_beacon_filter(wl, false); + wl1271_acx_beacon_filter_opt(wl, false); } wl1271_ps_elp_sleep(wl); -- cgit v1.2.3 From fa6ad9f0f34b0754ce7551866b33587f077a2a51 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:14 +0300 Subject: wl12xx: add set_rate_mgmt_params acx Configure rate management parameters on hw init Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 42 ++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/acx.h | 25 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/conf.h | 20 ++++++++++++++++++ drivers/net/wireless/wl12xx/init.c | 4 ++++ drivers/net/wireless/wl12xx/main.c | 21 +++++++++++++++++++ 5 files changed, 112 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 968d2197ac81..a784ba6a8ef6 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1699,3 +1699,45 @@ out: kfree(acx); return ret; } + +int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) +{ + struct wl12xx_acx_set_rate_mgmt_params *acx = NULL; + struct conf_rate_policy_settings *conf = &wl->conf.rate; + int ret; + + wl1271_debug(DEBUG_ACX, "acx set rate mgmt params"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->index = ACX_RATE_MGMT_ALL_PARAMS; + acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score); + acx->per_add = cpu_to_le16(conf->per_add); + acx->per_th1 = cpu_to_le16(conf->per_th1); + acx->per_th2 = cpu_to_le16(conf->per_th2); + acx->max_per = cpu_to_le16(conf->max_per); + acx->inverse_curiosity_factor = conf->inverse_curiosity_factor; + acx->tx_fail_low_th = conf->tx_fail_low_th; + acx->tx_fail_high_th = conf->tx_fail_high_th; + acx->per_alpha_shift = conf->per_alpha_shift; + acx->per_add_shift = conf->per_add_shift; + acx->per_beta1_shift = conf->per_beta1_shift; + acx->per_beta2_shift = conf->per_beta2_shift; + acx->rate_check_up = conf->rate_check_up; + acx->rate_check_down = conf->rate_check_down; + memcpy(acx->rate_retry_policy, conf->rate_retry_policy, + sizeof(acx->rate_retry_policy)); + + ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx set rate mgmt params failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 3aec410634e7..6909bc535a5d 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1155,6 +1155,30 @@ struct wl1271_acx_fm_coex { u8 swallow_clk_diff; } __packed; +#define ACX_RATE_MGMT_ALL_PARAMS 0xff +struct wl12xx_acx_set_rate_mgmt_params { + struct acx_header header; + + u8 index; /* 0xff to configure all params */ + u8 padding1; + __le16 rate_retry_score; + __le16 per_add; + __le16 per_th1; + __le16 per_th2; + __le16 max_per; + u8 inverse_curiosity_factor; + u8 tx_fail_low_th; + u8 tx_fail_high_th; + u8 per_alpha_shift; + u8 per_add_shift; + u8 per_beta1_shift; + u8 per_beta2_shift; + u8 rate_check_up; + u8 rate_check_down; + u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; + u8 padding2[2]; +} __packed; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1294,5 +1318,6 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_fm_coex(struct wl1271 *wl); +int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 6080e01d92c6..30ee7d304bcc 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1309,6 +1309,25 @@ struct conf_fwlog { u8 threshold; }; +#define ACX_RATE_MGMT_NUM_OF_RATES 13 +struct conf_rate_policy_settings { + u16 rate_retry_score; + u16 per_add; + u16 per_th1; + u16 per_th2; + u16 max_per; + u8 inverse_curiosity_factor; + u8 tx_fail_low_th; + u8 tx_fail_high_th; + u8 per_alpha_shift; + u8 per_add_shift; + u8 per_beta1_shift; + u8 per_beta2_shift; + u8 rate_check_up; + u8 rate_check_down; + u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1326,6 +1345,7 @@ struct conf_drv_settings { struct conf_fm_coex fm_coex; struct conf_rx_streaming_settings rx_streaming; struct conf_fwlog fwlog; + struct conf_rate_policy_settings rate; u8 hci_io_ds; }; diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 3a6660901c33..1bc246f42a65 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -715,6 +715,10 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + ret = wl12xx_acx_set_rate_mgmt_params(wl); + if (ret < 0) + goto out_free_memmap; + /* Configure initiator BA sessions policies */ ret = wl1271_set_ba_policies(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index d683bca9b308..3db191de3f51 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -379,6 +379,27 @@ static struct conf_drv_settings default_conf = { .threshold = 0, }, .hci_io_ds = HCI_IO_DS_6MA, + .rate = { + .rate_retry_score = 32000, + .per_add = 8192, + .per_th1 = 2048, + .per_th2 = 4096, + .max_per = 8100, + .inverse_curiosity_factor = 5, + .tx_fail_low_th = 4, + .tx_fail_high_th = 10, + .per_alpha_shift = 4, + .per_add_shift = 13, + .per_beta1_shift = 10, + .per_beta2_shift = 8, + .rate_check_up = 2, + .rate_check_down = 12, + .rate_retry_policy = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + }, + }, }; static char *fwlog_param; -- cgit v1.2.3 From f4df1bd525e027aa1975e00f87a420aec7bef4e0 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:15 +0300 Subject: wl12xx: add system_hlid system_hlid is a const hlid (always 0), used by the fw and driver for packets which are not bound to specific role (e.g. dynamic memory packets). indicate it as always allocated. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 9 +++++++- drivers/net/wireless/wl12xx/tx.c | 40 ++++++++++++++++++++++-------------- drivers/net/wireless/wl12xx/tx.h | 2 +- drivers/net/wireless/wl12xx/wl12xx.h | 2 ++ 4 files changed, 36 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3db191de3f51..e4081e222184 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1491,7 +1491,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) q = wl1271_tx_get_queue(mapping); if (wl->bss_type == BSS_TYPE_AP_BSS) - hlid = wl1271_tx_get_hlid(skb); + hlid = wl12xx_tx_get_hlid_ap(wl, skb); spin_lock_irqsave(&wl->wl_lock, flags); @@ -2069,6 +2069,9 @@ deinit: memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->links_map, 0, sizeof(wl->links_map)); + /* The system link is always allocated */ + __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); + /* * this is performed after the cancel_work calls and the associated * mutex_lock, so that wl1271_op_add_interface does not accidentally @@ -4407,6 +4410,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->tx_security_seq = 0; wl->tx_security_last_seq_lsb = 0; wl->role_id = WL12XX_INVALID_ROLE_ID; + wl->system_hlid = WL12XX_SYSTEM_HLID; wl->sta_hlid = WL12XX_INVALID_LINK_ID; wl->dev_role_id = WL12XX_INVALID_ROLE_ID; wl->dev_hlid = WL12XX_INVALID_LINK_ID; @@ -4415,6 +4419,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->fwlog_size = 0; init_waitqueue_head(&wl->fwlog_waitq); + /* The system link is always allocated */ + __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); + memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 23ce7aaeb4c4..ffdaf97854cb 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -132,7 +132,12 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) } #endif -u8 wl1271_tx_get_hlid(struct sk_buff *skb) +static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +{ + return wl->dummy_packet == skb; +} + +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) { struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); @@ -145,6 +150,9 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb) } else { struct ieee80211_hdr *hdr; + if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) + return wl->system_hlid; + hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_mgmt(hdr->frame_control)) return WL1271_AP_GLOBAL_HLID; @@ -153,6 +161,20 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb) } } +static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) +{ + if (wl12xx_is_dummy_packet(wl, skb)) + return wl->system_hlid; + + if (wl->bss_type == BSS_TYPE_AP_BSS) + return wl12xx_tx_get_hlid_ap(wl, skb); + + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + return wl->sta_hlid; + else + return wl->dev_hlid; +} + static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, unsigned int packet_length) { @@ -221,11 +243,6 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return ret; } -static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) -{ - return wl->dummy_packet == skb; -} - static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control, u8 hlid) @@ -371,14 +388,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, } } - if (wl->bss_type == BSS_TYPE_AP_BSS) - hlid = wl1271_tx_get_hlid(skb); - else - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - hlid = wl->sta_hlid; - else - hlid = wl->dev_hlid; - + hlid = wl1271_tx_get_hlid(wl, skb); if (hlid == WL12XX_INVALID_LINK_ID) { wl1271_error("invalid hlid. dropping skb 0x%p", skb); return -EINVAL; @@ -564,7 +574,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) if (wl12xx_is_dummy_packet(wl, skb)) { set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); } else if (wl->bss_type == BSS_TYPE_AP_BSS) { - u8 hlid = wl1271_tx_get_hlid(skb); + u8 hlid = wl1271_tx_get_hlid(wl, skb); skb_queue_head(&wl->links[hlid].tx_queue[q], skb); /* make sure we dequeue the same packet next time */ diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index b712d7b058a8..7da35c0e411b 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -210,7 +210,7 @@ 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); u32 wl1271_tx_min_rate_get(struct wl1271 *wl); -u8 wl1271_tx_get_hlid(struct sk_buff *skb); +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb); void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 93e689d1f46a..089304d874d5 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -141,6 +141,7 @@ extern u32 wl12xx_debug_level; #define WL12XX_MAX_LINKS 8 #define WL12XX_INVALID_ROLE_ID 0xff #define WL12XX_INVALID_LINK_ID 0xff +#define WL12XX_SYSTEM_HLID 0 #define WL1271_AP_GLOBAL_HLID 0 #define WL1271_AP_BROADCAST_HLID 1 #define WL1271_AP_STA_HLID_START 2 @@ -395,6 +396,7 @@ struct wl1271 { int channel; u8 role_id; u8 dev_role_id; + u8 system_hlid; u8 sta_hlid; u8 dev_hlid; -- cgit v1.2.3 From a7cba38471bd457db8c536c94073673f41ef66f4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:16 +0300 Subject: wl12xx: add ROC/CROC commands Add structs and functions to support the ROC/CROC commands. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 73 +++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/cmd.h | 16 +++++++++ 2 files changed, 89 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index e29343ed6ea2..1b04102144e6 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1481,3 +1481,76 @@ out_free: out: return ret; } + +static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id) +{ + struct wl12xx_cmd_roc *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id); + + if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = role_id; + cmd->channel = wl->channel; + switch (wl->band) { + case IEEE80211_BAND_2GHZ: + cmd->band = RADIO_BAND_2_4GHZ; + break; + case IEEE80211_BAND_5GHZ: + cmd->band = RADIO_BAND_5GHZ; + break; + default: + wl1271_error("roc - unknown band: %d", (int)wl->band); + ret = -EINVAL; + goto out_free; + } + + + ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send ROC command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) +{ + struct wl12xx_cmd_croc *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + cmd->role_id = role_id; + + ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send ROC 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 index 6950759172f0..80b02ed0e3f2 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -565,6 +565,22 @@ struct wl12xx_cmd_set_peer_state { u8 padding[2]; } __packed; +struct wl12xx_cmd_roc { + struct wl1271_cmd_header header; + + u8 role_id; + u8 channel; + u8 band; + u8 padding; +}; + +struct wl12xx_cmd_croc { + struct wl1271_cmd_header header; + + u8 role_id; + u8 padding[3]; +}; + enum wl12xx_ssid_type { WL12XX_SSID_TYPE_PUBLIC = 0, WL12XX_SSID_TYPE_HIDDEN = 1, -- cgit v1.2.3 From 79ebec76be4e7c2ebed9fb0b9510d10d599ed63e Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:18 +0300 Subject: wl12xx: handle dummy packet event also in ap mode Allow handling of DUMMY_PACKET_EVENT_ID also in ap mode. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/event.c | 2 +- drivers/net/wireless/wl12xx/tx.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 431ceae6c1c8..0bd7b020a420 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -291,7 +291,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_stop_ba_event(wl, mbox->rx_ba_allowed); } - if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { + if ((vector & DUMMY_PACKET_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) wl1271_tx_dummy_packet(wl); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index ffdaf97854cb..a2dbbadd58f0 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -821,10 +821,14 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) total[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status_ni(wl->hw, skb); + + if (!wl12xx_is_dummy_packet(wl, skb)) { + info = IEEE80211_SKB_CB(skb); + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + ieee80211_tx_status_ni(wl->hw, skb); + } + total[i]++; } } -- cgit v1.2.3 From 251c177f886027fbce494202e44935762f103137 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:17 +0300 Subject: wl12xx: replace dummy_join with ROC/CROC commands The ROC command asks the fw stay on the channel of the given hlid. it currently has 2 primary functions: 1. Allow tx/rx from the device role. In order to tx/rx packets while the stations is not associated (e.g. auth req/resp), the device role has to be used, along with ROC on its link. Keep the logic similiar to the one used in dummy_join. However, since we can't scan while we ROC, we add CROC before starting a scan, and ROC again (if needed) on scan complete. 2. Keeping the antenna for a specific link. We ROC until the connection was completed (after EAPOLs exchange) in order to prevent BT coex operations from taking the antenna and failing the connection (after this stage, psm can be used). During association, we ROC on the station role, and then CROC the device role, thus assuring being ROC during all the connection process. Delete the WL1271_FLAG_JOINED flag, and use a roc bitmap to indicate what roles are currently ROCed. Add wl12xx_roc/croc functions in order to wrap the roc/croc commands while taking care of the roc bitmap. The current ROC/CROC state-machine is a bit complicated. In the future we'll probably want to use wpa_supplicant to control the ROC during connection. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 39 ++++++++++ drivers/net/wireless/wl12xx/cmd.h | 2 + drivers/net/wireless/wl12xx/main.c | 144 +++++++++++++++++++++++++++-------- drivers/net/wireless/wl12xx/scan.c | 20 +++-- drivers/net/wireless/wl12xx/tx.c | 13 ++++ drivers/net/wireless/wl12xx/wl12xx.h | 2 +- 6 files changed, 182 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 1b04102144e6..c620a9d4939c 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1554,3 +1554,42 @@ out_free: out: return ret; } + +int wl12xx_roc(struct wl1271 *wl, u8 role_id) +{ + int ret = 0; + + if (WARN_ON(test_bit(role_id, wl->roc_map))) + return 0; + + ret = wl12xx_cmd_roc(wl, role_id); + if (ret < 0) + goto out; + + ret = wl1271_cmd_wait_for_event(wl, + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); + if (ret < 0) { + wl1271_error("cmd roc event completion error"); + goto out; + } + + __set_bit(role_id, wl->roc_map); +out: + return ret; +} + +int wl12xx_croc(struct wl1271 *wl, u8 role_id) +{ + int ret = 0; + + if (WARN_ON(!test_bit(role_id, wl->roc_map))) + return 0; + + ret = wl12xx_cmd_croc(wl, role_id); + if (ret < 0) + goto out; + + __clear_bit(role_id, wl->roc_map); +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 80b02ed0e3f2..5cf92e256641 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -71,6 +71,8 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16); int wl12xx_cmd_set_peer_state(struct wl1271 *wl); +int wl12xx_roc(struct wl1271 *wl, u8 role_id); +int wl12xx_croc(struct wl1271 *wl, u8 role_id); int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e4081e222184..57b10e98730e 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -440,6 +440,8 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate) if (ret < 0) return ret; + wl12xx_croc(wl, wl->role_id); + wl1271_info("Association completed."); return 0; } @@ -2068,6 +2070,7 @@ deinit: wl->dev_role_id = WL12XX_INVALID_ROLE_ID; memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->links_map, 0, sizeof(wl->links_map)); + memset(wl->roc_map, 0, sizeof(wl->roc_map)); /* The system link is always allocated */ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); @@ -2110,25 +2113,6 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, cancel_work_sync(&wl->recovery_work); } -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); - - ret = wl12xx_cmd_role_start_sta(wl); - 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; @@ -2152,8 +2136,6 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) if (ret < 0) goto out; - set_bit(WL1271_FLAG_JOINED, &wl->flags); - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) goto out; @@ -2193,7 +2175,6 @@ static int wl1271_unjoin(struct wl1271 *wl) if (ret < 0) goto out; - clear_bit(WL1271_FLAG_JOINED, &wl->flags); memset(wl->bssid, 0, ETH_ALEN); /* reset TX security counters on a clean disconnect */ @@ -2212,13 +2193,29 @@ static void wl1271_set_band_rate(struct wl1271 *wl) wl->basic_rate_set = wl->conf.tx.basic_rate_5; } +static bool wl12xx_is_roc(struct wl1271 *wl) +{ + u8 role_id; + + role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES); + if (role_id >= WL12XX_MAX_ROLES) + return false; + + return true; +} + static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) { int ret; if (idle) { - if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { - ret = wl1271_unjoin(wl); + /* no need to croc if we weren't busy (e.g. during boot) */ + if (wl12xx_is_roc(wl)) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_role_stop_dev(wl); if (ret < 0) goto out; } @@ -2244,7 +2241,11 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) ieee80211_sched_scan_stopped(wl->hw); } - ret = wl1271_dummy_join(wl); + ret = wl12xx_cmd_role_start_dev(wl); + if (ret < 0) + goto out; + + ret = wl12xx_roc(wl, wl->dev_role_id); if (ret < 0) goto out; clear_bit(WL1271_FLAG_IDLE, &wl->flags); @@ -2324,11 +2325,34 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl1271_warning("rate policy for channel " "failed %d", ret); - if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + if (wl12xx_is_roc(wl)) { + /* roaming */ + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out_sleep; + } ret = wl1271_join(wl, false); if (ret < 0) wl1271_warning("cmd join on channel " "failed %d", ret); + } else { + /* + * change the ROC channel. do it only if we are + * not idle. otherwise, CROC will be called + * anyway. + */ + if (wl12xx_is_roc(wl) && + !(conf->flags & IEEE80211_CONF_IDLE)) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out_sleep; + + ret = wl12xx_roc(wl, wl->dev_role_id); + if (ret < 0) + wl1271_warning("roc failed %d", + ret); + } } } } @@ -2784,10 +2808,20 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1271_scan(hw->priv, ssid, len, req); + /* cancel ROC before scanning */ + if (wl12xx_is_roc(wl)) { + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + /* don't allow scanning right now */ + ret = -EBUSY; + goto out_sleep; + } + wl12xx_croc(wl, wl->dev_role_id); + wl12xx_cmd_role_stop_dev(wl); + } + ret = wl1271_scan(hw->priv, ssid, len, req); +out_sleep: wl1271_ps_elp_sleep(wl); - out: mutex_unlock(&wl->mutex); @@ -3311,7 +3345,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, bool was_assoc = !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); - clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); + bool was_ifup = + !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT, + &wl->flags); wl->aid = 0; /* free probe-request template */ @@ -3338,8 +3374,32 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, /* restore the bssid filter and go to dummy bssid */ if (was_assoc) { + u32 conf_flags = wl->hw->conf.flags; + /* + * we might have to disable roc, if there was + * no IF_OPER_UP notification. + */ + if (!was_ifup) { + ret = wl12xx_croc(wl, wl->role_id); + if (ret < 0) + goto out; + } + /* + * (we also need to disable roc in case of + * roaming on the same channel. until we will + * have a better flow...) + */ + if (test_bit(wl->dev_role_id, wl->roc_map)) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out; + } + wl1271_unjoin(wl); - wl1271_dummy_join(wl); + if (!(conf_flags & IEEE80211_CONF_IDLE)) { + wl12xx_cmd_role_start_dev(wl); + wl12xx_roc(wl, wl->dev_role_id); + } } } } @@ -3400,7 +3460,29 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, wl1271_warning("cmd join failed %d", ret); goto out; } - wl1271_check_operstate(wl, ieee80211_get_operstate(vif)); + + /* ROC until connected (after EAPOL exchange) */ + if (!is_ibss) { + ret = wl12xx_roc(wl, wl->role_id); + if (ret < 0) + goto out; + + wl1271_check_operstate(wl, + ieee80211_get_operstate(vif)); + } + /* + * stop device role if started (we might already be in + * STA role). TODO: make it better. + */ + if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_role_stop_dev(wl); + if (ret < 0) + goto out; + } } out: diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 54a4e75a37fe..653091a38dce 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -33,6 +33,7 @@ void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); @@ -50,21 +51,28 @@ void wl1271_scan_complete_work(struct work_struct *work) wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, false); - /* restore hardware connection monitoring template */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { - if (wl1271_ps_elp_wakeup(wl) == 0) { - wl1271_cmd_build_ap_probe_req(wl, wl->probereq); - wl1271_ps_elp_sleep(wl); - } + /* restore hardware connection monitoring template */ + wl1271_cmd_build_ap_probe_req(wl, wl->probereq); + } else { + /* restore remain on channel */ + wl12xx_cmd_role_start_dev(wl); + wl12xx_roc(wl, wl->dev_role_id); } + wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } + ieee80211_scan_completed(wl->hw, false); + out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index a2dbbadd58f0..057db6f86bee 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -78,6 +78,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, struct sk_buff *skb) { struct ieee80211_hdr *hdr; + int ret; hdr = (struct ieee80211_hdr *)(skb->data + sizeof(struct wl1271_tx_hw_descr)); @@ -91,6 +92,18 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, if (!ieee80211_is_auth(hdr->frame_control)) return 0; + if (wl->dev_hlid != WL12XX_INVALID_LINK_ID) + goto out; + + wl1271_debug(DEBUG_CMD, "starting device role for roaming"); + ret = wl12xx_cmd_role_start_dev(wl); + if (ret < 0) + goto out; + + ret = wl12xx_roc(wl, wl->dev_role_id); + if (ret < 0) + goto out; +out: return 0; } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 089304d874d5..a136795352c8 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -319,7 +319,6 @@ struct wl1271_ap_key { enum wl12xx_flags { WL1271_FLAG_STA_ASSOCIATED, - WL1271_FLAG_JOINED, WL1271_FLAG_GPIO_POWER, WL1271_FLAG_TX_QUEUE_STOPPED, WL1271_FLAG_TX_PENDING, @@ -402,6 +401,7 @@ struct wl1271 { unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; + unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; struct wl1271_acx_mem_map *target_mem_map; -- cgit v1.2.3 From 3be4112cb2c53fcda85fb408aea9a6f94075683b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:19 +0300 Subject: wl12xx: update BT coex configuration params The BT coex params api have been changed. Update it, and init coex for both sta and ap. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 40 +---- drivers/net/wireless/wl12xx/acx.h | 16 +- drivers/net/wireless/wl12xx/conf.h | 318 +++++++++++++------------------------ drivers/net/wireless/wl12xx/init.c | 5 +- drivers/net/wireless/wl12xx/main.c | 165 +++++++------------ 5 files changed, 177 insertions(+), 367 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index a784ba6a8ef6..d783fce45613 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -528,13 +528,13 @@ out: return ret; } -int wl1271_acx_sta_sg_cfg(struct wl1271 *wl) +int wl12xx_acx_sg_cfg(struct wl1271 *wl) { - struct acx_sta_bt_wlan_coex_param *param; + struct acx_bt_wlan_coex_param *param; struct conf_sg_settings *c = &wl->conf.sg; int i, ret; - wl1271_debug(DEBUG_ACX, "acx sg sta cfg"); + wl1271_debug(DEBUG_ACX, "acx sg cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) { @@ -543,38 +543,8 @@ int wl1271_acx_sta_sg_cfg(struct wl1271 *wl) } /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->sta_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_ap_sg_cfg(struct wl1271 *wl) -{ - struct acx_ap_bt_wlan_coex_param *param; - struct conf_sg_settings *c = &wl->conf.sg; - int i, ret; - - wl1271_debug(DEBUG_ACX, "acx sg ap cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->ap_params[i]); + 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)); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 6909bc535a5d..5b3fabde0afe 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -302,23 +302,14 @@ struct acx_bt_wlan_coex { u8 pad[3]; } __packed; -struct acx_sta_bt_wlan_coex_param { +struct acx_bt_wlan_coex_param { struct acx_header header; - __le32 params[CONF_SG_STA_PARAMS_MAX]; + __le32 params[CONF_SG_PARAMS_MAX]; u8 param_idx; u8 padding[3]; } __packed; -struct acx_ap_bt_wlan_coex_param { - struct acx_header header; - - __le32 params[CONF_SG_AP_PARAMS_MAX]; - u8 param_idx; - u8 padding[3]; -} __packed; - - struct acx_dco_itrim_params { struct acx_header header; @@ -1269,8 +1260,7 @@ 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_sta_sg_cfg(struct wl1271 *wl); -int wl1271_acx_ap_sg_cfg(struct wl1271 *wl); +int wl12xx_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); diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 30ee7d304bcc..a7c147838ab8 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -99,40 +99,75 @@ enum { enum { /* - * PER threshold in PPM of the BT voice + * Configure the min and max time BT gains the antenna + * in WLAN / BT master basic rate * - * Range: 0 - 10000000 + * Range: 0 - 255 (ms) */ - CONF_SG_BT_PER_THRESHOLD = 0, + CONF_SG_ACL_BT_MASTER_MIN_BR = 0, + CONF_SG_ACL_BT_MASTER_MAX_BR, /* - * Number of consequent RX_ACTIVE activities to override BT voice - * frames to ensure WLAN connection + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave basic rate * - * Range: 0 - 100 + * Range: 0 - 255 (ms) */ - CONF_SG_HV3_MAX_OVERRIDE, + CONF_SG_ACL_BT_SLAVE_MIN_BR, + CONF_SG_ACL_BT_SLAVE_MAX_BR, /* - * Defines the PER threshold of the BT voice + * Configure the min and max time BT gains the antenna + * in WLAN / BT master EDR * - * Range: 0 - 65000 + * Range: 0 - 255 (ms) */ - CONF_SG_BT_NFS_SAMPLE_INTERVAL, + CONF_SG_ACL_BT_MASTER_MIN_EDR, + CONF_SG_ACL_BT_MASTER_MAX_EDR, /* - * Defines the load ratio of BT + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave EDR * - * Range: 0 - 100 (%) + * Range: 0 - 255 (ms) */ - CONF_SG_BT_LOAD_RATIO, + CONF_SG_ACL_BT_SLAVE_MIN_EDR, + CONF_SG_ACL_BT_SLAVE_MAX_EDR, /* - * Defines whether the SG will force WLAN host to enter/exit PSM + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave BR * - * Range: 1 - SG can force, 0 - host handles PSM + * Range: 0 - 255 (ms) */ - CONF_SG_AUTO_PS_MODE, + CONF_SG_ACL_WLAN_PS_MASTER_BR, + CONF_SG_ACL_WLAN_PS_SLAVE_BR, + + /* + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_WLAN_PS_MASTER_EDR, + CONF_SG_ACL_WLAN_PS_SLAVE_EDR, + + /* TODO: explain these values */ + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR, + + CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR, + CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR, + CONF_SG_ACL_PASSIVE_SCAN_BT_BR, + CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR, + CONF_SG_ACL_PASSIVE_SCAN_BT_EDR, + CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR, /* * Compensation percentage of probe requests when scan initiated @@ -151,102 +186,70 @@ enum { 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. + * Compensation percentage of WLAN active scan window if initiated + * during BT A2DP * - * Range: 0 + * Range: 0 - 1000 (%) */ - CONF_SG_RATE_ADAPT_SNR, + CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT master basic rate + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP BR * - * Range: 0 - 255 (ms) + * Range: 0 - 1000 (%) */ - CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR, - CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR, + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR, /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT master basic rate + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP EDR * - * Range: 0 - 255 (ms) + * Range: 0 - 1000 (%) */ - CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR, + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT slave basic rate + * Compensation percentage of WLAN passive scan window if initiated + * during BT voice * - * Range: 0 - 255 (ms) + * Range: 0 - 1000 (%) */ - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR, - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR, + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, - /* - * 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, + /* TODO: explain these values */ + CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, + CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN, + CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT master EDR + * Defines whether the SG will force WLAN host to enter/exit PSM * - * Range: 0 - 255 (ms) + * Range: 1 - SG can force, 0 - host handles PSM */ - CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR, - CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR, + CONF_SG_STA_FORCE_PS_IN_BT_SCO, /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT master EDR + * Defines antenna configuration (single/dual antenna) * - * Range: 0 - 255 (ms) + * Range: 0 - single antenna, 1 - dual antenna */ - CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR, + CONF_SG_ANTENNA_CONFIGURATION, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT slave EDR + * The threshold (percent) of max consecutive beacon misses before + * increasing priority of beacon reception. * - * Range: 0 - 255 (ms) + * Range: 0 - 100 (%) */ - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR, - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR, + CONF_SG_BEACON_MISS_PERCENT, /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT slave EDR + * Protection time of the DHCP procedure. * - * Range: 0 - 255 (ms) + * Range: 0 - 100000 (ms) */ - CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR, + CONF_SG_DHCP_TIME, /* * RX guard time before the beginning of a new BT voice frame during @@ -273,166 +276,59 @@ enum { */ 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, + /* TODO: explain this value */ + CONF_SG_GENERAL_USAGE_BIT_MAP, /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT slave EDR + * Number of consecutive BT voice frames not interrupted by WLAN * - * 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) + * Range: 0 - 100 */ - CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR, + CONF_SG_HV3_MAX_SERVED, /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT basic rate + * The used WLAN legacy service period during active BT ACL link * * Range: 0 - 255 (ms) */ - CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR, - CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR, + CONF_SG_PS_POLL_TIMEOUT, /* - * The maximum time WLAN can gain the antenna for - * in WLAN Active / BT basic rate + * The used WLAN UPSD service period during active BT ACL link * * 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, + CONF_SG_UPSD_TIMEOUT, - /* - * 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, + CONF_SG_CONSECUTIVE_CTS_THRESHOLD, + CONF_SG_STA_RX_WINDOW_AFTER_DTIM, + CONF_SG_STA_CONNECTION_PROTECTION_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, + /* AP params */ + CONF_AP_BEACON_MISS_TX, + CONF_AP_RX_WINDOW_AFTER_BEACON, + CONF_AP_BEACON_WINDOW_INTERVAL, + CONF_AP_CONNECTION_PROTECTION_TIME, + CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, + CONF_AP_BT_ACL_VAL_WL_SERVE_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, - - /* - * AP beacon miss - * - * Range: 0 - 255 - */ - CONF_SG_AP_BEACON_MISS_TX, - - /* - * AP RX window length - * - * Range: 0 - 50 - */ - CONF_SG_RX_WINDOW_LENGTH, - - /* - * AP connection protection time - * - * Range: 0 - 5000 - */ - CONF_SG_AP_CONNECTION_PROTECTION_TIME, - CONF_SG_TEMP_PARAM_6, CONF_SG_TEMP_PARAM_7, CONF_SG_TEMP_PARAM_8, CONF_SG_TEMP_PARAM_9, CONF_SG_TEMP_PARAM_10, - CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1, - CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1, - + CONF_SG_PARAMS_MAX, CONF_SG_PARAMS_ALL = 0xff }; struct conf_sg_settings { - u32 sta_params[CONF_SG_STA_PARAMS_MAX]; - u32 ap_params[CONF_SG_AP_PARAMS_MAX]; + u32 params[CONF_SG_PARAMS_MAX]; u8 state; }; @@ -913,7 +809,7 @@ struct conf_conn_settings { struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; /* - * The number of consequtive beacons to lose, before the firmware + * The number of consecutive beacons to lose, before the firmware * becomes out of synch. * * Range: u32 @@ -951,7 +847,7 @@ struct conf_conn_settings { u8 rx_broadcast_in_ps; /* - * Consequtive PS Poll failures before sending event to driver + * Consecutive PS Poll failures before sending event to driver * * Range: u8 */ diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 1bc246f42a65..47d87aaa63a7 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -277,10 +277,7 @@ int wl1271_init_pta(struct wl1271 *wl) { int ret; - if (wl->bss_type == BSS_TYPE_AP_BSS) - ret = wl1271_acx_ap_sg_cfg(wl); - else - ret = wl1271_acx_sta_sg_cfg(wl); + ret = wl12xx_acx_sg_cfg(wl); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 57b10e98730e..1774a6672314 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -52,110 +52,67 @@ static struct conf_drv_settings default_conf = { .sg = { - .sta_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] = 200, - [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, - }, - .ap_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] = 64, - [CONF_SG_RATE_ADAPT_SNR] = 1, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25, - [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] = 25, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25, - [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, - [CONF_SG_TEMP_PARAM_1] = 0, - [CONF_SG_TEMP_PARAM_2] = 0, - [CONF_SG_TEMP_PARAM_3] = 0, - [CONF_SG_TEMP_PARAM_4] = 0, - [CONF_SG_TEMP_PARAM_5] = 0, - [CONF_SG_AP_BEACON_MISS_TX] = 3, - [CONF_SG_RX_WINDOW_LENGTH] = 6, - [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50, - [CONF_SG_TEMP_PARAM_6] = 1, + .params = { + [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, + [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, + [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, + [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, + [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, + [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, + [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, + [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, + [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, + [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, + [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, + [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, + [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, + [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, + [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, + [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, + [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, + [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, + /* active scan params */ + [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, + /* passive scan params */ + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + /* passive scan in dual antenna params */ + [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, + [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, + [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, + /* general params */ + [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, + [CONF_SG_ANTENNA_CONFIGURATION] = 0, + [CONF_SG_BEACON_MISS_PERCENT] = 60, + [CONF_SG_DHCP_TIME] = 5000, + [CONF_SG_RXT] = 1200, + [CONF_SG_TXT] = 1000, + [CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, + [CONF_SG_HV3_MAX_SERVED] = 6, + [CONF_SG_PS_POLL_TIMEOUT] = 10, + [CONF_SG_UPSD_TIMEOUT] = 10, + [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, + [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, + [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, + /* AP params */ + [CONF_AP_BEACON_MISS_TX] = 3, + [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, + [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, + [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, + [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, + [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, }, .state = CONF_SG_PROTECTIVE, }, -- cgit v1.2.3 From 712e9bf750c5d0db63040c5695dacf38aed4f42c Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:20 +0300 Subject: wl12xx: fix session counter Increment the session counter on every wl12xx_cmd_role_start_sta() command. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 12 +++++++++++- drivers/net/wireless/wl12xx/main.c | 6 +----- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index c620a9d4939c..7c5d73845361 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -458,6 +458,16 @@ static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid) *hlid = WL12XX_INVALID_LINK_ID; } +static int wl12xx_get_new_session_id(struct wl1271 *wl) +{ + if (wl->session_counter >= SESSION_COUNTER_MAX) + wl->session_counter = 0; + + wl->session_counter++; + + return wl->session_counter; +} + int wl12xx_cmd_role_start_dev(struct wl1271 *wl) { struct wl12xx_cmd_role_start *cmd; @@ -580,7 +590,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl) goto out_free; } cmd->sta.hlid = wl->sta_hlid; - cmd->sta.session = wl->session_counter; + cmd->sta.session = wl12xx_get_new_session_id(wl); cmd->sta.remote_rates = cpu_to_le32(wl->rate_set); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 1774a6672314..157c46237d9f 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2187,11 +2187,6 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) 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; - /* The current firmware only supports sched_scan in idle */ if (wl->sched_scanning) { wl1271_scan_sched_scan_stop(wl); @@ -4453,6 +4448,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->sta_hlid = WL12XX_INVALID_LINK_ID; wl->dev_role_id = WL12XX_INVALID_ROLE_ID; wl->dev_hlid = WL12XX_INVALID_LINK_ID; + wl->session_counter = 0; setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, (unsigned long) wl); wl->fwlog_size = 0; -- cgit v1.2.3 From e51ae9be2e313b63a43f1f93578d9a71d38a77ea Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:21 +0300 Subject: wl12xx: use dynamic hlids for AP-mode Using hlid=0 in AP mode is a bug. Dynamically allocate HLIDs. Set the "first sta hlid" as 3. This will have to be changed when multiple vifs will be supported. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 27 +++++++++++++++++++++++---- drivers/net/wireless/wl12xx/main.c | 9 +++++++-- drivers/net/wireless/wl12xx/tx.c | 17 ++++++----------- drivers/net/wireless/wl12xx/wl12xx.h | 13 ++++++++++--- 4 files changed, 46 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 7c5d73845361..025fb14184d6 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -682,11 +682,19 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) goto out; } + ret = wl12xx_allocate_link(wl, &wl->ap_global_hlid); + if (ret < 0) + goto out_free; + + ret = wl12xx_allocate_link(wl, &wl->ap_bcast_hlid); + if (ret < 0) + goto out_free_global; + cmd->role_id = wl->role_id; cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->ap.bss_index = WL1271_AP_BSS_INDEX; - cmd->ap.global_hlid = WL1271_AP_GLOBAL_HLID; - cmd->ap.broadcast_hlid = WL1271_AP_BROADCAST_HLID; + cmd->ap.global_hlid = wl->ap_global_hlid; + cmd->ap.broadcast_hlid = wl->ap_bcast_hlid; cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set); cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int); cmd->ap.dtim_interval = bss_conf->dtim_period; @@ -713,9 +721,17 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd role start ap"); - goto out_free; + goto out_free_bcast; } + goto out_free; + +out_free_bcast: + wl12xx_free_link(wl, &wl->ap_bcast_hlid); + +out_free_global: + wl12xx_free_link(wl, &wl->ap_global_hlid); + out_free: kfree(cmd); @@ -744,6 +760,9 @@ int wl12xx_cmd_role_stop_ap(struct wl1271 *wl) goto out_free; } + wl12xx_free_link(wl, &wl->ap_bcast_hlid); + wl12xx_free_link(wl, &wl->ap_global_hlid); + out_free: kfree(cmd); @@ -1253,7 +1272,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, if (!cmd) return -ENOMEM; - if (hlid == WL1271_AP_BROADCAST_HLID) { + if (hlid == wl->ap_bcast_hlid) { if (key_type == KEY_WEP) lid_type = WEP_DEFAULT_LID_TYPE; else diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 157c46237d9f..ea150b5ff9f5 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1972,8 +1972,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl1271_ps_elp_sleep(wl); } deinit: + /* clear all hlids (except system_hlid) */ wl->sta_hlid = WL12XX_INVALID_LINK_ID; wl->dev_hlid = WL12XX_INVALID_LINK_ID; + wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; + wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; /* * this must be before the cancel_work calls below, so that the work @@ -2538,7 +2541,7 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl) if (wep_key_added) { ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key, - WL1271_AP_BROADCAST_HLID); + wl->ap_bcast_hlid); if (ret < 0) goto out; } @@ -2563,7 +2566,7 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, wl_sta = (struct wl1271_station *)sta->drv_priv; hlid = wl_sta->hlid; } else { - hlid = WL1271_AP_BROADCAST_HLID; + hlid = wl->ap_bcast_hlid; } if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { @@ -4449,6 +4452,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->dev_role_id = WL12XX_INVALID_ROLE_ID; wl->dev_hlid = WL12XX_INVALID_LINK_ID; wl->session_counter = 0; + wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; + wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, (unsigned long) wl); wl->fwlog_size = 0; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 057db6f86bee..1240f4094a8b 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -38,7 +38,7 @@ static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) if (is_ap) ret = wl12xx_cmd_set_default_wep_key(wl, id, - WL1271_AP_BROADCAST_HLID); + wl->ap_bcast_hlid); else ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid); @@ -168,9 +168,9 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_mgmt(hdr->frame_control)) - return WL1271_AP_GLOBAL_HLID; + return wl->ap_global_hlid; else - return WL1271_AP_BROADCAST_HLID; + return wl->ap_bcast_hlid; } } @@ -317,17 +317,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else rate_idx = ACX_TX_BASIC_RATE; } else { - switch (hlid) { - case WL1271_AP_GLOBAL_HLID: + if (hlid == wl->ap_global_hlid) rate_idx = ACX_TX_AP_MODE_MGMT_RATE; - break; - case WL1271_AP_BROADCAST_HLID: + else if (hlid == wl->ap_bcast_hlid) rate_idx = ACX_TX_AP_MODE_BCST_RATE; - break; - default: + else rate_idx = ac; - break; - } } tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index a136795352c8..1313dc5b855e 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -141,10 +141,15 @@ extern u32 wl12xx_debug_level; #define WL12XX_MAX_LINKS 8 #define WL12XX_INVALID_ROLE_ID 0xff #define WL12XX_INVALID_LINK_ID 0xff + +/* Defined by FW as 0. Will not be freed or allocated. */ #define WL12XX_SYSTEM_HLID 0 -#define WL1271_AP_GLOBAL_HLID 0 -#define WL1271_AP_BROADCAST_HLID 1 -#define WL1271_AP_STA_HLID_START 2 + +/* + * TODO: we currently don't support multirole. remove + * this constant from the code when we do. + */ +#define WL1271_AP_STA_HLID_START 3 /* * When in AP-mode, we allow (at least) this number of mem-blocks @@ -398,6 +403,8 @@ struct wl1271 { u8 system_hlid; u8 sta_hlid; u8 dev_hlid; + u8 ap_global_hlid; + u8 ap_bcast_hlid; unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; -- cgit v1.2.3 From 0f9c8250e10a16f48f82ffda3a5a7cb9e7b4a9ee Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 17 Aug 2011 10:45:49 +0300 Subject: wl12xx: re-enable block ack session support Incorporate interface changes for HT support. Add ba_bitmap field to the wl1271_link struct, to indicate activate RX BA sessions (for AP mode). Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 66 ++++++---------- drivers/net/wireless/wl12xx/acx.h | 82 +++++++------------- drivers/net/wireless/wl12xx/cmd.h | 1 + drivers/net/wireless/wl12xx/conf.h | 9 ++- drivers/net/wireless/wl12xx/init.c | 37 +++------ drivers/net/wireless/wl12xx/main.c | 146 ++++++++++++++++++++++++----------- drivers/net/wireless/wl12xx/wl12xx.h | 6 ++ 7 files changed, 177 insertions(+), 170 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index d783fce45613..ecbceb6f1ea9 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1323,19 +1323,15 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, goto out; } - /* Allow HT Operation ? */ if (allow_ht_operation) { - ht_capabilites = - WL1271_ACX_FW_CAP_HT_OPERATION; - if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) - ht_capabilites |= - WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; - if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) - ht_capabilites |= - WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; - if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) - ht_capabilites |= - WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; + /* no need to translate capabilities - use the spec values */ + ht_capabilites = ht_cap->cap; + + /* + * this bit is not employed by the spec but only by FW to + * indicate peer HT support + */ + ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; /* get data from A-MPDU parameters field */ acx->ampdu_max_length = ht_cap->ampdu_factor; @@ -1392,14 +1388,12 @@ out: } /* 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) +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl) { - struct wl1271_acx_ba_session_policy *acx; + struct wl1271_acx_ba_initiator_policy *acx; int ret; - wl1271_debug(DEBUG_ACX, "acx ba session setting"); + wl1271_debug(DEBUG_ACX, "acx ba initiator policy"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -1407,33 +1401,18 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl, 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; - } + /* set for the current role */ + acx->role_id = wl->role_id; + acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; + acx->win_size = wl->conf.ht.tx_ba_win_size; + acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; ret = wl1271_cmd_configure(wl, - ACX_BA_SESSION_POLICY_CFG, + ACX_BA_SESSION_INIT_POLICY, acx, sizeof(*acx)); if (ret < 0) { - wl1271_warning("acx ba session setting failed: %d", ret); + wl1271_warning("acx ba initiator policy failed: %d", ret); goto out; } @@ -1443,8 +1422,8 @@ out: } /* setup BA session receiver setting in the FW. */ -int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, - bool enable) +int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, + u16 ssn, bool enable, u8 peer_hlid) { struct wl1271_acx_ba_receiver_setup *acx; int ret; @@ -1457,11 +1436,10 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, goto out; } - /* Single link for now */ - acx->link_id = 1; + acx->hlid = peer_hlid; acx->tid = tid_index; acx->enable = enable; - acx->win_size = 0; + acx->win_size = wl->conf.ht.rx_ba_win_size; acx->ssn = ssn; ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 5b3fabde0afe..82c9271b4e84 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -899,6 +899,10 @@ struct wl1271_acx_rssi_snr_avg_weights { u8 snr_data; }; + +/* special capability bit (not employed by the 802.11n spec) */ +#define WL12XX_HT_CAP_HT_OPERATION BIT(16) + /* * ACX_PEER_HT_CAP * Configure HT capabilities - declare the capabilities of the peer @@ -907,19 +911,7 @@ struct wl1271_acx_rssi_snr_avg_weights { 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. - */ + /* bitmask of capability bits supported by the peer */ __le32 ht_capabilites; /* Indicates to which link these capabilities apply. */ @@ -937,15 +929,6 @@ struct wl1271_acx_ht_capabilities { u8 padding; } __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. @@ -979,57 +962,48 @@ struct wl1271_acx_ht_information { u8 padding[2]; } __packed; -#define RX_BA_WIN_SIZE 8 +#define RX_BA_MAX_SESSIONS 2 -struct wl1271_acx_ba_session_policy { +struct wl1271_acx_ba_initiator_policy { struct acx_header header; - /* - * Specifies role Id, Range 0-7, 0xFF means ANY role. - * Future use. For now this field is irrelevant - */ + + /* Specifies role Id, Range 0-7, 0xFF means ANY role. */ u8 role_id; + /* - * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id. - * Not applicable if Role Id is set to ANY. + * Per TID setting for allowing TX BA. Set a bit to 1 to allow + * TX BA sessions for the corresponding TID. */ - u8 link_id; - - u8 tid; - - u8 enable; + u8 tid_bitmap; /* Windows size in number of packets */ - u16 win_size; + u8 win_size; - /* - * As initiator inactivity timeout in time units(TU) of 1024us. - * As receiver reserved - */ - u16 inactivity_timeout; + u8 padding1[1]; - /* Initiator = 1/Receiver = 0 */ - u8 ba_direction; + /* As initiator inactivity timeout in time units(TU) of 1024us */ + u16 inactivity_timeout; - u8 padding[3]; + u8 padding[2]; } __packed; struct wl1271_acx_ba_receiver_setup { struct acx_header header; - /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */ - u8 link_id; + /* Specifies link id, range 0-31 */ + u8 hlid; u8 tid; u8 enable; - u8 padding[1]; - /* Windows size in number of packets */ - u16 win_size; + u8 win_size; /* BA session starting sequence number. RANGE 0-FFF */ u16 ssn; + + u8 padding[2]; } __packed; struct wl1271_acx_fw_tsf_information { @@ -1218,7 +1192,7 @@ enum { ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_KEEP_ALIVE_MODE = 0x0053, ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, - ACX_BA_SESSION_POLICY_CFG = 0x0055, + ACX_BA_SESSION_INIT_POLICY = 0x0055, ACX_BA_SESSION_RX_SETUP = 0x0056, ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, @@ -1297,11 +1271,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_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, - bool enable); +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl); +int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, + u16 ssn, bool enable, u8 peer_hlid); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 5cf92e256641..8b32a57e1cc6 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -208,6 +208,7 @@ enum { CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ CMD_STATUS_TEMPLATE_OOM = 23, + CMD_STATUS_NO_RX_BA_SESSION = 24, MAX_COMMAND_STATUS = 0xff }; diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index a7c147838ab8..76b5c6233da4 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -557,6 +557,9 @@ struct conf_tx_ac_category { #define CONF_TX_MAX_TID_COUNT 8 +/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */ +#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F + enum { CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ @@ -1095,8 +1098,12 @@ struct conf_rf_settings { }; struct conf_ht_setting { - u16 tx_ba_win_size; + u8 rx_ba_win_size; + u8 tx_ba_win_size; u16 inactivity_timeout; + + /* bitmap of enabled TIDs for TX BA sessions */ + u8 tx_ba_tid_bitmap; }; struct conf_memory_settings { diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 47d87aaa63a7..a374c2112be3 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -529,41 +529,24 @@ int wl1271_init_ap_rates(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; - int ret = 0; - /* Reset the BA RX indicators */ wl->ba_rx_bitmap = 0; wl->ba_allowed = true; + wl->ba_rx_session_count = 0; - /* validate that FW support BA */ - wl1271_check_ba_support(wl); + /* BA is supported in STA/AP modes */ + if (wl->bss_type != BSS_TYPE_AP_BSS && + wl->bss_type != BSS_TYPE_STA_BSS) { + wl->ba_support = false; + return 0; + } - 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; - } + wl->ba_support = true; - return ret; + /* 802.11n initiator BA session setting */ + return wl12xx_acx_set_ba_initiator_policy(wl); } int wl1271_chip_specific_init(struct wl1271 *wl) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index ea150b5ff9f5..934f5731fd73 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -286,8 +286,10 @@ static struct conf_drv_settings default_conf = { }, }, .ht = { + .rx_ba_win_size = 8, .tx_ba_win_size = 64, .inactivity_timeout = 10000, + .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, }, .mem_wl127x = { .num_stations = 1, @@ -3191,9 +3193,12 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } } - rcu_read_lock(); - sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (sta) { + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (!sta) + goto sta_not_found; + /* save the supp_rates of the ap */ sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; if (sta->ht_cap.ht_supported) @@ -3201,38 +3206,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); sta_ht_cap = sta->ht_cap; sta_exists = true; - } - rcu_read_unlock(); - if (sta_exists) { - /* handle new association with HT and HT information change */ - if ((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; - } - 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; - } - } - /* handle new association without HT and disassociation */ - else if (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; - } - } +sta_not_found: + rcu_read_unlock(); } if ((changed & BSS_CHANGED_ASSOC)) { @@ -3440,6 +3416,41 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } } + /* Handle new association with HT. Do this only after join. */ + if (sta_exists) { + if ((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; + } + } + /* handle new association without HT and disassociation */ + else if (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; + } + } + } + + /* Handle HT information change. Only after join. */ + if (sta_exists && (changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + 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; + } + } + out: return; } @@ -3623,6 +3634,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) __clear_bit(id, wl->ap_hlid_map); memset(wl->links[hlid].addr, 0, ETH_ALEN); + wl->links[hlid].ba_bitmap = 0; wl1271_tx_reset_link_queues(wl, hlid); __clear_bit(hlid, &wl->ap_ps_map); __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); @@ -3725,6 +3737,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, { struct wl1271 *wl = hw->priv; int ret; + u8 hlid, *ba_bitmap; + + wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, + tid); + + /* sanity check - the fields in FW are only 8bits wide */ + if (WARN_ON(tid > 0xFF)) + return -ENOTSUPP; mutex_lock(&wl->mutex); @@ -3733,6 +3753,20 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, goto out; } + if (wl->bss_type == BSS_TYPE_STA_BSS) { + hlid = wl->sta_hlid; + ba_bitmap = &wl->ba_rx_bitmap; + } else if (wl->bss_type == BSS_TYPE_AP_BSS) { + struct wl1271_station *wl_sta; + + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + ba_bitmap = &wl->links[hlid].ba_bitmap; + } else { + ret = -EINVAL; + goto out; + } + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -3742,20 +3776,46 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - if ((wl->ba_support) && (wl->ba_allowed)) { - ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn, - true); - if (!ret) - wl->ba_rx_bitmap |= BIT(tid); - } else { + if (!wl->ba_support || !wl->ba_allowed) { ret = -ENOTSUPP; + break; + } + + if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) { + ret = -EBUSY; + wl1271_error("exceeded max RX BA sessions"); + break; + } + + if (*ba_bitmap & BIT(tid)) { + ret = -EINVAL; + wl1271_error("cannot enable RX BA session on active " + "tid: %d", tid); + break; + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true, + hlid); + if (!ret) { + *ba_bitmap |= BIT(tid); + wl->ba_rx_session_count++; } break; case IEEE80211_AMPDU_RX_STOP: - ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false); - if (!ret) - wl->ba_rx_bitmap &= ~BIT(tid); + if (!(*ba_bitmap & BIT(tid))) { + ret = -EINVAL; + wl1271_error("no active RX BA session on tid: %d", + tid); + break; + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false, + hlid); + if (!ret) { + *ba_bitmap &= ~BIT(tid); + wl->ba_rx_session_count--; + } break; /* diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 1313dc5b855e..487c3c7e0273 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -355,6 +355,9 @@ struct wl1271_link { u8 prev_freed_blks; u8 addr[ETH_ALEN]; + + /* bitmap of TIDs where RX BA sessions are active for this link */ + u8 ba_bitmap; }; struct wl1271 { @@ -609,6 +612,9 @@ struct wl1271 { /* Platform limitations */ unsigned int platform_quirks; + + /* number of currently active RX BA sessions */ + int ba_rx_session_count; }; struct wl1271_station { -- cgit v1.2.3 From b67476ef1a6417b92d3bb52510ceee266cd9ea1e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:23 +0300 Subject: wl12xx: call wl12xx_cmd_set_peer_state() in AP mode After adding a station, call wl12xx_cmd_set_peer_state(). This is required for 11n support. Change wl12xx_cmd_set_peer_state() prototype to get hlid as param. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 6 +++--- drivers/net/wireless/wl12xx/cmd.h | 2 +- drivers/net/wireless/wl12xx/main.c | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 025fb14184d6..d655e629677c 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1321,12 +1321,12 @@ out: return ret; } -int wl12xx_cmd_set_peer_state(struct wl1271 *wl) +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) { struct wl12xx_cmd_set_peer_state *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", wl->sta_hlid); + wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1334,7 +1334,7 @@ int wl12xx_cmd_set_peer_state(struct wl1271 *wl) goto out; } - cmd->hlid = wl->sta_hlid; + cmd->hlid = hlid; cmd->state = WL1271_CMD_STA_STATE_CONNECTED; ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 8b32a57e1cc6..740d27edd02d 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -70,7 +70,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16); -int wl12xx_cmd_set_peer_state(struct wl1271 *wl); +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); int wl12xx_roc(struct wl1271 *wl, u8 role_id); int wl12xx_croc(struct wl1271 *wl, u8 role_id); int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 934f5731fd73..27333d1afd0d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -395,7 +395,7 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate) if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) return 0; - ret = wl12xx_cmd_set_peer_state(wl); + ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid); if (ret < 0) return ret; @@ -3676,6 +3676,10 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; + ret = wl12xx_cmd_set_peer_state(wl, hlid); + if (ret < 0) + goto out_sleep; + out_sleep: wl1271_ps_elp_sleep(wl); -- cgit v1.2.3 From b42f068baab96a899bb5488ad9f0e72b14743ec5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:24 +0300 Subject: wl12xx: don't remove key if hlid was already deleted If hlid was already removed, there is no need to remove its key (it might cause a fw crash, as the key is invalid). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index d655e629677c..261807b45ab5 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1203,6 +1203,10 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, struct wl1271_cmd_set_keys *cmd; int ret = 0; + /* hlid might have already been deleted */ + if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) + return 0; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; -- cgit v1.2.3 From 31cd3aed29ca7ebcdaa2570a891a3fab75fe35f6 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:25 +0300 Subject: wl12xx: add wl12xx_cmd_role_start_ibss() Add wl12xx_cmd_role_start_ibss() implementation and defintion. This function is used in order to start the IBSS role. Stopping the IBSS is done by using the same api as stop STA, so there is no need for a separate function. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 62 +++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/cmd.h | 1 + 2 files changed, 63 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 261807b45ab5..d8c391681041 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -617,6 +617,7 @@ out: return ret; } +/* use this function to stop ibss as well */ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl) { struct wl12xx_cmd_role_stop *cmd; @@ -770,6 +771,67 @@ out: return ret; } +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id); + + cmd->role_id = wl->role_id; + if (wl->band == IEEE80211_BAND_5GHZ) + cmd->band = WL12XX_BAND_5GHZ; + cmd->channel = wl->channel; + cmd->ibss.basic_rate_set = cpu_to_le32(wl->basic_rate_set); + cmd->ibss.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->ibss.dtim_interval = bss_conf->dtim_period; + cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; + cmd->ibss.ssid_len = wl->ssid_len; + memcpy(cmd->ibss.ssid, wl->ssid, wl->ssid_len); + memcpy(cmd->ibss.bssid, wl->bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wl->rate_set); + + if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, &wl->sta_hlid); + if (ret) + goto out_free; + } + cmd->ibss.hlid = wl->sta_hlid; + cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set); + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " + "basic_rate_set: 0x%x, remote_rates: 0x%x", + wl->role_id, cmd->sta.hlid, cmd->sta.session, + wl->basic_rate_set, wl->rate_set); + + wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error. */ + wl12xx_free_link(wl, &wl->sta_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + /** * send test command to firmware diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 740d27edd02d..22c2f373dd04 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -44,6 +44,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl); int wl12xx_cmd_role_stop_sta(struct wl1271 *wl); int wl12xx_cmd_role_start_ap(struct wl1271 *wl); int wl12xx_cmd_role_stop_ap(struct wl1271 *wl); +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl); 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); -- cgit v1.2.3 From 227e81e18422851901b9de11c5955d292c4a47fc Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:26 +0300 Subject: wl12xx: support IBSS vif type Start IBSS role when the interface type is IBSS. As with sta role, use the dev role until the role is started. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 33 ++++++++++++++++++++++++++++----- drivers/net/wireless/wl12xx/scan.c | 9 ++++++++- drivers/net/wireless/wl12xx/tx.c | 3 ++- drivers/net/wireless/wl12xx/wl12xx.h | 1 + 4 files changed, 39 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 27333d1afd0d..e280d9d7911b 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1770,6 +1770,9 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl) case BSS_TYPE_STA_BSS: return WL1271_ROLE_STA; + case BSS_TYPE_IBSS: + return WL1271_ROLE_IBSS; + default: wl1271_error("invalid bss_type: %d", wl->bss_type); } @@ -1848,7 +1851,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, if (ret < 0) goto power_off; - if (wl->bss_type == BSS_TYPE_STA_BSS) { + if (wl->bss_type == BSS_TYPE_STA_BSS || + wl->bss_type == BSS_TYPE_IBSS) { /* * The device role is a special role used for * rx and tx frames prior to association (as @@ -2078,6 +2082,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, static int wl1271_join(struct wl1271 *wl, bool set_assoc) { int ret; + bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS); /* * One of the side effects of the JOIN command is that is clears @@ -2094,7 +2099,10 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) if (set_assoc) set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); - ret = wl12xx_cmd_role_start_sta(wl); + if (is_ibss) + ret = wl12xx_cmd_role_start_ibss(wl); + else + ret = wl12xx_cmd_role_start_sta(wl); if (ret < 0) goto out; @@ -3128,6 +3136,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, { bool do_join = false, set_assoc = false; bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS); + bool ibss_joined = false; u32 sta_rate_set = 0; int ret; struct ieee80211_sta *sta; @@ -3141,14 +3150,28 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, goto out; } - if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss) + if (changed & BSS_CHANGED_IBSS) { + if (bss_conf->ibss_joined) { + set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags); + ibss_joined = true; + } else { + if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED, + &wl->flags)) { + wl1271_unjoin(wl); + wl12xx_cmd_role_start_dev(wl); + wl12xx_roc(wl, wl->dev_role_id); + } + } + } + + if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined) do_join = true; /* Need to update the SSID (for filtering etc) */ - if ((changed & BSS_CHANGED_BEACON) && is_ibss) + if ((changed & BSS_CHANGED_BEACON) && ibss_joined) do_join = true; - if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) { + if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) { wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", bss_conf->enable_beacon ? "enabled" : "disabled"); diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 653091a38dce..7229eaa89018 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -34,6 +34,7 @@ void wl1271_scan_complete_work(struct work_struct *work) struct delayed_work *dwork; struct wl1271 *wl; int ret; + bool is_sta, is_ibss; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); @@ -59,7 +60,13 @@ void wl1271_scan_complete_work(struct work_struct *work) if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { /* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req(wl, wl->probereq); - } else { + } + + /* return to ROC if needed */ + is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); + is_ibss = (wl->bss_type == BSS_TYPE_IBSS); + if ((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || + (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) { /* restore remain on channel */ wl12xx_cmd_role_start_dev(wl); wl12xx_roc(wl, wl->dev_role_id); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 1240f4094a8b..8fdffd08d492 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -182,7 +182,8 @@ static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) if (wl->bss_type == BSS_TYPE_AP_BSS) return wl12xx_tx_get_hlid_ap(wl, skb); - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) return wl->sta_hlid; else return wl->dev_hlid; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 487c3c7e0273..416d68ed95cf 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -324,6 +324,7 @@ struct wl1271_ap_key { enum wl12xx_flags { WL1271_FLAG_STA_ASSOCIATED, + WL1271_FLAG_IBSS_JOINED, WL1271_FLAG_GPIO_POWER, WL1271_FLAG_TX_QUEUE_STOPPED, WL1271_FLAG_TX_PENDING, -- cgit v1.2.3 From 0b932ab9f156488a56577873b638ecb1e65fa8d7 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:27 +0300 Subject: wl12xx: AP-mode - set STA HT capabilities when adding a STA In addition, set global HT operation mode via ACX_HT_BSS_OPERATION when a change is detected by usermode Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 10 ++++++---- drivers/net/wireless/wl12xx/acx.h | 2 +- drivers/net/wireless/wl12xx/main.c | 34 +++++++++++++++++++++++++++------- 3 files changed, 34 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index ecbceb6f1ea9..e047594794aa 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1309,13 +1309,15 @@ out: int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation) + bool allow_ht_operation, u8 hlid) { struct wl1271_acx_ht_capabilities *acx; int ret = 0; u32 ht_capabilites = 0; - wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); + wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " + "sta supp: %d sta cap: %d", ht_cap->ht_supported, + ht_cap->cap); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -1323,7 +1325,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, goto out; } - if (allow_ht_operation) { + if (allow_ht_operation && ht_cap->ht_supported) { /* no need to translate capabilities - use the spec values */ ht_capabilites = ht_cap->cap; @@ -1338,7 +1340,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, acx->ampdu_min_spacing = ht_cap->ampdu_density; } - acx->hlid = wl->sta_hlid; + acx->hlid = hlid; acx->ht_capabilites = cpu_to_le32(ht_capabilites); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 82c9271b4e84..758c596f62f6 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1268,7 +1268,7 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, 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); + bool allow_ht_operation, u8 hlid); int wl1271_acx_set_ht_information(struct wl1271 *wl, u16 ht_operation_mode); int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e280d9d7911b..0a0b4b634bd4 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3124,6 +3124,18 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); if (ret < 0) goto out; + + /* Handle HT information change */ + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + 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; + } + } + out: return; } @@ -3439,12 +3451,14 @@ sta_not_found: } } - /* Handle new association with HT. Do this only after join. */ + /* Handle new association with HT. Do this after join. */ if (sta_exists) { if ((changed & BSS_CHANGED_HT) && (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, - true); + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + true, + wl->sta_hlid); if (ret < 0) { wl1271_warning("Set ht cap true failed %d", ret); @@ -3453,8 +3467,10 @@ sta_not_found: } /* handle new association without HT and disassociation */ else if (changed & BSS_CHANGED_ASSOC) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, - false); + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + false, + wl->sta_hlid); if (ret < 0) { wl1271_warning("Set ht cap false failed %d", ret); @@ -3463,8 +3479,8 @@ sta_not_found: } } - /* Handle HT information change. Only after join. */ - if (sta_exists && (changed & BSS_CHANGED_HT) && + /* Handle HT information change. Done after join. */ + if ((changed & BSS_CHANGED_HT) && (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { ret = wl1271_acx_set_ht_information(wl, bss_conf->ht_operation_mode); @@ -3703,6 +3719,10 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid); + if (ret < 0) + goto out_sleep; + out_sleep: wl1271_ps_elp_sleep(wl); -- cgit v1.2.3 From 99d5ad7b9ccedee4a9ff8e24688c7c20e428cd21 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:28 +0300 Subject: wl12xx: AP-mode - configure STA HT rates on join When a new STA joins the BSS, configure the HT rates it supports to the FW. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index d8c391681041..d3e938012ac2 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1415,10 +1415,12 @@ out_free: out: return ret; } + int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) { struct wl12xx_cmd_add_peer *cmd; int ret; + u32 sta_rates; wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); @@ -1437,8 +1439,12 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) cmd->hlid = hlid; cmd->wmm = sta->wme ? 1 : 0; - cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, - sta->supp_rates[wl->band])); + sta_rates = sta->supp_rates[wl->band]; + if (sta->ht_cap.ht_supported) + sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; + + cmd->supported_rates = + cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates)); wl1271_debug(DEBUG_CMD, "new peer rates: 0x%x", cmd->supported_rates); -- cgit v1.2.3 From 1a8adb67f9c37cad9539dd9dcb289ce1411680fc Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:29 +0300 Subject: wl12xx: AP-mode - configure HT rate support to the FW Unconditionally configure HT rate support to the FW on all ACs when starting the AP. When 11n support is disabled by usermode (hostapd), each STA joining the AP will appear as a non-HT STA. This will stop us from accidentally transmitting using MCS rates. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/conf.h | 5 +++++ drivers/net/wireless/wl12xx/init.c | 3 +++ 2 files changed, 8 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 76b5c6233da4..82f205c43342 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -441,6 +441,11 @@ struct conf_rx_settings { CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ CONF_HW_BIT_RATE_54MBPS) +#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \ + CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \ + CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \ + CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \ + CONF_HW_BIT_RATE_MCS_7) /* * Default rates for management traffic when operating in AP mode. This diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index a374c2112be3..b13bebea95e0 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -515,6 +515,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl) else supported_rates = CONF_TX_AP_ENABLED_RATES; + /* unconditionally enable HT rates */ + supported_rates |= CONF_TX_MCS_RATES; + /* configure unicast TX rate classes */ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { rc.enabled_rates = supported_rates; -- cgit v1.2.3 From 7f97b487c4a9634afc008a76ff26268147d7ee8e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:30 +0300 Subject: wl12xx: use ap_bcast_hlid for recorded keys when the key was recorded, wl->ap_bcast_hlid was invalid (since the role wasn't started), so when configuring the key we need to use the current ap_bcast_hlid. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0a0b4b634bd4..360e33ed3ddb 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2533,14 +2533,19 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl) bool wep_key_added = false; for (i = 0; i < MAX_NUM_KEYS; i++) { + u8 hlid; if (wl->recorded_ap_keys[i] == NULL) break; key = wl->recorded_ap_keys[i]; + hlid = key->hlid; + if (hlid == WL12XX_INVALID_LINK_ID) + hlid = wl->ap_bcast_hlid; + ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE, key->id, key->key_type, key->key_size, key->key, - key->hlid, key->tx_seq_32, + hlid, key->tx_seq_32, key->tx_seq_16); if (ret < 0) goto out; -- cgit v1.2.3 From 010d3d30a218fba961bd3d250a59b0ce9d5278f3 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:31 +0300 Subject: wl12xx: don't remove key if hlid was already deleted When wep key was removed after disconnection, sta_hlid was invalid, and it resulted in a fw crash. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 360e33ed3ddb..c917f69f0069 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2625,6 +2625,11 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr)) return 0; + /* don't remove key if hlid was already deleted */ + if (action == KEY_REMOVE && + wl->sta_hlid == WL12XX_INVALID_LINK_ID) + return 0; + ret = wl1271_cmd_set_sta_key(wl, action, id, key_type, key_size, key, addr, tx_seq_32, -- cgit v1.2.3 From bf54e301671a6ece6c94550294dc7faf14158cd3 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:32 +0300 Subject: wl12xx: track freed packets in FW by AC Track the number of freed packets in each AC when receiving an interrupt from the FW. This paves the way for tracking allocated packets per AC. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 16 +++++++++++++++- drivers/net/wireless/wl12xx/tx.c | 2 ++ drivers/net/wireless/wl12xx/wl12xx.h | 8 ++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index c917f69f0069..09cecb336d53 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -814,6 +814,7 @@ static void wl12xx_fw_status(struct wl1271 *wl, struct timespec ts; u32 old_tx_blk_count = wl->tx_blocks_available; int avail, freed_blocks; + int i; wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); @@ -824,6 +825,15 @@ static void wl12xx_fw_status(struct wl1271 *wl, status->drv_rx_counter, status->tx_results_counter); + for (i = 0; i < NUM_TX_QUEUES; i++) { + /* prevent wrap-around in freed-packets counter */ + wl->tx_allocated_pkts -= + (status->tx_released_pkts[i] - + wl->tx_pkts_freed[i]) & 0xff; + + wl->tx_pkts_freed[i] = status->tx_released_pkts[i]; + } + freed_blocks = le32_to_cpu(status->total_released_blks) - wl->tx_blocks_freed; wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks); @@ -1934,7 +1944,7 @@ out: static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues) { - int ret; + int ret, i; wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); @@ -2050,6 +2060,10 @@ deinit: wl->tx_blocks_freed = 0; + wl->tx_allocated_pkts = 0; + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_pkts_freed[i] = 0; + wl1271_debugfs_reset(wl); kfree(wl->fw_status); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 8fdffd08d492..7dd6d8b94f64 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -242,6 +242,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, wl->tx_blocks_available -= total_blocks; wl->tx_allocated_blocks += total_blocks; + wl->tx_allocated_pkts++; + if (wl->bss_type == BSS_TYPE_AP_BSS) wl->links[hlid].allocated_blks += total_blocks; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 416d68ed95cf..24b40251535b 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -268,8 +268,8 @@ struct wl12xx_fw_status { /* Size (in Memory Blocks) of TX pool */ __le32 tx_total; - /* Cumulative counter of released mem-blocks per AC */ - u8 tx_released_blks[NUM_TX_QUEUES]; + /* Cumulative counter of released packets per AC */ + u8 tx_released_pkts[NUM_TX_QUEUES]; /* Cumulative counter of freed MBs per HLID */ u8 tx_lnk_free_blks[WL12XX_MAX_LINKS]; @@ -422,6 +422,10 @@ struct wl1271 { u32 tx_allocated_blocks; u32 tx_results_count; + /* Accounting for allocated / available Tx packets in HW */ + u32 tx_pkts_freed[NUM_TX_QUEUES]; + u32 tx_allocated_pkts; + /* Transmitted TX packets counter for chipset interface */ u32 tx_packets_count; -- cgit v1.2.3 From 742246f8bc16c3a1a556c68ca2fabca162d14c24 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:33 +0300 Subject: wl12xx: schedule TX packets according to FW packet occupancy When selecting packets for transmission, prefer the ACs that are least occupied in the FW. When packets for multiple ACs are present in the FW, it decides which to transmit according to WMM QoS parameters. With these changes, lower priority ACs should not be starved when higher priority traffic is present. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/debugfs.c | 4 ++ drivers/net/wireless/wl12xx/main.c | 7 ++-- drivers/net/wireless/wl12xx/tx.c | 71 +++++++++++++++++++++++------------ drivers/net/wireless/wl12xx/wl12xx.h | 2 +- 4 files changed, 57 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 3102652c7625..d59354f53702 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -340,6 +340,10 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(tx_blocks_available); DRIVER_STATE_PRINT_INT(tx_allocated_blocks); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]); DRIVER_STATE_PRINT_INT(tx_frames_cnt); DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); DRIVER_STATE_PRINT_INT(tx_queue_count[0]); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 09cecb336d53..027b6742a151 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -827,7 +827,7 @@ static void wl12xx_fw_status(struct wl1271 *wl, for (i = 0; i < NUM_TX_QUEUES; i++) { /* prevent wrap-around in freed-packets counter */ - wl->tx_allocated_pkts -= + wl->tx_allocated_pkts[i] -= (status->tx_released_pkts[i] - wl->tx_pkts_freed[i]) & 0xff; @@ -2060,9 +2060,10 @@ deinit: wl->tx_blocks_freed = 0; - wl->tx_allocated_pkts = 0; - for (i = 0; i < NUM_TX_QUEUES; i++) + for (i = 0; i < NUM_TX_QUEUES; i++) { wl->tx_pkts_freed[i] = 0; + wl->tx_allocated_pkts[i] = 0; + } wl1271_debugfs_reset(wl); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 7dd6d8b94f64..ccbcd0a4d2bf 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -205,7 +205,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 len; u32 total_blocks; - int id, ret = -EBUSY; + int id, ret = -EBUSY, ac; /* we use 1 spare block */ u32 spare_blocks = 1; @@ -242,7 +242,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, wl->tx_blocks_available -= total_blocks; wl->tx_allocated_blocks += total_blocks; - wl->tx_allocated_pkts++; + ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + wl->tx_allocated_pkts[ac]++; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->links[hlid].allocated_blks += total_blocks; @@ -485,21 +486,45 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl) } } +static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, + struct sk_buff_head *queues) +{ + int i, q = -1, ac; + u32 min_pkts = 0xffffffff; + + /* + * Find a non-empty ac where: + * 1. There are packets to transmit + * 2. The FW has the least allocated blocks + * + * We prioritize the ACs according to VO>VI>BE>BK + */ + for (i = 0; i < NUM_TX_QUEUES; i++) { + ac = wl1271_tx_get_queue(i); + if (!skb_queue_empty(&queues[ac]) && + (wl->tx_allocated_pkts[ac] < min_pkts)) { + q = ac; + min_pkts = wl->tx_allocated_pkts[q]; + } + } + + if (q == -1) + return NULL; + + return &queues[q]; +} + static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) { struct sk_buff *skb = NULL; unsigned long flags; + struct sk_buff_head *queue; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]); - if (skb) + queue = wl1271_select_queue(wl, wl->tx_queue); + if (!queue) goto out; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]); - if (skb) - goto out; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]); - if (skb) - goto out; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]); + + skb = skb_dequeue(queue); out: if (skb) { @@ -517,6 +542,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) struct sk_buff *skb = NULL; unsigned long flags; int i, h, start_hlid; + struct sk_buff_head *queue; /* start from the link after the last one */ start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; @@ -525,21 +551,20 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) for (i = 0; i < AP_MAX_LINKS; i++) { h = (start_hlid + i) % AP_MAX_LINKS; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]); - if (skb) - goto out; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]); - if (skb) - goto out; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]); - if (skb) - goto out; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]); + /* only consider connected stations */ + if (h >= WL1271_AP_STA_HLID_START && + !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map)) + continue; + + queue = wl1271_select_queue(wl, wl->links[h].tx_queue); + if (!queue) + continue; + + skb = skb_dequeue(queue); if (skb) - goto out; + break; } -out: if (skb) { int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); wl->last_tx_hlid = h; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 24b40251535b..6118df5b742d 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -424,7 +424,7 @@ struct wl1271 { /* Accounting for allocated / available Tx packets in HW */ u32 tx_pkts_freed[NUM_TX_QUEUES]; - u32 tx_allocated_pkts; + u32 tx_allocated_pkts[NUM_TX_QUEUES]; /* Transmitted TX packets counter for chipset interface */ u32 tx_packets_count; -- cgit v1.2.3 From bdf91cfae66dd76a093c75cac8f6ada12fd21b83 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:34 +0300 Subject: wl12xx: handle wrap-around overflow in released Tx blocks FW counter When the FW Tx released blocks counter wraps around, we should correct our calculation of released blocks. Otherwise we add a large negative figure to our driver freed blocks counter Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 027b6742a151..0fa3a2281ddb 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -834,8 +834,15 @@ static void wl12xx_fw_status(struct wl1271 *wl, wl->tx_pkts_freed[i] = status->tx_released_pkts[i]; } - freed_blocks = le32_to_cpu(status->total_released_blks) - - wl->tx_blocks_freed; + /* prevent wrap-around in total blocks counter */ + if (likely(wl->tx_blocks_freed <= + le32_to_cpu(status->total_released_blks))) + freed_blocks = le32_to_cpu(status->total_released_blks) - + wl->tx_blocks_freed; + else + freed_blocks = 0x100000000LL - wl->tx_blocks_freed + + le32_to_cpu(status->total_released_blks); + wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks); wl->tx_allocated_blocks -= freed_blocks; -- cgit v1.2.3 From 769d7ac62d328ff2c126fdee461b7d46e7ea89f4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 14 Aug 2011 13:17:36 +0300 Subject: wl12xx: don't wait for disconnection event Sometimes the fw doesn't send the DISCONNECT_EVENT_COMPLETE_ID on station role stop, so don't wait for it. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index d3e938012ac2..817bc183bc83 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -644,12 +644,6 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl) goto out_free; } - ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); - if (ret < 0) { - wl1271_error("cmd role stop sta event completion error"); - goto out_free; - } - wl12xx_free_link(wl, &wl->sta_hlid); out_free: -- cgit v1.2.3 From 9b17f1b371c5aa5179b3e5392bc22132a3371da4 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:35 +0300 Subject: wl12xx: enable AP advanced functionality This adjusts FW TX block allocation for connected stations in PS. Firmware congestion is measured in allocated packets instead of blocks. Allow a link in PS to queue up to 2 packets to the FW. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 54 ++++++++++++++++++------------------ drivers/net/wireless/wl12xx/ps.c | 4 +-- drivers/net/wireless/wl12xx/tx.c | 19 ++++++------- drivers/net/wireless/wl12xx/wl12xx.h | 25 +++++++++-------- 4 files changed, 51 insertions(+), 51 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0fa3a2281ddb..ad0b5a163b9d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -755,8 +755,7 @@ static int wl1271_plt_init(struct wl1271 *wl) return ret; } -#if 0 -static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks) +static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) { bool fw_ps; @@ -768,21 +767,29 @@ static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks) /* * Wake up from high level PS if the STA is asleep with too little - * blocks in FW or if the STA is awake. + * packets in FW or if the STA is awake. */ - if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS) + if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_end(wl, hlid); /* Start high-level PS if the STA is asleep with enough blocks in FW */ - else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) + else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } -static void wl1271_irq_update_links_status(struct wl1271 *wl, - struct wl1271_fw_ap_status *status) +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) +{ + int id = hlid - WL1271_AP_STA_HLID_START; + return test_bit(id, wl->ap_hlid_map); +} + +static void wl12xx_irq_update_links_status(struct wl1271 *wl, + struct wl12xx_fw_status *status) { u32 cur_fw_ps_map; - u8 hlid; + u8 hlid, cnt; + + /* TODO: also use link_fast_bitmap here */ cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); if (wl->ap_fw_ps_map != cur_fw_ps_map) { @@ -795,18 +802,20 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl, } for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) { - u8 cnt = status->tx_lnk_free_blks[hlid] - - wl->links[hlid].prev_freed_blks; + if (!wl1271_is_active_sta(wl, hlid)) + continue; - wl->links[hlid].prev_freed_blks = - status->tx_lnk_free_blks[hlid]; - wl->links[hlid].allocated_blks -= cnt; + cnt = status->tx_lnk_free_pkts[hlid] - + wl->links[hlid].prev_freed_pkts; - wl1271_irq_ps_regulate_link(wl, hlid, - wl->links[hlid].allocated_blks); + wl->links[hlid].prev_freed_pkts = + status->tx_lnk_free_pkts[hlid]; + wl->links[hlid].allocated_pkts -= cnt; + + wl12xx_irq_ps_regulate_link(wl, hlid, + wl->links[hlid].allocated_pkts); } } -#endif static void wl12xx_fw_status(struct wl1271 *wl, struct wl12xx_fw_status *status) @@ -865,11 +874,8 @@ static void wl12xx_fw_status(struct wl1271 *wl, clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); /* for AP update num of allocated TX blocks per link and ps status */ - if (wl->bss_type == BSS_TYPE_AP_BSS) { -#if 0 - wl1271_irq_update_links_status(wl, status); -#endif - } + if (wl->bss_type == BSS_TYPE_AP_BSS) + wl12xx_irq_update_links_status(wl, status); /* update the host-chipset time offset */ getnstimeofday(&ts); @@ -3711,12 +3717,6 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); } -bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) -{ - int id = hlid - WL1271_AP_STA_HLID_START; - return test_bit(id, wl->ap_hlid_map); -} - static int wl1271_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 3548377ab9c2..4b720b1b9f65 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -226,8 +226,8 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) if (test_bit(hlid, &wl->ap_ps_map)) return; - wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d blks %d " - "clean_queues %d", hlid, wl->links[hlid].allocated_blks, + wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d " + "clean_queues %d", hlid, wl->links[hlid].allocated_pkts, clean_queues); rcu_read_lock(); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index ccbcd0a4d2bf..0f1578577b1a 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -123,27 +123,25 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, wl1271_acx_set_inconnection_sta(wl, hdr->addr1); } -#if 0 static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) { bool fw_ps; - u8 tx_blks; + u8 tx_pkts; /* only regulate station links */ if (hlid < WL1271_AP_STA_HLID_START) return; fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); - tx_blks = wl->links[hlid].allocated_blks; + tx_pkts = wl->links[hlid].allocated_pkts; /* * if in FW PS and there is enough data in FW we can put the link * into high-level PS and clean out its TX queues. */ - if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) + if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } -#endif static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) { @@ -245,8 +243,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); wl->tx_allocated_pkts[ac]++; - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->links[hlid].allocated_blks += total_blocks; + if (wl->bss_type == BSS_TYPE_AP_BSS && + hlid >= WL1271_AP_STA_HLID_START) + wl->links[hlid].allocated_pkts++; ret = 0; @@ -414,9 +413,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); -#if 0 wl1271_tx_regulate_link(wl, hlid); -#endif } else { wl1271_tx_update_filters(wl, skb); } @@ -888,8 +885,8 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) if (wl->bss_type == BSS_TYPE_AP_BSS) { for (i = 0; i < AP_MAX_LINKS; i++) { wl1271_tx_reset_link_queues(wl, i); - wl->links[i].allocated_blks = 0; - wl->links[i].prev_freed_blks = 0; + wl->links[i].allocated_pkts = 0; + wl->links[i].prev_freed_pkts = 0; } wl->last_tx_hlid = 0; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 6118df5b742d..61a7c2163ea2 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -152,15 +152,14 @@ extern u32 wl12xx_debug_level; #define WL1271_AP_STA_HLID_START 3 /* - * When in AP-mode, we allow (at least) this number of mem-blocks + * When in AP-mode, we allow (at least) this number of packets * to be transmitted to FW for a STA in PS-mode. Only when packets are * present in the FW buffers it will wake the sleeping STA. We want to put * enough packets for the driver to transmit all of its buffered data before - * the STA goes to sleep again. But we don't want to take too much mem-blocks + * the STA goes to sleep again. But we don't want to take too much memory * as it might hurt the throughput of active STAs. - * The number of blocks (18) is enough for 2 large packets. */ -#define WL1271_PS_STA_MAX_BLOCKS (2 * 9) +#define WL1271_PS_STA_MAX_PACKETS 2 #define WL1271_AP_BSS_INDEX 0 #define WL1271_AP_DEF_BEACON_EXP 20 @@ -237,8 +236,12 @@ struct wl1271_stats { #define AP_MAX_STATIONS 5 -/* Broadcast and Global links + links to stations */ -#define AP_MAX_LINKS (AP_MAX_STATIONS + 2) +/* Broadcast and Global links + system link + links to stations */ +/* + * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all + * the places that use this. + */ +#define AP_MAX_LINKS (AP_MAX_STATIONS + 3) /* FW status registers */ struct wl12xx_fw_status { @@ -271,8 +274,8 @@ struct wl12xx_fw_status { /* Cumulative counter of released packets per AC */ u8 tx_released_pkts[NUM_TX_QUEUES]; - /* Cumulative counter of freed MBs per HLID */ - u8 tx_lnk_free_blks[WL12XX_MAX_LINKS]; + /* Cumulative counter of freed packets per HLID */ + u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS]; /* Cumulative counter of released Voice memory blocks */ u8 tx_voice_released_blks; @@ -351,9 +354,9 @@ struct wl1271_link { /* AP-mode - TX queue per AC in link */ struct sk_buff_head tx_queue[NUM_TX_QUEUES]; - /* accounting for allocated / available TX blocks in FW */ - u8 allocated_blks; - u8 prev_freed_blks; + /* accounting for allocated / freed packets in FW */ + u8 allocated_pkts; + u8 prev_freed_pkts; u8 addr[ETH_ALEN]; -- cgit v1.2.3 From cf42039f33c8c7c12f19390661eb00ba47b96f91 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:37 +0300 Subject: wl12xx: set the AP-started flag only after setting keys This fix eliminates a potential race between starting the AP role and setting encryption keys. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index ad0b5a163b9d..a23b394291f2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3140,12 +3140,12 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if (ret < 0) goto out; - set_bit(WL1271_FLAG_AP_STARTED, &wl->flags); - wl1271_debug(DEBUG_AP, "started AP"); - ret = wl1271_ap_init_hwenc(wl); if (ret < 0) goto out; + + set_bit(WL1271_FLAG_AP_STARTED, &wl->flags); + wl1271_debug(DEBUG_AP, "started AP"); } } else { if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { -- cgit v1.2.3 From 04216da393e1f6653cc99a58f2fa48d0dde417c0 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:38 +0300 Subject: wl12xx: AP-mode - prevent Tx to stale/invalid stations Don't pollute the queues with Tx directed to invalid stations. This can happen during recovery. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a23b394291f2..b06ff0b25de1 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -779,7 +779,13 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) { - int id = hlid - WL1271_AP_STA_HLID_START; + int id; + + /* global/broadcast "stations" are always active */ + if (hlid < WL1271_AP_STA_HLID_START) + return true; + + id = hlid - WL1271_AP_STA_HLID_START; return test_bit(id, wl->ap_hlid_map); } @@ -1493,6 +1499,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) /* queue the packet */ if (wl->bss_type == BSS_TYPE_AP_BSS) { + if (!wl1271_is_active_sta(wl, hlid)) { + wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", + hlid, q); + dev_kfree_skb(skb); + goto out; + } + wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q); skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); } else { @@ -1508,6 +1521,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags)) ieee80211_queue_work(wl->hw, &wl->tx_work); +out: spin_unlock_irqrestore(&wl->wl_lock, flags); } @@ -3695,7 +3709,7 @@ static int wl1271_allocate_sta(struct wl1271 *wl, } wl_sta = (struct wl1271_station *)sta->drv_priv; - __set_bit(id, wl->ap_hlid_map); + set_bit(id, wl->ap_hlid_map); wl_sta->hlid = WL1271_AP_STA_HLID_START + id; *hlid = wl_sta->hlid; memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); @@ -3709,7 +3723,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) if (WARN_ON(!test_bit(id, wl->ap_hlid_map))) return; - __clear_bit(id, wl->ap_hlid_map); + clear_bit(id, wl->ap_hlid_map); memset(wl->links[hlid].addr, 0, ETH_ALEN); wl->links[hlid].ba_bitmap = 0; wl1271_tx_reset_link_queues(wl, hlid); -- cgit v1.2.3 From 04b4d69c89593d907d81a4aa33e4e42a632fe436 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Aug 2011 13:17:39 +0300 Subject: wl12xx: fix tx_queue_count spurious increment Only increment the queue count after actually queuing the skb. This avoids a spurious increment is case of dropped packets. Also move the Tx-watermark checking code after the packet is enqueued. This makes the count more accurate - it includes the just-queued packet. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index b06ff0b25de1..82f4408e89ad 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1485,18 +1485,6 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count[q]++; - - /* - * The workqueue is slow to process the tx_queue and we need stop - * the queue here, otherwise the queue will get too long. - */ - if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { - wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); - ieee80211_stop_queue(wl->hw, mapping); - set_bit(q, &wl->stopped_queues_map); - } - /* queue the packet */ if (wl->bss_type == BSS_TYPE_AP_BSS) { if (!wl1271_is_active_sta(wl, hlid)) { @@ -1512,6 +1500,18 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) skb_queue_tail(&wl->tx_queue[q], skb); } + wl->tx_queue_count[q]++; + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { + wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); + ieee80211_stop_queue(wl->hw, mapping); + set_bit(q, &wl->stopped_queues_map); + } + /* * The chip specific setup must run before the first TX packet - * before that, the tx_work will not be initialized! -- cgit v1.2.3 From e9eb8cbe77139470651c858b8b7a3d20d332cf47 Mon Sep 17 00:00:00 2001 From: Guy Eilam Date: Tue, 16 Aug 2011 19:49:12 +0300 Subject: wl12xx: use 2 spare TX blocks for GEM cipher Add tx_spare_blocks member to the wl1271 struct for more generic configuration of the amount of spare TX blocks that should be used. The default value is 1. In case GEM cipher is used by the STA, we need 2 spare TX blocks instead of just 1. Signed-off-by: Guy Eilam Acked-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 13 +++++++++++++ drivers/net/wireless/wl12xx/tx.c | 8 +++++--- drivers/net/wireless/wl12xx/tx.h | 1 + drivers/net/wireless/wl12xx/wl12xx.h | 3 +++ 4 files changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 82f4408e89ad..20e7bc78a7fe 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2064,6 +2064,7 @@ deinit: wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; wl->vif = NULL; + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; wl1271_free_ap_keys(wl); memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; @@ -2653,6 +2654,17 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + /* + * A STA set to GEM cipher requires 2 tx spare blocks. + * Return to default value when GEM cipher key is removed + */ + if (key_type == KEY_GEM) { + if (action == KEY_ADD_OR_REPLACE) + wl->tx_spare_blocks = 2; + else if (action == KEY_REMOVE) + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + } + addr = sta ? sta->addr : bcast_addr; if (is_zero_ether_addr(addr)) { @@ -4599,6 +4611,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->sched_scanning = false; wl->tx_security_seq = 0; wl->tx_security_last_seq_lsb = 0; + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; wl->role_id = WL12XX_INVALID_ROLE_ID; wl->system_hlid = WL12XX_SYSTEM_HLID; wl->sta_hlid = WL12XX_INVALID_LINK_ID; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 0f1578577b1a..08227e69616b 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -204,9 +204,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 len; u32 total_blocks; int id, ret = -EBUSY, ac; - - /* we use 1 spare block */ - u32 spare_blocks = 1; + u32 spare_blocks = wl->tx_spare_blocks; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -220,6 +218,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, in the firmware */ len = wl12xx_calc_packet_alignment(wl, total_len); + /* in case of a dummy packet, use default amount of spare mem blocks */ + if (unlikely(wl12xx_is_dummy_packet(wl, skb))) + spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + spare_blocks; diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 7da35c0e411b..6519be4b2c38 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -25,6 +25,7 @@ #ifndef __TX_H__ #define __TX_H__ +#define TX_HW_BLOCK_SPARE_DEFAULT 1 #define TX_HW_BLOCK_SIZE 252 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 61a7c2163ea2..fb2753c46300 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -425,6 +425,9 @@ struct wl1271 { u32 tx_allocated_blocks; u32 tx_results_count; + /* amount of spare TX blocks to use */ + u32 tx_spare_blocks; + /* Accounting for allocated / available Tx packets in HW */ u32 tx_pkts_freed[NUM_TX_QUEUES]; u32 tx_allocated_pkts[NUM_TX_QUEUES]; -- cgit v1.2.3 From cabb81c9a8d8dd7e5f220244246332ab24ef6d80 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 23 Aug 2011 15:56:22 +0300 Subject: wl12xx: allow 11a AP-mode for wl127x devices There was a check preventing 127x devices from using the 11a band when operating as AP. Since we now support this functionality, remove the check. With this patch, a 11a AP starts ok on 127x cards. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index cc70422c0575..6d5664bfc37d 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -294,9 +294,7 @@ 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) { - /* for now 11a is unsupported in AP mode */ - if (wl->bss_type != BSS_TYPE_AP_BSS && - nvs->general_params.dual_mode_select) + if (nvs->general_params.dual_mode_select) wl->enable_11a = true; } -- cgit v1.2.3 From 53835a2d19f533acb0de2466d1ece7b673556419 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 23 Aug 2011 15:56:23 +0300 Subject: wl12xx: initialize rate_set on band rates initialization In some corner cases, (invalid) 11g rates were used while working on 11a band. Take care of it by initializing rate_set according to the configured band. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 20e7bc78a7fe..3702e61a89f6 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2200,10 +2200,14 @@ out: static void wl1271_set_band_rate(struct wl1271 *wl) { - if (wl->band == IEEE80211_BAND_2GHZ) + if (wl->band == IEEE80211_BAND_2GHZ) { wl->basic_rate_set = wl->conf.tx.basic_rate; - else + wl->rate_set = wl->conf.tx.basic_rate; + } else { wl->basic_rate_set = wl->conf.tx.basic_rate_5; + wl->rate_set = wl->conf.tx.basic_rate_5; + } + } static bool wl12xx_is_roc(struct wl1271 *wl) -- cgit v1.2.3 From a879ed790a6108a3372be2d22a1ae81f59ab8db8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 23 Aug 2011 16:37:02 +0300 Subject: wl12xx: increase psm_entry_retries In congested env, sometimes 5 psm entry retries are not enough. Increase the retries count to 8. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3702e61a89f6..3edc1d867836 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -236,7 +236,7 @@ static struct conf_drv_settings default_conf = { .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 50, - .psm_entry_retries = 5, + .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, .psm_entry_hangover_period = 1, -- cgit v1.2.3 From 05dba3550603b9dc8609b5ea7c3ffba4e3bb97f2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 23 Aug 2011 16:37:01 +0300 Subject: wl12xx: enter psm only after station role was started The station didn't get into psm after recovery, because psm was configured before sta role was started. Move wl1271_ps_set_mode() to be executed only after the role was started. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3edc1d867836..0f72af9fc267 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3361,19 +3361,6 @@ sta_not_found: ret = wl1271_acx_conn_monit_params(wl, true); if (ret < 0) goto out; - - /* 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)) { - enum wl1271_cmd_ps_mode mode; - - mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, - wl->basic_rate, - true); - if (ret < 0) - goto out; - } } else { /* use defaults when not associated */ bool was_assoc = @@ -3517,6 +3504,19 @@ sta_not_found: if (ret < 0) goto out; } + + /* 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)) { + enum wl1271_cmd_ps_mode mode; + + mode = STATION_POWER_SAVE_MODE; + ret = wl1271_ps_set_mode(wl, mode, + wl->basic_rate, + true); + if (ret < 0) + goto out; + } } /* Handle new association with HT. Do this after join. */ -- cgit v1.2.3 From f952079a19c69843f4da2f7e0da008192421c6ce Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 23 Aug 2011 18:34:44 +0300 Subject: wl12xx: add support for multiple SSIDs in sched_scan The wl12xx firmwares support multiple SSIDs in a single sched_scan run. This patch implements support for it. We use three different types os sched_scan: FILTER_ANY (ie. not filtering, only wildcard SSID in the probe_reqs); FILTER_LIST (ie. send out probe_reqs with the specified SSIDs and only report if they are found); and FILTER_DISABLED (ie. send out probe_reqs with the specified SSIDs, but report anything found). Since we still don't have proper filter support in nl80211/cfg80211 yet, we cannot use filters when the wildcard SSID is used. Thus, we will not filter anything if the wildcard SSID is specified. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 1 + drivers/net/wireless/wl12xx/scan.c | 63 +++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0f72af9fc267..bde84027ab7f 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4491,6 +4491,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->max_sched_scan_ssids = 8; /* * Maximum length of elements in scanning probe request templates * should be the maximum length possible for a template, without diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 7229eaa89018..af9d53c8e19c 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -473,6 +473,48 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl, cfg->passive[2] || cfg->active[2]; } +/* Returns 0 if no wildcard is used, 1 if wildcard is used or a + * negative value on error */ +static int +wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req) +{ + struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; + struct cfg80211_ssid *ssid = req->ssids; + int ret, wildcard = 0; + + wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + while ((cmd->n_ssids < req->n_ssids) && ssid) { + if (ssid->ssid_len == 0) + wildcard = 1; + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; + cmd->ssids[cmd->n_ssids].len = ssid->ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, ssid->ssid, + ssid->ssid_len); + ssid++; + cmd->n_ssids++; + } + + wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("cmd sched scan ssid list failed"); + goto out; + } + + ret = wildcard; +out: + kfree(cmd); + return ret; +} + int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) @@ -504,14 +546,21 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) cfg->intervals[i] = cpu_to_le32(req->interval); - if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) { - cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC; - cfg->ssid_len = req->ssids[0].ssid_len; - memcpy(cfg->ssid, req->ssids[0].ssid, - req->ssids[0].ssid_len); - } else { + cfg->ssid_len = 0; + if (req->n_ssids == 0) { + wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_ANY"); cfg->filter_type = SCAN_SSID_FILTER_ANY; - cfg->ssid_len = 0; + } else { + ret = wl12xx_scan_sched_scan_ssid_list(wl, req); + if (ret < 0) + goto out; + if (ret) { + wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_DISABLED"); + cfg->filter_type = SCAN_SSID_FILTER_DISABLED; + } else { + wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_LIST"); + cfg->filter_type = SCAN_SSID_FILTER_LIST; + } } if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { -- cgit v1.2.3 From bd4932b8ee2fbdbcf168930de9dcfed1018a085d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 23 Aug 2011 18:34:45 +0300 Subject: wl12xx: use SCAN_SSID_TYPE_PUBLIC when using the wildcard in sched_scan When we are scanning for the wildcard SSID in a scheduled scan, we should use SCAN_SSID_TYPE_PUBLIC so that we don't filter out the scan results. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index af9d53c8e19c..af4ad2353f59 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -490,9 +490,12 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, return -ENOMEM; while ((cmd->n_ssids < req->n_ssids) && ssid) { - if (ssid->ssid_len == 0) + if (ssid->ssid_len == 0) { wildcard = 1; - cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; + } else { + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; + } cmd->ssids[cmd->n_ssids].len = ssid->ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, ssid->ssid, ssid->ssid_len); -- cgit v1.2.3 From 78b8e51dd93a36df55a1c9aacbf6c16361a98cbd Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 29 Aug 2011 15:47:58 -0400 Subject: wl12xx/sdio_test.c: fix build breakage from WL127X_FW_NAME change Commit c302b2c959164622558474871ae942da0e484a38 ("wl12xx: Use a single fw for both STA and AP roles") changed the name of the firmware name definition, breaking the build of wl12xx/sdio_test.c. Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/sdio_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index f28915392877..c3610492852e 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -193,7 +193,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) ret = request_firmware(&fw, WL128X_FW_NAME, wl1271_wl_to_dev(wl)); else - ret = request_firmware(&fw, WL1271_FW_NAME, + ret = request_firmware(&fw, WL127X_FW_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { -- cgit v1.2.3 From c91d06006dd327153d163e5299b8c92f82da86b3 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 25 Aug 2011 18:10:57 +0300 Subject: wl12xx: print acx id Add id param to the acx debug print (on wl1271_cmd_configure) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 817bc183bc83..9ec2f31b0ecf 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -895,7 +895,7 @@ 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"); + wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); acx->id = cpu_to_le16(id); -- cgit v1.2.3 From 5c472148b0894478c427f5b1b0f69602cb103f88 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 25 Aug 2011 18:10:58 +0300 Subject: wl12xx: print the seq_num of rx packet Make it easier to match the driver log against a sniffer log. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/rx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 78d8410da1f4..9074625853b2 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -107,6 +107,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, u8 beacon = 0; u8 is_data = 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0; + u16 seq_num; /* * In PLT mode we seem to get frames and mac80211 warns about them, @@ -169,9 +170,11 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, + seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb, skb->len - desc->pad_len, - beacon ? "beacon" : ""); + beacon ? "beacon" : "", + seq_num); skb_trim(skb, skb->len - desc->pad_len); -- cgit v1.2.3 From 2a5bff091f4c32d07f007d6491453b67b497a3a4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 25 Aug 2011 18:10:59 +0300 Subject: wl12xx: add module_param to trigger BUG() on recovery Crashing on recovery is useful for debugging, as a JTAG can be connected in order to investigate the current fw state. (otherwise, a reconfiguration will occur) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index bde84027ab7f..8324d905b431 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -362,6 +362,7 @@ static struct conf_drv_settings default_conf = { }; static char *fwlog_param; +static bool bug_on_recovery; static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues); @@ -1213,6 +1214,8 @@ static void wl1271_recovery_work(struct work_struct *work) wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); + BUG_ON(bug_on_recovery); + /* * Advance security sequence number to overcome potential progress * in the firmware during recovery. This doens't hurt if the network is @@ -4776,6 +4779,9 @@ module_param_named(fwlog, fwlog_param, charp, 0); MODULE_PARM_DESC(keymap, "FW logger options: continuous, ondemand, dbgpins or disable"); +module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); -- cgit v1.2.3 From a0a521560a686ccb06c92919f1047f94acbb8835 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 25 Aug 2011 18:11:00 +0300 Subject: wl12xx: add beacon_filtering debugfs file Allow enabling/disabling beacon_filtering by debugfs, in order to reduce the log size while debugging (beacon filtering is disabled by default in AP mode, as beacons are needed for ERP configuration). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/debugfs.c | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index d59354f53702..d227385a8f9c 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -655,6 +655,47 @@ static const struct file_operations rx_streaming_always_ops = { .llseek = default_llseek, }; +static ssize_t beacon_filtering_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; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value for beacon_filtering!"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_beacon_filter_opt(wl, !!value); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations beacon_filtering_ops = { + .write = beacon_filtering_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -767,6 +808,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(driver_state, rootdir); DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir); + DEBUGFS_ADD(beacon_filtering, rootdir); streaming = debugfs_create_dir("rx_streaming", rootdir); if (!streaming || IS_ERR(streaming)) -- cgit v1.2.3 From 87579550b2532c23789c89eaa61814d5e71ea521 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 28 Aug 2011 15:11:53 +0300 Subject: wl12xx: don't disconnect on recovery allow full connection recovery by dropping the beacon_loss notification. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8324d905b431..8aff8d4102d5 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1225,9 +1225,6 @@ static void wl1271_recovery_work(struct work_struct *work) test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING; - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - ieee80211_connection_loss(wl->vif); - /* Prevent spurious TX during FW restart */ ieee80211_stop_queues(wl->hw); -- cgit v1.2.3 From 2ec7da254c5bdb5fe1dc18f8f5bdbe32deb3c466 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 28 Aug 2011 15:11:54 +0300 Subject: wl12xx: don't use WL1271_SCAN_OPT_PRIORITY_HIGH flag When setting the WL1271_SCAN_OPT_PRIORITY_HIGH flag, the driver requests a scan *now*, and the fw doesn't enter psm before scanning, which in turn might cause packets loss. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index af4ad2353f59..b2e2abd40045 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -164,9 +164,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, 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; -- cgit v1.2.3 From e0b38265b035a8a2ea05071b67b997f5db181c45 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 28 Aug 2011 15:11:55 +0300 Subject: wl12xx: check for ROC on scan_complete When scan completes, and we are not associated, we should start the dev role and ROC. however, we might already be in this situation (e.g. if we got disconnected during scan). check for it. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index b2e2abd40045..4a4d0d03fa1f 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -65,8 +65,9 @@ void wl1271_scan_complete_work(struct work_struct *work) /* return to ROC if needed */ is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); is_ibss = (wl->bss_type == BSS_TYPE_IBSS); - if ((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || - (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) { + if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || + (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) && + !test_bit(wl->dev_role_id, wl->roc_map)) { /* restore remain on channel */ wl12xx_cmd_role_start_dev(wl); wl12xx_roc(wl, wl->dev_role_id); -- cgit v1.2.3 From 9487775c5b785d7c1e8182825c9ff9cf5e88149e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 28 Aug 2011 15:11:56 +0300 Subject: wl12xx: add config_hangover command Add wl12xx_acx_config_hangover() and respective conf values. This command configures how long the chip will stay awake after it was configured to enter psm. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 40 ++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/acx.h | 18 +++++++++++++++++ drivers/net/wireless/wl12xx/conf.h | 23 ++++++++++++++-------- drivers/net/wireless/wl12xx/init.c | 5 +++++ drivers/net/wireless/wl12xx/main.c | 14 ++++++++++++- 5 files changed, 91 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index e047594794aa..9809e41f06e2 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1691,3 +1691,43 @@ out: kfree(acx); return ret; } + +int wl12xx_acx_config_hangover(struct wl1271 *wl) +{ + struct wl12xx_acx_config_hangover *acx; + struct conf_hangover_settings *conf = &wl->conf.hangover; + int ret; + + wl1271_debug(DEBUG_ACX, "acx config hangover"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->recover_time = cpu_to_le32(conf->recover_time); + acx->hangover_period = conf->hangover_period; + acx->dynamic_mode = conf->dynamic_mode; + acx->early_termination_mode = conf->early_termination_mode; + acx->max_period = conf->max_period; + acx->min_period = conf->min_period; + acx->increase_delta = conf->increase_delta; + acx->decrease_delta = conf->decrease_delta; + acx->quiet_time = conf->quiet_time; + acx->increase_time = conf->increase_time; + acx->window_size = acx->window_size; + + ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, + sizeof(*acx)); + + if (ret < 0) { + wl1271_warning("acx config hangover failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; + +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 758c596f62f6..556ee4e282d5 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1144,6 +1144,23 @@ struct wl12xx_acx_set_rate_mgmt_params { u8 padding2[2]; } __packed; +struct wl12xx_acx_config_hangover { + struct acx_header header; + + __le32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; + u8 padding[2]; +} __packed; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1281,5 +1298,6 @@ int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_fm_coex(struct wl1271 *wl); int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); +int wl12xx_acx_config_hangover(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 82f205c43342..45428a21f9e2 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -915,14 +915,6 @@ struct conf_conn_settings { */ 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 @@ -1236,6 +1228,20 @@ struct conf_rate_policy_settings { u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; }; +struct conf_hangover_settings { + u32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1254,6 +1260,7 @@ struct conf_drv_settings { struct conf_rx_streaming_settings rx_streaming; struct conf_fwlog fwlog; struct conf_rate_policy_settings rate; + struct conf_hangover_settings hangover; u8 hci_io_ds; }; diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index b13bebea95e0..09515f5e5e1d 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -707,6 +707,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* configure hangover */ + ret = wl12xx_acx_config_hangover(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 8aff8d4102d5..f1fd9916e020 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -239,7 +239,6 @@ static struct conf_drv_settings default_conf = { .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, - .psm_entry_hangover_period = 1, .keep_alive_interval = 55000, .max_listen_interval = 20, }, @@ -359,6 +358,19 @@ static struct conf_drv_settings default_conf = { 0x00, 0x00, 0x00, }, }, + .hangover = { + .recover_time = 0, + .hangover_period = 20, + .dynamic_mode = 1, + .early_termination_mode = 1, + .max_period = 20, + .min_period = 1, + .increase_delta = 1, + .decrease_delta = 2, + .quiet_time = 4, + .increase_time = 1, + .window_size = 16, + }, }; static char *fwlog_param; -- cgit v1.2.3 From 14623787abd1217f4c48f128fd4dc03e238265fe Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 28 Aug 2011 15:11:57 +0300 Subject: wl12xx: don't queue a new dummy packet if one is already pending The firmware only asks for one dummy packet at a time, but sometimes we are unable to provide it before a FW timer expires. When this happens, the FW will re-request the dummy packet. If a packet is still queued in the driver queues, do nothing in this case. This prevents spurious dummy packets from clogging up the VO AC. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index f1fd9916e020..aeb4cc51bd3b 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1540,7 +1540,13 @@ out: int wl1271_tx_dummy_packet(struct wl1271 *wl) { unsigned long flags; - int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); + int q; + + /* no need to queue a new dummy packet if one is already pending */ + if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) + return 0; + + q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); spin_lock_irqsave(&wl->wl_lock, flags); set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); -- cgit v1.2.3 From 04907011d59101b508b1c4258f2731fd8f6b6c0a Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 19 May 2011 09:35:00 +0300 Subject: wl12xx: remove deprecated CONFIG_WL12XX_HT flag The driver now support HT properly, so we can always have HT enabled. Remove the WL12XX_HT configuration. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/Kconfig | 10 ---------- drivers/net/wireless/wl12xx/main.c | 6 ------ drivers/net/wireless/wl12xx/rx.c | 2 -- drivers/net/wireless/wl12xx/tx.c | 2 -- 4 files changed, 20 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 07bcb1548d8b..3fe388b87c2e 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -19,16 +19,6 @@ config WL12XX If you choose to build a module, it will be called wl12xx. Say N if unsure. -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 in the wl12xx module. - - That configuration is temporary due to the code incomplete and - still in testing process. - config WL12XX_SPI tristate "TI wl12xx SPI support" depends on WL12XX && SPI_MASTER diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index aeb4cc51bd3b..e5b871c5c521 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4084,7 +4084,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { /* 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 | \ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ @@ -4097,11 +4096,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { .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 = { diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 9074625853b2..dee4cfe9ccc1 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -66,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl, status->rate_idx = wl1271_rate_to_idx(desc->rate, status->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; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 08227e69616b..b8dbc6d1ff98 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -453,7 +453,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) rate_set >>= 1; } -#ifdef CONFIG_WL12XX_HT /* MCS rates indication are on bits 16 - 23 */ rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; @@ -462,7 +461,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); rate_set >>= 1; } -#endif return enabled_rates; } -- cgit v1.2.3 From b6883582a8ea6a7a70d4cc9f4c121ed3d8a75681 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 31 Aug 2011 14:50:13 +0300 Subject: wl12xx: use kstrtoul_from_user simplify code by calling kstrtoul_from_user() (instead of copy_from_user() + kstrtoul()) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/debugfs.c | 46 ++++------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index d227385a8f9c..3999fd528302 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -265,18 +265,10 @@ static ssize_t gpio_power_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) { - return -EFAULT; - } - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in gpio_power"); return -EINVAL; @@ -427,17 +419,10 @@ static ssize_t dtim_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value for dtim_interval"); return -EINVAL; @@ -492,17 +477,10 @@ static ssize_t beacon_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value for beacon_interval"); return -EINVAL; @@ -542,17 +520,10 @@ static ssize_t rx_streaming_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in rx_streaming_interval!"); return -EINVAL; @@ -601,17 +572,10 @@ static ssize_t rx_streaming_always_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in rx_streaming_write!"); return -EINVAL; -- cgit v1.2.3 From 1ec23f7f709b7ab5552cb9c34089633c384ec657 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 25 Aug 2011 14:26:54 +0300 Subject: wl12xx: declare support for WIPHY_FLAG_AP_UAPSD Declare support for uapsd when working as AP, and set psd_type and sp_len whan a station is being added. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 15 ++++++++++----- drivers/net/wireless/wl12xx/cmd.h | 7 +++++++ drivers/net/wireless/wl12xx/main.c | 2 ++ 3 files changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 9ec2f31b0ecf..084262f169b2 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1413,7 +1413,7 @@ out: int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) { struct wl12xx_cmd_add_peer *cmd; - int ret; + int i, ret; u32 sta_rates; wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); @@ -1424,15 +1424,19 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) goto out; } - /* currently we don't support UAPSD */ - cmd->sp_len = 0; - memcpy(cmd->addr, sta->addr, ETH_ALEN); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->aid = sta->aid; cmd->hlid = hlid; + cmd->sp_len = sta->max_sp; cmd->wmm = sta->wme ? 1 : 0; + for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) + if (sta->wme && (sta->uapsd_queues & BIT(i))) + cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; + else + cmd->psd_type[i] = WL1271_PSD_LEGACY; + sta_rates = sta->supp_rates[wl->band]; if (sta->ht_cap.ht_supported) sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; @@ -1440,7 +1444,8 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates)); - wl1271_debug(DEBUG_CMD, "new peer rates: 0x%x", cmd->supported_rates); + wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", + cmd->supported_rates, sta->uapsd_queues); ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 22c2f373dd04..8e4d11ec0c55 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -591,6 +591,13 @@ enum wl12xx_ssid_type { WL12XX_SSID_TYPE_ANY = 2, }; +enum wl1271_psd_type { + WL1271_PSD_LEGACY = 0, + WL1271_PSD_UPSD_TRIGGER = 1, + WL1271_PSD_LEGACY_PSPOLL = 2, + WL1271_PSD_SAPSD = 3 +}; + struct wl12xx_cmd_add_peer { struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e5b871c5c521..501a9e408d7a 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4512,6 +4512,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - sizeof(struct ieee80211_header); + wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + ARRAY_SIZE(wl1271_channels_5ghz) > -- cgit v1.2.3 From fb55377b2aa9464b773e8688a135d5b4c6aa91fa Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 2 Sep 2011 14:28:21 +0300 Subject: wl12xx: add support for sched_scan filters Implement support for filtering in scheduled scans. With this commit we now use the match sets passed by cfg80211 to filter on SSIDs. Due to the nature of the wl12xx firmware API, we don't allow SSIDs to be sent in the probe requests if they are not going to match any of the filters. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 107 +++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 4a4d0d03fa1f..488033b2a39b 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -471,34 +471,77 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl, cfg->passive[2] || cfg->active[2]; } -/* Returns 0 if no wildcard is used, 1 if wildcard is used or a - * negative value on error */ +/* Returns the scan type to be used or a negative value on error */ static int wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, struct cfg80211_sched_scan_request *req) { struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; - struct cfg80211_ssid *ssid = req->ssids; - int ret, wildcard = 0; + struct cfg80211_match_set *sets = req->match_sets; + struct cfg80211_ssid *ssids = req->ssids; + int ret = 0, type, i, j; wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); + /* No filter, no ssids or only bcast ssid */ + if (!req->n_match_sets && + (!req->n_ssids || + (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { + type = SCAN_SSID_FILTER_ANY; + goto out; + } + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (!req->n_match_sets) { + /* No filter, with ssids */ + type = SCAN_SSID_FILTER_DISABLED; + + for (i = 0; i < req->n_ssids; i++) { + cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? + SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, + ssids[i].ssid_len); + cmd->n_ssids++; + } + } else { + type = SCAN_SSID_FILTER_LIST; - while ((cmd->n_ssids < req->n_ssids) && ssid) { - if (ssid->ssid_len == 0) { - wildcard = 1; + /* Add all SSIDs from the filters */ + for (i = 0; i < req->n_match_sets; i++) { cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; - } else { - cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN; + cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, + sets[i].ssid.ssid, sets[i].ssid.ssid_len); + cmd->n_ssids++; + } + if ((req->n_ssids > 1) || + (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { + /* + * Mark all the SSIDs passed in the SSID list as HIDDEN, + * so they're used in probe requests. + */ + for (i = 0; i < req->n_ssids; i++) { + for (j = 0; j < cmd->n_ssids; j++) + if (!memcmp(req->ssids[i].ssid, + cmd->ssids[j].ssid, + req->ssids[i].ssid_len)) { + cmd->ssids[j].type = + SCAN_SSID_TYPE_HIDDEN; + break; + } + /* Fail if SSID isn't present in the filters */ + if (j == req->n_ssids) { + ret = -EINVAL; + goto out_free; + } + } } - cmd->ssids[cmd->n_ssids].len = ssid->ssid_len; - memcpy(cmd->ssids[cmd->n_ssids].ssid, ssid->ssid, - ssid->ssid_len); - ssid++; - cmd->n_ssids++; } wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); @@ -507,13 +550,15 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("cmd sched scan ssid list failed"); - goto out; + goto out_free; } - ret = wildcard; -out: +out_free: kfree(cmd); - return ret; +out: + if (ret < 0) + return ret; + return type; } int wl1271_scan_sched_scan_config(struct wl1271 *wl, @@ -548,21 +593,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, cfg->intervals[i] = cpu_to_le32(req->interval); cfg->ssid_len = 0; - if (req->n_ssids == 0) { - wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_ANY"); - cfg->filter_type = SCAN_SSID_FILTER_ANY; - } else { - ret = wl12xx_scan_sched_scan_ssid_list(wl, req); - if (ret < 0) - goto out; - if (ret) { - wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_DISABLED"); - cfg->filter_type = SCAN_SSID_FILTER_DISABLED; - } else { - wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_LIST"); - cfg->filter_type = SCAN_SSID_FILTER_LIST; - } - } + ret = wl12xx_scan_sched_scan_ssid_list(wl, req); + if (ret < 0) + goto out; + + cfg->filter_type = ret; + + wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { wl1271_error("scan channel list is empty"); -- cgit v1.2.3 From 221737d24f884f3f829e7f94d24fc4cc6d0f7b41 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 2 Sep 2011 14:28:22 +0300 Subject: wl12xx: increase number of allowed SSIDs in sched_scan The latest firmware supports up to 16 SSIDs in the scheduled scan lists. Increase the number we report to cfg80211 and increase the min/max dwell time to 30 and 60 TUs respectively, because otherwise we don't have the time to send the probes for all SSIDs. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 501a9e408d7a..2eb1471ac4ec 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -266,8 +266,8 @@ static struct conf_drv_settings default_conf = { }, .sched_scan = { /* sched_scan requires dwell times in TU instead of TU/1000 */ - .min_dwell_time_active = 8, - .max_dwell_time_active = 30, + .min_dwell_time_active = 30, + .max_dwell_time_active = 60, .dwell_time_passive = 100, .dwell_time_dfs = 150, .num_probe_reqs = 2, @@ -4503,7 +4503,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->max_sched_scan_ssids = 8; + wl->hw->wiphy->max_sched_scan_ssids = 16; + wl->hw->wiphy->max_match_sets = 16; /* * Maximum length of elements in scanning probe request templates * should be the maximum length possible for a template, without -- cgit v1.2.3 From 20a33e52edfd75510ee8cc56a013dd55cb0de0aa Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 2 Sep 2011 14:28:23 +0300 Subject: wl12xx: ignore sched scan match sets without SSID For now, cfg80211 only support match sets with SSIDs, but in the future more parameters will be added. This patch ignores eventual matches that do not contain SSIDs in preparation for the future. This change also affects the case where broadcast SSIDs are used. Matching a broadcast SSID will match everything, so they can be ignored. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 488033b2a39b..eeccc9f095bb 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -479,12 +479,17 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; struct cfg80211_match_set *sets = req->match_sets; struct cfg80211_ssid *ssids = req->ssids; - int ret = 0, type, i, j; + int ret = 0, type, i, j, n_match_ssids = 0; wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); + /* count the match sets that contain SSIDs */ + for (i = 0; i < req->n_match_sets; i++) + if (sets[i].ssid.ssid_len > 0) + n_match_ssids++; + /* No filter, no ssids or only bcast ssid */ - if (!req->n_match_sets && + if (!n_match_ssids && (!req->n_ssids || (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { type = SCAN_SSID_FILTER_ANY; @@ -497,7 +502,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, goto out; } - if (!req->n_match_sets) { + if (!n_match_ssids) { /* No filter, with ssids */ type = SCAN_SSID_FILTER_DISABLED; @@ -514,6 +519,10 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, /* Add all SSIDs from the filters */ for (i = 0; i < req->n_match_sets; i++) { + /* ignore sets without SSIDs */ + if (!sets[i].ssid.ssid_len) + continue; + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, -- cgit v1.2.3 From f8e0af6b8732b47c2531a280753d29a4ca2d114b Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 25 Aug 2011 12:43:12 +0300 Subject: wl12xx: don't indicate up PS-filtered dummy packets Dummy packets are currently only sent on the system_hlid link. The system_hlid link should never be filtered for PS (as it is not a STA link). Even so, for correctness, don't indicate dummy packets up. The skb does not belong to mac80211 and as such does not contain a correct skb->cb. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/ps.c | 8 ++++++-- drivers/net/wireless/wl12xx/tx.c | 2 +- drivers/net/wireless/wl12xx/tx.h | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 4b720b1b9f65..c15ebf2efd40 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) unsigned long flags; int filtered[NUM_TX_QUEUES]; - /* filter all frames currently the low level queus for this hlid */ + /* filter all frames currently in the low level queues for this hlid */ for (i = 0; i < NUM_TX_QUEUES; i++) { filtered[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { + filtered[i]++; + + if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) + continue; + info = IEEE80211_SKB_CB(skb); info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.rates[0].idx = -1; ieee80211_tx_status_ni(wl->hw, skb); - filtered[i]++; } } diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index b8dbc6d1ff98..b6b2d3ac75cf 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -143,7 +143,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) wl1271_ps_link_start(wl, hlid, true); } -static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) { return wl->dummy_packet == skb; } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 6519be4b2c38..5c0fbbe5b42f 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -214,5 +214,6 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl); u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb); void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); +bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); #endif -- cgit v1.2.3 From 56d4f8f685c073c7ed7203b78c57f5d893d65102 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 25 Aug 2011 12:43:13 +0300 Subject: wl12xx: AP mode - don't regulate FW blocks for non-active STAs Check a STA is associated before regulating its PS-status in mac80211. Should never happen, so warn as a precaution. [Small cosmetic change wrt Kalle Valo's comment. -- Luca] Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/tx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index b6b2d3ac75cf..b876e9eb4e83 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -30,6 +30,7 @@ #include "reg.h" #include "ps.h" #include "tx.h" +#include "event.h" static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) { @@ -132,6 +133,9 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) if (hlid < WL1271_AP_STA_HLID_START) return; + if (WARN_ON(!wl1271_is_active_sta(wl, hlid))) + return; + fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); tx_pkts = wl->links[hlid].allocated_pkts; -- cgit v1.2.3 From c47e8229fa5622e4e3f2d6b8e847c4429696a275 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 25 Aug 2011 12:43:14 +0300 Subject: wl12xx: support up to 8 stations in AP-mode Change the max number of AP stations to 8, up from 5. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl12xx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index fb2753c46300..ba1fde9f9b28 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -234,14 +234,14 @@ struct wl1271_stats { #define NUM_TX_QUEUES 4 #define NUM_RX_PKT_DESC 8 -#define AP_MAX_STATIONS 5 +#define AP_MAX_STATIONS 8 /* Broadcast and Global links + system link + links to stations */ /* * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all * the places that use this. */ -#define AP_MAX_LINKS (AP_MAX_STATIONS + 3) +#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START) /* FW status registers */ struct wl12xx_fw_status { -- cgit v1.2.3 From da03209eaca9302e110925f84a515e03062aaa9e Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 25 Aug 2011 12:43:15 +0300 Subject: wl12xx: don't regulate links when a single STA is connected When operating as AP track the number of connected stations. When a single STA is connected don't regulate the PS status of the link. Since this is the only STA connected, there's no point holding space in FW for other links. This will speed up communications with a single connected STA in PSM. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 15 ++++++++++++--- drivers/net/wireless/wl12xx/tx.c | 7 +++++-- drivers/net/wireless/wl12xx/wl12xx.h | 3 +++ 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 2eb1471ac4ec..1127a3ee36e3 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -770,13 +770,14 @@ static int wl1271_plt_init(struct wl1271 *wl) static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) { - bool fw_ps; + bool fw_ps, single_sta; /* only regulate station links */ if (hlid < WL1271_AP_STA_HLID_START) return; fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + single_sta = (wl->active_sta_count == 1); /* * Wake up from high level PS if the STA is asleep with too little @@ -785,8 +786,12 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_end(wl, hlid); - /* Start high-level PS if the STA is asleep with enough blocks in FW */ - else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + /* + * Start high-level PS if the STA is asleep with enough blocks in FW. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. + */ + else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } @@ -2093,6 +2098,7 @@ deinit: memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->links_map, 0, sizeof(wl->links_map)); memset(wl->roc_map, 0, sizeof(wl->roc_map)); + wl->active_sta_count = 0; /* The system link is always allocated */ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); @@ -3747,6 +3753,7 @@ static int wl1271_allocate_sta(struct wl1271 *wl, wl_sta->hlid = WL1271_AP_STA_HLID_START + id; *hlid = wl_sta->hlid; memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); + wl->active_sta_count++; return 0; } @@ -3763,6 +3770,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) wl1271_tx_reset_link_queues(wl, hlid); __clear_bit(hlid, &wl->ap_ps_map); __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + wl->active_sta_count--; } static int wl1271_op_sta_add(struct ieee80211_hw *hw, @@ -4640,6 +4648,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->session_counter = 0; wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; + wl->active_sta_count = 0; setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, (unsigned long) wl); wl->fwlog_size = 0; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index b876e9eb4e83..2bf31302b975 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -126,7 +126,7 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) { - bool fw_ps; + bool fw_ps, single_sta; u8 tx_pkts; /* only regulate station links */ @@ -138,12 +138,15 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); tx_pkts = wl->links[hlid].allocated_pkts; + single_sta = (wl->active_sta_count == 1); /* * if in FW PS and there is enough data in FW we can put the link * into high-level PS and clean out its TX queues. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. */ - if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index ba1fde9f9b28..b661c2c4f689 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -626,6 +626,9 @@ struct wl1271 { /* number of currently active RX BA sessions */ int ba_rx_session_count; + + /* AP-mode - number of currently connected stations */ + int active_sta_count; }; struct wl1271_station { -- cgit v1.2.3 From f4d3b6ab5e78fbdf3c27123cc29c44ff3d626c59 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 25 Aug 2011 12:43:16 +0300 Subject: wl12xx: AP mode - enable the BA constraint event from the FW Unblock the RX BA constraint event from firmware in AP mode as well. This allows us to stop RX BA sessions when the FW requests it. In addition refactor the handler for this event to make the flow clearer. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/event.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 0bd7b020a420..c73fe4c6b616 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl, wl->last_rssi_event = event; } -static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed) +static void wl1271_stop_ba_event(struct wl1271 *wl) { - /* Convert the value to bool */ - wl->ba_allowed = !!ba_allowed; - - /* - * Return in case: - * there are not BA open or the event indication is to allowed BA - */ - if ((!wl->ba_rx_bitmap) || (wl->ba_allowed)) - return; + if (wl->bss_type != BSS_TYPE_AP_BSS) { + if (!wl->ba_rx_bitmap) + return; + ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, + wl->bssid); + } else { + int i; + struct wl1271_link *lnk; + for (i = WL1271_AP_STA_HLID_START; i < WL12XX_MAX_LINKS; i++) { + lnk = &wl->links[i]; + if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap) + continue; - ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid); + ieee80211_stop_rx_ba_session(wl->vif, + lnk->ba_bitmap, + lnk->addr); + } + } } static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, @@ -283,12 +290,14 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_rssi_trigger(wl, mbox); } - if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) { + if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " "ba_allowed = 0x%x", mbox->rx_ba_allowed); - if (wl->vif) - wl1271_stop_ba_event(wl, mbox->rx_ba_allowed); + wl->ba_allowed = !!mbox->rx_ba_allowed; + + if (wl->vif && !wl->ba_allowed) + wl1271_stop_ba_event(wl); } if ((vector & DUMMY_PACKET_EVENT_ID)) { -- cgit v1.2.3 From f1acea9a9d48174f982e14a7a488b208d39d825f Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 25 Aug 2011 12:43:17 +0300 Subject: wl12xx: AP mode - clean BA and queue state in tx_reset Reset the BA state of all connected stations and explicitly clear the Tx queues. The latter is needed for clearing dummy packets from tx_queue_count. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 7 +++++-- drivers/net/wireless/wl12xx/tx.c | 7 ++++++- drivers/net/wireless/wl12xx/tx.h | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 1127a3ee36e3..45cd10ab3aac 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3757,11 +3757,14 @@ static int wl1271_allocate_sta(struct wl1271 *wl, return 0; } -static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) +void wl1271_free_sta(struct wl1271 *wl, u8 hlid) { int id = hlid - WL1271_AP_STA_HLID_START; - if (WARN_ON(!test_bit(id, wl->ap_hlid_map))) + if (hlid < WL1271_AP_STA_HLID_START) + return; + + if (!test_bit(id, wl->ap_hlid_map)) return; clear_bit(id, wl->ap_hlid_map); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 2bf31302b975..9d4157ce0950 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -891,6 +891,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) /* TX failure */ if (wl->bss_type == BSS_TYPE_AP_BSS) { for (i = 0; i < AP_MAX_LINKS; i++) { + wl1271_free_sta(wl, i); wl1271_tx_reset_link_queues(wl, i); wl->links[i].allocated_pkts = 0; wl->links[i].prev_freed_pkts = 0; @@ -910,10 +911,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ieee80211_tx_status_ni(wl->hw, skb); } } - wl->tx_queue_count[i] = 0; } + + wl->ba_rx_bitmap = 0; } + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_queue_count[i] = 0; + wl->stopped_queues_map = 0; /* diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 5c0fbbe5b42f..d6fdbf904a09 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -216,4 +216,7 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); +/* from main.c */ +void wl1271_free_sta(struct wl1271 *wl, u8 hlid); + #endif -- cgit v1.2.3 From 93f8c8e02597b7d7997c4a0a10173ac90ad378e8 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 30 Aug 2011 09:34:01 +0300 Subject: wl12xx: set mac80211 flags for A-MPDU aggregation support We set the mac80211 flag for A-MPDU support and also indicate that Tx-agg session setup is performed in HW. This patch depends on "mac80211: add flag to indicate HW only Tx-agg setup support" Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 45cd10ab3aac..ade62b3d9a2c 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4506,7 +4506,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_AP_LINK_PS; + IEEE80211_HW_AP_LINK_PS | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_TX_AMPDU_SETUP_IN_HW; wl->hw->wiphy->cipher_suites = cipher_suites; wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); -- cgit v1.2.3 From 045c745f8ccdb584ccc97f068c7c10c1090fbcf9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 28 Aug 2011 15:23:01 +0300 Subject: wl12xx: support p2p interfaces Declare support for p2p interfaces, and create p2p_cli/p2p_go roles when being asked for. Indicate we are using a p2p interface by setting the wl->p2p flag. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 24 +++++++++++++++++++----- drivers/net/wireless/wl12xx/wl12xx.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index ade62b3d9a2c..680f5582618e 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1825,10 +1825,16 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl) { switch (wl->bss_type) { case BSS_TYPE_AP_BSS: - return WL1271_ROLE_AP; + if (wl->p2p) + return WL1271_ROLE_P2P_GO; + else + return WL1271_ROLE_AP; case BSS_TYPE_STA_BSS: - return WL1271_ROLE_STA; + if (wl->p2p) + return WL1271_ROLE_P2P_CL; + else + return WL1271_ROLE_STA; case BSS_TYPE_IBSS: return WL1271_ROLE_IBSS; @@ -1850,7 +1856,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, bool booted = false; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); + ieee80211_vif_type_p2p(vif), vif->addr); mutex_lock(&wl->mutex); if (wl->vif) { @@ -1870,7 +1876,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - switch (vif->type) { + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_CLIENT: + wl->p2p = 1; + /* fall-through */ case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; wl->set_bss_type = BSS_TYPE_STA_BSS; @@ -1879,6 +1888,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_P2P_GO: + wl->p2p = 1; + /* fall-through */ case NL80211_IFTYPE_AP: wl->bss_type = BSS_TYPE_AP_BSS; break; @@ -2074,6 +2086,7 @@ deinit: wl->ssid_len = 0; wl->bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE; + wl->p2p = 0; wl->band = IEEE80211_BAND_2GHZ; wl->rx_counter = 0; @@ -4514,7 +4527,8 @@ 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_AP); + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->max_sched_scan_ssids = 16; wl->hw->wiphy->max_match_sets = 16; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b661c2c4f689..3ceb20c170bc 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -402,6 +402,7 @@ struct wl1271 { u8 mac_addr[ETH_ALEN]; u8 bss_type; u8 set_bss_type; + u8 p2p; /* we are using p2p role */ u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; int channel; -- cgit v1.2.3 From 6cd9d21a0c1e2648c07c32c66bb25795ad3208aa Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 22 Sep 2011 10:06:10 +0300 Subject: wl12xx: fix forced passive scans We were using incorrect max and min dwell times during forced passive scans because we were still using the active scan states to scan (passively) the channels that were not marked as passive. Instead of doing passive scans in active states, we now skip active states and scan for all channels in passive states. Cc: # 2.6.36+ Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/scan.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index eeccc9f095bb..08f7e826d27b 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -99,14 +99,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, for (i = 0, j = 0; i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; i++) { - flags = req->channels[i]->flags; if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && - ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && - (req->channels[i]->band == band)) { - + (req->channels[i]->band == band) && + /* + * In passive scans, we scan all remaining + * channels, even if not marked as such. + * In active scans, we only scan channels not + * marked as passive. + */ + (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", req->channels[i]->band, req->channels[i]->center_freq); @@ -158,6 +162,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, int ret; u16 scan_options = 0; + /* skip active scans if we don't have SSIDs */ + if (!passive && wl->scan.req->n_ssids == 0) + return WL1271_NOTHING_TO_SCAN; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { @@ -165,8 +173,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, goto out; } - /* No SSIDs means that we have a forced passive scan */ - if (passive || wl->scan.req->n_ssids == 0) + if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { -- cgit v1.2.3 From d3b104ae22a761dbec8410e6e66ac048c9ff9b5f Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Mon, 12 Sep 2011 10:00:37 +0300 Subject: wl12xx: fix sdio_test module functionality Due to some changes in PM in recent kernels, the sdio_test module has been broken for a while. This patch fixes the code that powers the card on and off. Also made some small indentation fixes in the Makefile. [Rephrased commit log and removed the change in the FW name, since it's done in another patch. -- Luca] Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/Makefile | 6 +++--- drivers/net/wireless/wl12xx/sdio_test.c | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 521c0414e52e..621b3483ca2c 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,16 +1,16 @@ 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 -wl12xx_spi-objs = spi.o +wl12xx_spi-objs = spi.o wl12xx_sdio-objs = sdio.o -wl12xx_sdio_test-objs = sdio_test.o +wl12xx_sdio_test-objs = sdio_test.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 -obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o +obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o # small builtin driver bit obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index c3610492852e..f25d5d9212e7 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -142,14 +143,23 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) ret = pm_runtime_get_sync(&func->dev); if (ret < 0) goto out; + + /* Runtime PM might be disabled, power up the card manually */ + ret = mmc_power_restore_host(func->card->host); + if (ret < 0) + goto out; + sdio_claim_host(func); sdio_enable_func(func); - sdio_release_host(func); } else { - sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); + /* Runtime PM might be disabled, power off the card manually */ + ret = mmc_power_save_host(func->card->host); + if (ret < 0) + goto out; + /* Power down the card */ ret = pm_runtime_put_sync(&func->dev); } @@ -433,7 +443,6 @@ static int __devinit wl1271_probe(struct sdio_func *func, sdio_set_drvdata(func, wl_test); - /* power up the device */ ret = wl1271_chip_wakeup(wl); if (ret) { -- cgit v1.2.3 From 06b660e1a31cf1c7bdcfb87ebf7785dd715b7d17 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Mon, 5 Sep 2011 13:54:36 +0300 Subject: wl12xx: Include OFDM rates in IBSS mode We were including only 11b rates in IBSS mode. This patch adds OFDM rates. [Rephrased commit log and removed one unnecessary comment. -- Luca] Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/conf.h | 6 ++---- drivers/net/wireless/wl12xx/main.c | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 45428a21f9e2..6a6805c3cc74 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -454,12 +454,10 @@ struct conf_rx_settings { #define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) -/* - * Default rates for working as IBSS. use 11b rates - */ +/* default rates for working as IBSS (11b and OFDM) */ #define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ - CONF_HW_BIT_RATE_11MBPS); + CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES); struct conf_tx_rate_class { diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 680f5582618e..7218944f4700 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3472,7 +3472,7 @@ sta_not_found: rates); wl->basic_rate = wl1271_tx_min_rate_get(wl); - /* by default, use 11b rates */ + /* by default, use 11b + OFDM rates */ wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) -- cgit v1.2.3 From d48055d9fc730a7389bac782f98a96de763129e3 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 15 Sep 2011 12:07:04 +0300 Subject: wl12xx: remove TIM ie from probe response wl12xx uses the beacon as the probe response template. However, the beacon includes a TIM ie, which shouldn't exist in the probe response. Delete it from the skb before configuring the probe response template. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7218944f4700..a6c22ad0f575 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3069,6 +3069,20 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, return 0; } +static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + static int wl1271_bss_erp_info_changed(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) @@ -3151,6 +3165,9 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, goto out; } + /* remove TIM ie from probe response */ + wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); + hdr = (struct ieee80211_hdr *) beacon->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); -- cgit v1.2.3 From 26b4bf2e0f0dbafa4dd575b03ffcb12710ef5611 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 15 Sep 2011 12:07:05 +0300 Subject: wl12xx: remove P2P ie from probe response wl12xx uses a single probe response template, regardless of the probe request. However, the P2P spec forbids including the p2p ie in some cases (e.g. the probe request didn't include the p2p ie). The fw responds only to probe requests that don't include the p2p ie, and passes up probe requests that include them (the supplicant will answer them). Thus, strip the p2p ie from the probe response template. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a6c22ad0f575..a8728ae2bb02 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3083,6 +3083,23 @@ static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) skb_trim(skb, skb->len - len); } +static void wl12xx_remove_vendor_ie(struct sk_buff *skb, + unsigned int oui, u8 oui_type, + int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + static int wl1271_bss_erp_info_changed(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) @@ -3168,6 +3185,17 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, /* remove TIM ie from probe response */ wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); + /* + * remove p2p ie from probe response. + * the fw reponds to probe requests that don't include + * the p2p ie. probe requests with p2p ie will be passed, + * and will be responded by the supplicant (the spec + * forbids including the p2p ie when responding to probe + * requests that didn't include it). + */ + wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, ieoffset); + hdr = (struct ieee80211_hdr *) beacon->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); -- cgit v1.2.3 From c6930b07b3d0a8c529e1d9287bd5994319cf447d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 15 Sep 2011 13:00:01 +0300 Subject: wl12xx: send all pending packets on channel change There is a race condition between wl1271_tx_work() and the channel switch, so make sure all the pending packets are being sent before switching channel. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a8728ae2bb02..62118b7988bd 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2355,6 +2355,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL && ((wl->band != conf->channel->band) || (wl->channel != channel))) { + /* send all pending packets */ + wl1271_tx_work_locked(wl); wl->band = conf->channel->band; wl->channel = channel; -- cgit v1.2.3 From df4c849f4608e8962f019fea6021ebd602a11641 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 15 Sep 2011 16:05:47 +0300 Subject: wl12xx: Use dev_hlid for auth and assoc req On roaming, the auth and assoc req are sent with the sta hlid. This is wrong, as the sta hlid is configured according to the old ap. Use the dev_hlid instead. Move the wl1271_tx_update_filters() call into wl1271_tx_get_hlid(), so wl->dev_hlid will be valid. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/tx.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 9d4157ce0950..f6e95e439308 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -81,8 +81,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, struct ieee80211_hdr *hdr; int ret; - hdr = (struct ieee80211_hdr *)(skb->data + - sizeof(struct wl1271_tx_hw_descr)); + hdr = (struct ieee80211_hdr *)skb->data; /* * stop bssid-based filtering before transmitting authentication @@ -181,14 +180,20 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + if (wl12xx_is_dummy_packet(wl, skb)) return wl->system_hlid; if (wl->bss_type == BSS_TYPE_AP_BSS) return wl12xx_tx_get_hlid_ap(wl, skb); - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || - test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) + wl1271_tx_update_filters(wl, skb); + + if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) && + !ieee80211_is_auth(hdr->frame_control) && + !ieee80211_is_assoc_req(hdr->frame_control)) return wl->sta_hlid; else return wl->dev_hlid; @@ -423,8 +428,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_regulate_link(wl, hlid); - } else { - wl1271_tx_update_filters(wl, skb); } /* -- cgit v1.2.3 From 68eaaf6ee5ac35d8e592834219cee9c9e88fdb24 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sat, 3 Sep 2011 20:22:03 +0300 Subject: wl12xx: AP mode - support hidden SSID If a hidden SSID is requested, generate a probe response template containing the real SSID. Depends on the patch "mac80211: add ssid config to bss information in AP-mode". Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 24 +++++++----- drivers/net/wireless/wl12xx/main.c | 75 ++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 084262f169b2..51be8f7fbb88 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -661,12 +661,9 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id); - /* - * We currently do not support hidden SSID. The real SSID - * should be fetched from mac80211 first. - */ - if (wl->ssid_len == 0) { - wl1271_warning("Hidden SSID currently not supported for AP"); + /* trying to use hidden SSID with an old hostapd version */ + if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) { + wl1271_error("got a null SSID from beacon/bss"); ret = -EINVAL; goto out; } @@ -695,9 +692,18 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl) cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; cmd->channel = wl->channel; - cmd->ap.ssid_len = wl->ssid_len; - cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; - memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len); + + if (!bss_conf->hidden_ssid) { + /* take the SSID from the beacon for backward compatibility */ + cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; + cmd->ap.ssid_len = wl->ssid_len; + memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len); + } else { + cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; + cmd->ap.ssid_len = bss_conf->ssid_len; + memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); + } + cmd->ap.local_rates = cpu_to_le32(0xffffffff); switch (wl->band) { diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 62118b7988bd..02b5c007d1bf 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3102,6 +3102,62 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb, skb_trim(skb, skb->len - len); } +static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, + u8 *probe_rsp_data, + size_t probe_rsp_len, + u32 rates) +{ + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; + int ssid_ie_offset, ie_offset, templ_len; + const u8 *ptr; + + /* no need to change probe response if the SSID is set correctly */ + if (wl->ssid_len > 0) + return wl1271_cmd_template_set(wl, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_data, + probe_rsp_len, 0, + rates); + + if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { + wl1271_error("probe_rsp template too big"); + return -EINVAL; + } + + /* start searching from IE offset */ + ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + + ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset, + probe_rsp_len - ie_offset); + if (!ptr) { + wl1271_error("No SSID in beacon!"); + return -EINVAL; + } + + ssid_ie_offset = ptr - probe_rsp_data; + ptr += (ptr[1] + 2); + + memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset); + + /* insert SSID from bss_conf */ + probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; + probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; + memcpy(probe_rsp_templ + ssid_ie_offset + 2, + bss_conf->ssid, bss_conf->ssid_len); + templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; + + memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, + ptr, probe_rsp_len - (ptr - probe_rsp_data)); + templ_len += probe_rsp_len - (ptr - probe_rsp_data); + + return wl1271_cmd_template_set(wl, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_templ, + templ_len, 0, + rates); +} + static int wl1271_bss_erp_info_changed(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) @@ -3201,14 +3257,17 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, hdr = (struct ieee80211_hdr *) beacon->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); - - tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE : - CMD_TEMPL_PROBE_RESPONSE; - ret = wl1271_cmd_template_set(wl, - tmpl_id, - beacon->data, - beacon->len, 0, - wl1271_tx_min_rate_get(wl)); + if (is_ap) + ret = wl1271_ap_set_probe_resp_tmpl(wl, + beacon->data, + beacon->len, + wl1271_tx_min_rate_get(wl)); + else + ret = wl1271_cmd_template_set(wl, + CMD_TEMPL_PROBE_RESPONSE, + beacon->data, + beacon->len, 0, + wl1271_tx_min_rate_get(wl)); dev_kfree_skb(beacon); if (ret < 0) goto out; -- cgit v1.2.3 From af7fbb28efff0c0d8fc0852ad6622e5437a7611e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 19 Sep 2011 13:51:42 +0300 Subject: wl12xx: implement set_bitrate_mask callback Save the configured bitrate, and use the min allowed rate as the basic rate (e.g. when scanning). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/cmd.c | 19 +++++---- drivers/net/wireless/wl12xx/init.c | 17 ++++---- drivers/net/wireless/wl12xx/main.c | 79 +++++++++++++++++++++++++----------- drivers/net/wireless/wl12xx/scan.c | 23 +++++++---- drivers/net/wireless/wl12xx/tx.c | 23 ++++------- drivers/net/wireless/wl12xx/tx.h | 5 ++- drivers/net/wireless/wl12xx/wl12xx.h | 1 + 7 files changed, 102 insertions(+), 65 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 51be8f7fbb88..287fe95ecb40 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1112,6 +1112,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, { struct sk_buff *skb; int ret; + u32 rate; skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, ie, ie_len); @@ -1122,14 +1123,13 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); 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); + skb->data, skb->len, 0, 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); + skb->data, skb->len, 0, rate); out: dev_kfree_skb(skb); @@ -1140,6 +1140,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct sk_buff *skb) { int ret; + u32 rate; if (!skb) skb = ieee80211_ap_probereq_get(wl->hw, wl->vif); @@ -1148,14 +1149,13 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]); if (wl->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); + skb->data, skb->len, 0, 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); + skb->data, skb->len, 0, rate); if (ret < 0) wl1271_error("Unable to set ap probe request template."); @@ -1448,7 +1448,8 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; cmd->supported_rates = - cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates)); + cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, + wl->band)); wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", cmd->supported_rates, sta->uapsd_queues); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 09515f5e5e1d..04db64c94e9a 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -103,6 +103,7 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl) { struct wl12xx_disconn_template *tmpl; int ret; + u32 rate; tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); if (!tmpl) { @@ -113,9 +114,9 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl) tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, - tmpl, sizeof(*tmpl), 0, - wl1271_tx_min_rate_get(wl)); + tmpl, sizeof(*tmpl), 0, rate); out: kfree(tmpl); @@ -126,6 +127,7 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl) { struct ieee80211_hdr_3addr *nullfunc; int ret; + u32 rate; nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); if (!nullfunc) { @@ -142,9 +144,9 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl) memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, - sizeof(*nullfunc), 0, - wl1271_tx_min_rate_get(wl)); + sizeof(*nullfunc), 0, rate); out: kfree(nullfunc); @@ -155,6 +157,7 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) { struct ieee80211_qos_hdr *qosnull; int ret; + u32 rate; qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); if (!qosnull) { @@ -171,9 +174,9 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, - sizeof(*qosnull), 0, - wl1271_tx_min_rate_get(wl)); + sizeof(*qosnull), 0, rate); out: kfree(qosnull); @@ -498,7 +501,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl) return ret; /* use the min basic rate for AP broadcast/multicast */ - rc.enabled_rates = wl1271_tx_min_rate_get(wl); + rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); rc.short_retry_limit = 10; rc.long_retry_limit = 10; rc.aflags = 0; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 02b5c007d1bf..384ba1944396 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2099,6 +2099,8 @@ deinit: wl->time_offset = 0; wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; wl->vif = NULL; wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; wl1271_free_ap_keys(wl); @@ -2237,14 +2239,8 @@ out: static void wl1271_set_band_rate(struct wl1271 *wl) { - if (wl->band == IEEE80211_BAND_2GHZ) { - wl->basic_rate_set = wl->conf.tx.basic_rate; - wl->rate_set = wl->conf.tx.basic_rate; - } else { - wl->basic_rate_set = wl->conf.tx.basic_rate_5; - wl->rate_set = wl->conf.tx.basic_rate_5; - } - + wl->basic_rate_set = wl->bitrate_masks[wl->band]; + wl->rate_set = wl->basic_rate_set; } static bool wl12xx_is_roc(struct wl1271 *wl) @@ -2273,7 +2269,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) if (ret < 0) goto out; } - wl->rate_set = wl1271_tx_min_rate_get(wl); + wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -2370,7 +2366,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) wl1271_warning("rate policy for channel " @@ -3214,6 +3211,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, if ((changed & BSS_CHANGED_BEACON)) { struct ieee80211_hdr *hdr; + u32 min_rate; int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); @@ -3229,12 +3227,13 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, dev_kfree_skb(beacon); goto out; } + min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : CMD_TEMPL_BEACON; ret = wl1271_cmd_template_set(wl, tmpl_id, beacon->data, beacon->len, 0, - wl1271_tx_min_rate_get(wl)); + min_rate); if (ret < 0) { dev_kfree_skb(beacon); goto out; @@ -3261,13 +3260,13 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, ret = wl1271_ap_set_probe_resp_tmpl(wl, beacon->data, beacon->len, - wl1271_tx_min_rate_get(wl)); + min_rate); else ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, beacon->data, beacon->len, 0, - wl1271_tx_min_rate_get(wl)); + min_rate); dev_kfree_skb(beacon); if (ret < 0) goto out; @@ -3288,8 +3287,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BASIC_RATES)) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = wl1271_tx_min_rate_get(wl, + wl->basic_rate_set); ret = wl1271_init_ap_rates(wl); if (ret < 0) { @@ -3471,12 +3472,15 @@ sta_not_found: * 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_tx_min_rate_get(wl); + wl->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); if (sta_rate_set) wl->rate_set = wl1271_tx_enabled_rates_get(wl, - sta_rate_set); + sta_rate_set, + wl->band); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -3523,7 +3527,8 @@ sta_not_found: /* revert back to minimum rates for the current band */ wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -3574,9 +3579,11 @@ sta_not_found: if (bss_conf->ibss_joined) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, - rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); /* by default, use 11b + OFDM rates */ wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; @@ -4098,6 +4105,29 @@ out: return ret; } +static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct wl1271 *wl = hw->priv; + int i; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", + mask->control[NL80211_BAND_2GHZ].legacy, + mask->control[NL80211_BAND_5GHZ].legacy); + + mutex_lock(&wl->mutex); + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + wl->bitrate_masks[i] = + wl1271_tx_enabled_rates_get(wl, + mask->control[i].legacy, + i); + mutex_unlock(&wl->mutex); + + return 0; +} + static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -4373,6 +4403,7 @@ static const struct ieee80211_ops wl1271_ops = { .sta_remove = wl1271_op_sta_remove, .ampdu_action = wl1271_op_ampdu_action, .tx_frames_pending = wl1271_tx_frames_pending, + .set_bitrate_mask = wl12xx_set_bitrate_mask, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -4793,6 +4824,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) /* Apply default driver configuration. */ wl1271_conf_init(wl); + wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; order = get_order(WL1271_AGGR_BUFFER_SIZE); wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 08f7e826d27b..128ccb79318c 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -28,6 +28,7 @@ #include "scan.h" #include "acx.h" #include "ps.h" +#include "tx.h" void wl1271_scan_complete_work(struct work_struct *work) { @@ -243,14 +244,17 @@ out: void wl1271_scan_stm(struct wl1271 *wl) { int ret = 0; + enum ieee80211_band band; + u32 rate; 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); + band = IEEE80211_BAND_2GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl); @@ -259,8 +263,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, - wl->conf.tx.basic_rate); + band = IEEE80211_BAND_2GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; @@ -272,8 +277,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, - wl->conf.tx.basic_rate_5); + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl); @@ -282,8 +288,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, - wl->conf.tx.basic_rate_5); + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index f6e95e439308..bad9e29d49b0 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -450,13 +450,14 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, return total_len; } -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, + enum ieee80211_band rate_band) { struct ieee80211_supported_band *band; u32 enabled_rates = 0; int bit; - band = wl->hw->wiphy->bands[wl->band]; + band = wl->hw->wiphy->bands[rate_band]; for (bit = 0; bit < band->n_bitrates; bit++) { if (rate_set & 0x1) enabled_rates |= band->bitrates[bit].hw_value; @@ -989,20 +990,10 @@ void wl1271_tx_flush(struct wl1271 *wl) wl1271_warning("Unable to flush all TX buffers, timed out."); } -u32 wl1271_tx_min_rate_get(struct wl1271 *wl) +u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) { - 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; - } + if (WARN_ON(!rate_set)) + return 0; - return rate; + return BIT(__ffs(rate_set)); } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index d6fdbf904a09..dc4f09adf088 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -209,8 +209,9 @@ void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues); 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); -u32 wl1271_tx_min_rate_get(struct wl1271 *wl); +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, + enum ieee80211_band rate_band); +u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb); void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 3ceb20c170bc..45f03f578e18 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -526,6 +526,7 @@ struct wl1271 { u32 basic_rate_set; u32 basic_rate; u32 rate_set; + u32 bitrate_masks[IEEE80211_NUM_BANDS]; /* The current band */ enum ieee80211_band band; -- cgit v1.2.3 From f80c2d12e51845c3a697e9ce9d8a98287f1aae38 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 22 Sep 2011 09:52:05 +0300 Subject: wl12xx: correct fw_status structure for 8 sta support in AP-mode Fix an erroneous labeling of array boundaries in the fw_status structure. Reported-by: Dan Carpenter Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 2 ++ drivers/net/wireless/wl12xx/wl12xx.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 384ba1944396..a51dd0ed6d2d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4722,6 +4722,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) int i, j, ret; unsigned int order; + BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS); + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { wl1271_error("could not alloc ieee80211_hw"); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 45f03f578e18..997f53245011 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -138,7 +138,7 @@ extern u32 wl12xx_debug_level; #define WL1271_DEFAULT_DTIM_PERIOD 1 #define WL12XX_MAX_ROLES 4 -#define WL12XX_MAX_LINKS 8 +#define WL12XX_MAX_LINKS 12 #define WL12XX_INVALID_ROLE_ID 0xff #define WL12XX_INVALID_LINK_ID 0xff @@ -279,7 +279,7 @@ struct wl12xx_fw_status { /* Cumulative counter of released Voice memory blocks */ u8 tx_voice_released_blks; - u8 padding_1[7]; + u8 padding_1[3]; __le32 log_start_addr; } __packed; -- cgit v1.2.3 From 6b661895a195f244097a60d4d4c9f09983d7efc7 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 22 Sep 2011 09:52:06 +0300 Subject: wl12xx: report the stop_ba event to all STAs in AP-mode Use the AP_MAX_LINKS as the upper boundary for traversing the links array, thereby guaranteeing BA sessions with all connected STAs are stopped when the stop_ba event is received. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index c73fe4c6b616..e66db69f8d17 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -181,7 +181,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl) } else { int i; struct wl1271_link *lnk; - for (i = WL1271_AP_STA_HLID_START; i < WL12XX_MAX_LINKS; i++) { + for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) { lnk = &wl->links[i]; if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap) continue; -- cgit v1.2.3 From 37a41b4affa33bb237d3692bf51f1b5ebcaf29d8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 21 Sep 2011 14:06:11 +0300 Subject: mac80211: add ieee80211_vif param to tsf functions TSF can be kept per vif. Add ieee80211_vif param to set/get/reset_tsf, and move the debugfs entries to the per-vif directory. Update all the drivers that implement these callbacks. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 3 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 6 +-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 9 ++-- drivers/net/wireless/ath/ath9k/main.c | 8 ++-- drivers/net/wireless/ath/carl9170/main.c | 3 +- drivers/net/wireless/b43/main.c | 5 ++- drivers/net/wireless/iwlegacy/iwl-core.c | 3 +- drivers/net/wireless/iwlegacy/iwl-core.h | 3 +- drivers/net/wireless/rt2x00/rt2400pci.c | 5 ++- drivers/net/wireless/rt2x00/rt2500pci.c | 3 +- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- drivers/net/wireless/rt2x00/rt2800lib.h | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- drivers/net/wireless/rtl818x/rtl8180/dev.c | 5 ++- drivers/net/wireless/rtl818x/rtl8187/dev.c | 2 +- drivers/net/wireless/rtlwifi/core.c | 8 ++-- drivers/net/wireless/wl12xx/main.c | 3 +- drivers/net/wireless/zd1211rw/zd_mac.c | 2 +- drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 12 ++++-- drivers/staging/winbond/wbusb.c | 2 +- include/net/mac80211.h | 7 ++-- net/mac80211/debugfs.c | 52 ------------------------ net/mac80211/debugfs_netdev.c | 48 +++++++++++++++++++++- net/mac80211/driver-ops.h | 22 ++++++---- net/mac80211/driver-trace.h | 26 +++++++----- net/mac80211/ibss.c | 4 +- 27 files changed, 137 insertions(+), 112 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 43ebc44fc82c..3b752d9fb3cd 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1249,7 +1249,8 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev) return 0; } -static u64 adm8211_get_tsft(struct ieee80211_hw *dev) +static u64 adm8211_get_tsft(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct adm8211_priv *priv = dev->priv; u32 tsftl; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 0560234ec3f6..bba4f6fcf7e2 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -602,7 +602,7 @@ ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, static u64 -ath5k_get_tsf(struct ieee80211_hw *hw) +ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_hw *ah = hw->priv; @@ -611,7 +611,7 @@ ath5k_get_tsf(struct ieee80211_hw *hw) static void -ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf) { struct ath5k_hw *ah = hw->priv; @@ -620,7 +620,7 @@ ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) static void -ath5k_reset_tsf(struct ieee80211_hw *hw) +ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 495fdf680a6c..17dbbd9d2f53 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1563,7 +1563,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } -static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) +static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; u64 tsf; @@ -1577,7 +1578,8 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { struct ath9k_htc_priv *priv = hw->priv; @@ -1588,7 +1590,8 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) mutex_unlock(&priv->mutex); } -static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) +static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ee39702da5d8..fb803e209760 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2143,7 +2143,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_ps_restore(sc); } -static u64 ath9k_get_tsf(struct ieee80211_hw *hw) +static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; u64 tsf; @@ -2157,7 +2157,9 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void ath9k_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 tsf) { struct ath_softc *sc = hw->priv; @@ -2168,7 +2170,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) mutex_unlock(&sc->mutex); } -static void ath9k_reset_tsf(struct ieee80211_hw *hw) +static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index af351ecd87c4..8b780d6d470f 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1078,7 +1078,8 @@ out: mutex_unlock(&ar->mutex); } -static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw) +static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ar9170 *ar = hw->priv; struct carl9170_tsf_rsp tsf; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 56fa3a3648c4..559bcd6688ec 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3599,7 +3599,7 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 b43_op_get_tsf(struct ieee80211_hw *hw) +static u64 b43_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -3618,7 +3618,8 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void b43_op_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 35cd2537e7fd..c4921911c6d1 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -2220,7 +2220,8 @@ out: } EXPORT_SYMBOL(iwl_legacy_mac_config); -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw) +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; unsigned long flags; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index 84da79376ef8..b2df01c8f8f5 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -620,7 +620,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( /* mac80211 handlers */ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed); -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw); +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index daa32fc9398b..7e9272b8f01d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1239,7 +1239,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, * call, we must decrease the higher 32bits with 1 to get * to correct value. */ - tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw); + tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw, NULL); rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME); rx_high = upper_32_bits(tsf); @@ -1673,7 +1673,8 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index b46c3b8866fa..dcc0e1fcca77 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1966,7 +1966,8 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 31c98509f7e6..9688dd0a7ebd 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4466,7 +4466,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, } EXPORT_SYMBOL_GPL(rt2800_conf_tx); -u64 rt2800_get_tsf(struct ieee80211_hw *hw) +u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 7a2511f6785c..6de128e9c612 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -199,7 +199,7 @@ void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params); -u64 rt2800_get_tsf(struct ieee80211_hw *hw); +u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 058ef4b19d1d..6b6a8e2dcddc 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2940,7 +2940,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } -static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 0baeb894f093..6f51e39f5595 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2279,7 +2279,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } -static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) +static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 66b29dc07cc3..0082015ff664 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -669,7 +669,8 @@ static void rtl8180_stop(struct ieee80211_hw *dev) rtl8180_free_tx_ring(dev, i); } -static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) +static u64 rtl8180_get_tsf(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct rtl8180_priv *priv = dev->priv; @@ -701,7 +702,7 @@ static void rtl8180_beacon_work(struct work_struct *work) * TODO: make hardware update beacon timestamp */ mgmt = (struct ieee80211_mgmt *)skb->data; - mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev)); + mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev, vif)); /* TODO: use actual beacon queue */ skb_set_queue_mapping(skb, 0); diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 1e0be14d10d4..f5afa155ce91 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -1277,7 +1277,7 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } -static u64 rtl8187_get_tsf(struct ieee80211_hw *dev) +static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif) { struct rtl8187_priv *priv = dev->priv; diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 04c4e9eb6ee6..21e40f62a8d7 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -775,7 +775,7 @@ out: mutex_unlock(&rtlpriv->locks.conf_mutex); } -static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); u64 tsf; @@ -784,7 +784,8 @@ static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -794,7 +795,8 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss)); } -static void rtl_op_reset_tsf(struct ieee80211_hw *hw) +static void rtl_op_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmp = 0; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a51dd0ed6d2d..7d409b0f3357 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3815,7 +3815,8 @@ out: return ret; } -static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) +static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index cabfae1e70b1..0a70149df3fc 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1332,7 +1332,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, } } -static u64 zd_op_get_tsf(struct ieee80211_hw *hw) +static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct zd_mac *mac = zd_hw_mac(hw); return zd_chip_get_tsf(&mac->chip); diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c index d6de44e430d3..315dd91800b6 100644 --- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c @@ -133,7 +133,8 @@ static int brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw); static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw); -static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf); +static void brcms_ops_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf); static int brcms_ops_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); static void brcms_ops_sta_notify(struct ieee80211_hw *hw, @@ -142,7 +143,8 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta); static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); -static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw); +static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); static int brcms_ops_sta_remove(struct ieee80211_hw *hw, @@ -516,7 +518,8 @@ static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw) return; } -static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void brcms_ops_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { wiphy_err(hw->wiphy, "%s: Enter\n", __func__); return; @@ -565,7 +568,8 @@ brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw) +static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { wiphy_err(hw->wiphy, "%s: Enter\n", __func__); return 0; diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 3724e1e67ec2..a2e8bd452ed9 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -277,7 +277,7 @@ static int wbsoft_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) +static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif) { printk("wbsoft_get_tsf called\n"); return 0; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c0f63fd0c52b..90dfcc99b466 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2000,9 +2000,10 @@ struct ieee80211_ops { enum sta_notify_cmd, struct ieee80211_sta *sta); int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); - u64 (*get_tsf)(struct ieee80211_hw *hw); - void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf); - void (*reset_tsf)(struct ieee80211_hw *hw); + u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf); + void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index c9141168fd43..883996b2f99f 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -78,57 +78,6 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); -static ssize_t tsf_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - u64 tsf; - - tsf = drv_get_tsf(local); - - return mac80211_format_buffer(user_buf, count, ppos, "0x%016llx\n", - (unsigned long long) tsf); -} - -static ssize_t tsf_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - unsigned long long tsf; - char buf[100]; - size_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - if (strncmp(buf, "reset", 5) == 0) { - if (local->ops->reset_tsf) { - drv_reset_tsf(local); - wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); - } - } else { - tsf = simple_strtoul(buf, NULL, 0); - if (local->ops->set_tsf) { - drv_set_tsf(local, tsf); - wiphy_info(local->hw.wiphy, - "debugfs set TSF to %#018llx\n", tsf); - - } - } - - return count; -} - -static const struct file_operations tsf_ops = { - .read = tsf_read, - .write = tsf_write, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; - static ssize_t reset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -447,7 +396,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(frequency); DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(wep_iv); - DEBUGFS_ADD(tsf); DEBUGFS_ADD(queues); DEBUGFS_ADD_MODE(reset, 0200); DEBUGFS_ADD(noack); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index dd0462917518..9352819a986b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -21,6 +21,7 @@ #include "rate.h" #include "debugfs.h" #include "debugfs_netdev.h" +#include "driver-ops.h" static ssize_t ieee80211_if_read( struct ieee80211_sub_if_data *sdata, @@ -331,6 +332,46 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( } __IEEE80211_IF_FILE(num_buffered_multicast, NULL); +/* IBSS attributes */ +static ssize_t ieee80211_if_fmt_tsf( + const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) +{ + struct ieee80211_local *local = sdata->local; + u64 tsf; + + tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata); + + return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf); +} + +static ssize_t ieee80211_if_parse_tsf( + struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) +{ + struct ieee80211_local *local = sdata->local; + unsigned long long tsf; + int ret; + + if (strncmp(buf, "reset", 5) == 0) { + if (local->ops->reset_tsf) { + drv_reset_tsf(local, sdata); + wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); + } + } else { + ret = kstrtoull(buf, 10, &tsf); + if (ret < 0) + return -EINVAL; + if (local->ops->set_tsf) { + drv_set_tsf(local, sdata, tsf); + wiphy_info(local->hw.wiphy, + "debugfs set TSF to %#018llx\n", tsf); + } + } + + return buflen; +} +__IEEE80211_IF_FILE_W(tsf); + + /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); @@ -421,6 +462,11 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD_MODE(tkip_mic_test, 0200); } +static void add_ibss_files(struct ieee80211_sub_if_data *sdata) +{ + DEBUGFS_ADD_MODE(tsf, 0600); +} + static void add_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(drop_unencrypted); @@ -515,7 +561,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata) add_sta_files(sdata); break; case NL80211_IFTYPE_ADHOC: - /* XXX */ + add_ibss_files(sdata); break; case NL80211_IFTYPE_AP: add_ap_files(sdata); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9001ff331f0a..5e5d97389bc9 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -427,36 +427,40 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, return ret; } -static inline u64 drv_get_tsf(struct ieee80211_local *local) +static inline u64 drv_get_tsf(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { u64 ret = -1ULL; might_sleep(); - trace_drv_get_tsf(local); + trace_drv_get_tsf(local, sdata); if (local->ops->get_tsf) - ret = local->ops->get_tsf(&local->hw); + ret = local->ops->get_tsf(&local->hw, &sdata->vif); trace_drv_return_u64(local, ret); return ret; } -static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) +static inline void drv_set_tsf(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u64 tsf) { might_sleep(); - trace_drv_set_tsf(local, tsf); + trace_drv_set_tsf(local, sdata, tsf); if (local->ops->set_tsf) - local->ops->set_tsf(&local->hw, tsf); + local->ops->set_tsf(&local->hw, &sdata->vif, tsf); trace_drv_return_void(local); } -static inline void drv_reset_tsf(struct ieee80211_local *local) +static inline void drv_reset_tsf(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { might_sleep(); - trace_drv_reset_tsf(local); + trace_drv_reset_tsf(local, sdata); if (local->ops->reset_tsf) - local->ops->reset_tsf(&local->hw); + local->ops->reset_tsf(&local->hw, &sdata->vif); trace_drv_return_void(local); } diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index f47b00dc7afd..07d94ff55798 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -726,35 +726,41 @@ TRACE_EVENT(drv_conf_tx, ) ); -DEFINE_EVENT(local_only_evt, drv_get_tsf, - TP_PROTO(struct ieee80211_local *local), - TP_ARGS(local) +DEFINE_EVENT(local_sdata_evt, drv_get_tsf, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) ); TRACE_EVENT(drv_set_tsf, - TP_PROTO(struct ieee80211_local *local, u64 tsf), + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u64 tsf), - TP_ARGS(local, tsf), + TP_ARGS(local, sdata, tsf), TP_STRUCT__entry( LOCAL_ENTRY + VIF_ENTRY __field(u64, tsf) ), TP_fast_assign( LOCAL_ASSIGN; + VIF_ASSIGN; __entry->tsf = tsf; ), TP_printk( - LOCAL_PR_FMT " tsf:%llu", - LOCAL_PR_ARG, (unsigned long long)__entry->tsf + LOCAL_PR_FMT VIF_PR_FMT " tsf:%llu", + LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf ) ); -DEFINE_EVENT(local_only_evt, drv_reset_tsf, - TP_PROTO(struct ieee80211_local *local), - TP_ARGS(local) +DEFINE_EVENT(local_sdata_evt, drv_reset_tsf, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) ); DEFINE_EVENT(local_only_evt, drv_tx_last_beacon, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 836b2752ecd6..7809895df8b0 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -81,7 +81,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, lockdep_assert_held(&ifibss->mtx); /* Reset own TSF to allow time synchronization work. */ - drv_reset_tsf(local); + drv_reset_tsf(local, sdata); skb = ifibss->skb; rcu_assign_pointer(ifibss->presp, NULL); @@ -382,7 +382,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, * second best option: get current TSF * (will return -1 if not supported) */ - rx_timestamp = drv_get_tsf(local); + rx_timestamp = drv_get_tsf(local, sdata); } #ifdef CONFIG_MAC80211_IBSS_DEBUG -- cgit v1.2.3 From 8a3a3c85e44d58f5af0adac74a0b866ba89a1978 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 2 Oct 2011 10:15:52 +0200 Subject: mac80211: pass vif param to conf_tx() callback tx params should be configured per interface. add ieee80211_vif param to the conf_tx callback, and change all the drivers that use this callback. The following spatch was used: @rule1@ struct ieee80211_ops ops; identifier conf_tx_op; @@ ops.conf_tx = conf_tx_op; @rule2@ identifier rule1.conf_tx_op; identifier hw, queue, params; @@ conf_tx_op ( - struct ieee80211_hw *hw, + struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) {...} Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 ++- drivers/net/wireless/ath/ath9k/main.c | 3 ++- drivers/net/wireless/ath/carl9170/main.c | 3 ++- drivers/net/wireless/b43/main.c | 3 ++- drivers/net/wireless/b43legacy/main.c | 3 ++- drivers/net/wireless/iwlegacy/iwl-core.c | 3 ++- drivers/net/wireless/iwlegacy/iwl-core.h | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-core.h | 3 ++- drivers/net/wireless/mac80211_hwsim.c | 3 ++- drivers/net/wireless/mwl8k.c | 5 +++-- drivers/net/wireless/p54/main.c | 3 ++- drivers/net/wireless/rt2x00/rt2400pci.c | 5 +++-- drivers/net/wireless/rt2x00/rt2800lib.c | 5 +++-- drivers/net/wireless/rt2x00/rt2800lib.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 ++- drivers/net/wireless/rt2x00/rt61pci.c | 5 +++-- drivers/net/wireless/rt2x00/rt73usb.c | 5 +++-- drivers/net/wireless/rtl818x/rtl8187/dev.c | 3 ++- drivers/net/wireless/rtlwifi/core.c | 3 ++- drivers/net/wireless/wl1251/main.c | 3 ++- drivers/net/wireless/wl12xx/main.c | 3 ++- drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 7 ++++--- include/net/mac80211.h | 3 ++- net/mac80211/driver-ops.h | 3 ++- 27 files changed, 61 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index bba4f6fcf7e2..6ed4c0717e3e 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -563,7 +563,7 @@ ath5k_get_stats(struct ieee80211_hw *hw, static int -ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, +ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 17dbbd9d2f53..0b9a0e8a4958 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1352,7 +1352,8 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, return ret; } -static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath9k_htc_priv *priv = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0ebf7321df12..988318665758 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1842,7 +1842,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, } } -static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int ath9k_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 8b780d6d470f..beca71073e9b 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1305,7 +1305,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, return 0; } -static int carl9170_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int carl9170_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *param) { struct ar9170 *ar = hw->priv; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 43400fb62e1c..7cf4125a1624 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3559,7 +3559,8 @@ static void b43_qos_init(struct b43_wldev *dev) b43dbg(dev->wl, "QoS enabled\n"); } -static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, +static int b43_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 468d1836548e..a3b72cd72c66 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2466,7 +2466,8 @@ out: } } -static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { return 0; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 8928d47432df..2bd5659310d7 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -1250,7 +1250,8 @@ void iwl_legacy_clear_isr_stats(struct iwl_priv *priv) memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); } -int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index b2df01c8f8f5..d1271fe07d4b 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -286,7 +286,8 @@ struct iwl_cfg { ***************************/ struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg); -int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw); void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index fc400bb2bdff..0725603dbf1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1123,8 +1123,9 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) &statistics_cmd); } -int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) +int iwl_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e55ffad83950..db50b650756c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -236,7 +236,8 @@ struct iwl_cfg { * L i b * ***************************/ -int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 34b79fc91e39..68455a2307cb 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -970,7 +970,8 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, } static int mac80211_hwsim_conf_tx( - struct ieee80211_hw *hw, u16 queue, + struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { wiphy_debug(hw->wiphy, diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ea1395aafa39..995695c28d5c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -4915,7 +4915,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, return ret; } -static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int mwl8k_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mwl8k_priv *priv = hw->priv; @@ -5462,7 +5463,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) goto fail; for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { - rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); + rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]); if (rc) goto fail; } diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 726a9343f514..ad9ae04d07aa 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -404,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev, p54_set_groupfilter(priv); } -static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, +static int p54_conf_tx(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 7e9272b8f01d..3a6b40239bc1 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1648,7 +1648,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int rt2400pci_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1661,7 +1662,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, if (queue != 0) return -EINVAL; - if (rt2x00mac_conf_tx(hw, queue, params)) + if (rt2x00mac_conf_tx(hw, vif, queue, params)) return -EINVAL; /* diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9688dd0a7ebd..3f183a15186e 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4398,7 +4398,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold); -int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2800_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -4414,7 +4415,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 6de128e9c612..8c3c281904fe 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -197,7 +197,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev); void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, u16 *iv16); int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2800_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params); u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index cbf8eb334e96..2ec5c00235e6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1299,7 +1299,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cef1c878c37e..bf0acff07807 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -713,7 +713,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 6b6a8e2dcddc..bf55b4a311e3 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2883,7 +2883,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +static int rt61pci_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2899,7 +2900,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6f51e39f5595..cfb19dbb0a67 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2222,7 +2222,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +static int rt73usb_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2238,7 +2239,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index f5afa155ce91..24873b55b55c 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -1241,7 +1241,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); } -static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, +static int rtl8187_conf_tx(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rtl8187_priv *priv = dev->priv; diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 21e40f62a8d7..3f0f056fae9c 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -504,7 +504,8 @@ static int _rtl_get_hal_qnum(u16 queue) *for mac80211 VO=0, VI=1, BE=2, BK=3 *for rtl819x BE=0, BK=1, VI=2, VO=3 */ -static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int rtl_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *param) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index a14a48c99cdc..ba3268ea81fe 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -1158,7 +1158,8 @@ static struct ieee80211_channel wl1251_channels[] = { { .hw_value = 13, .center_freq = 2472}, }; -static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int wl1251_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { enum wl1251_acx_ps_scheme ps_scheme; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7d409b0f3357..e2d6edd2fcd2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3744,7 +3744,8 @@ out: mutex_unlock(&wl->mutex); } -static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int wl1271_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct wl1271 *wl = hw->priv; diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c index 315dd91800b6..6d71cba3a0a5 100644 --- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c @@ -141,8 +141,9 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta); -static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params); +static int brcms_ops_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params); static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -556,7 +557,7 @@ brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } static int -brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, +brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct brcms_info *wl = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 135e897b61c7..cd108dfa1952 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2152,7 +2152,8 @@ struct ieee80211_ops { struct ieee80211_sta *sta); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, struct ieee80211_sta *sta); - int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, + int (*conf_tx)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 68721d379fe1..5f165d7eb2db 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -423,7 +423,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local, trace_drv_conf_tx(local, sdata, queue, params); if (local->ops->conf_tx) - ret = local->ops->conf_tx(&local->hw, queue, params); + ret = local->ops->conf_tx(&local->hw, &sdata->vif, + queue, params); trace_drv_return_int(local, ret); return ret; } -- cgit v1.2.3 From 4b29886feb072427df80ca6395b2b11a09245eaf Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 3 Oct 2011 12:06:36 +0200 Subject: wl12xx: configure rate policy for p2p operations p2p packets should go out only with OFDM rates. Configure a new rate policy that will (later) be used during p2p_find (when the p2p_cli / p2p_go interfaces are in use, we won't have to use this policy, as the configured rates should already be OFDM-only). Additionally, update CONF_TX_MAX_RATE_CLASSES to reflect the current value from the fw api. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/acx.c | 16 ++++++++++++++++ drivers/net/wireless/wl12xx/acx.h | 1 + drivers/net/wireless/wl12xx/conf.h | 6 +++++- 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 399849eeb247..ca044a743191 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -777,7 +777,23 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl) acx->rate_policy.long_retry_limit = c->long_retry_limit; acx->rate_policy.aflags = c->aflags; + 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; + } + /* + * configure one rate class for basic p2p operations. + * (p2p packets should always go out with OFDM rates, even + * if we are currently connected to 11b AP) + */ + acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE_P2P); + acx->rate_policy.enabled_rates = + cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 556ee4e282d5..e3f93b4b3429 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -656,6 +656,7 @@ struct acx_rate_class { #define ACX_TX_BASIC_RATE 0 #define ACX_TX_AP_FULL_RATE 1 +#define ACX_TX_BASIC_RATE_P2P 2 #define ACX_TX_AP_MODE_MGMT_RATE 4 #define ACX_TX_AP_MODE_BCST_RATE 5 struct acx_rate_policy { diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 6a6805c3cc74..04bb8fbf93f9 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -416,13 +416,17 @@ struct conf_rx_settings { u8 queue_type; }; -#define CONF_TX_MAX_RATE_CLASSES 8 +#define CONF_TX_MAX_RATE_CLASSES 10 #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 +/* basic rates for p2p operations (probe req/resp, etc.) */ +#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \ + CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS) + /* * Rates supported for data packets when operating as AP. Note the absence * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop -- cgit v1.2.3 From c9e79a4714493df6508d8346195ea30fb69b7783 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 27 Sep 2011 16:22:35 +0300 Subject: wl12xx: set max_sched_scan_ie_len correctly The wiphy max_sched_scan_ie_len attribute was not set correctly and remained as 0, so when IEs were being passed in a scheduled scan, we were returning -EINVAL. Fix this by setting the attribute properly. Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e2d6edd2fcd2..b1b405b576cc 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -4679,6 +4679,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - sizeof(struct ieee80211_header); + wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - + sizeof(struct ieee80211_header); + wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; /* make sure all our channels fit in the scanned_ch bitmask */ -- cgit v1.2.3 From 6d158ff38d8c99dc1bee775a66451168316692f4 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Thu, 8 Sep 2011 13:01:33 +0300 Subject: wl12xx: Add support for HW channel switch The wl12xx FW supports HW channel switch. If we don't use it, sometimes the firmware gets confused when recalibrating to the new channel, causing RX problems. This commit adds HW channel switch support by implementing the channell_switch op. Signed-off-by: Shahar Levi [added one comment, remove the tx_flush and rephrased the commit message] Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 3 +- drivers/net/wireless/wl12xx/cmd.c | 58 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/cmd.h | 20 +++++++++++++ drivers/net/wireless/wl12xx/event.c | 15 ++++++++++ drivers/net/wireless/wl12xx/main.c | 37 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl12xx.h | 1 + 6 files changed, 133 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 6d5664bfc37d..9b400270397b 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -503,7 +503,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) BA_SESSION_RX_CONSTRAINT_EVENT_ID | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | INACTIVE_STA_EVENT_ID | - MAX_TX_RETRY_EVENT_ID; + MAX_TX_RETRY_EVENT_ID | + CHANNEL_SWITCH_COMPLETE_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 287fe95ecb40..8c963a6bb0a5 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1700,3 +1700,61 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id) out: return ret; } + +int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct ieee80211_channel_switch *ch_switch) +{ + struct wl12xx_cmd_channel_switch *cmd; + int ret; + + wl1271_debug(DEBUG_ACX, "cmd channel switch"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = ch_switch->channel->hw_value; + cmd->switch_time = ch_switch->count; + cmd->tx_suspend = ch_switch->block_tx; + cmd->flush = 0; /* this value is ignored by the FW */ + + ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send channel switch command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) +{ + struct wl12xx_cmd_stop_channel_switch *cmd; + int ret; + + wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to stop channel switch 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 index 8e4d11ec0c55..b7bd42769aa7 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -79,6 +79,9 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); +int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct ieee80211_channel_switch *ch_switch); +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -677,4 +680,21 @@ struct wl12xx_cmd_stop_fwlog { struct wl1271_cmd_header header; } __packed; +struct wl12xx_cmd_channel_switch { + struct wl1271_cmd_header header; + + /* The new serving channel */ + u8 channel; + /* Relative time of the serving channel switch in TBTT units */ + u8 switch_time; + /* 1: Suspend TX till switch time; 0: Do not suspend TX */ + u8 tx_suspend; + /* 1: Flush TX at switch time; 0: Do not flush */ + u8 flush; +} __packed; + +struct wl12xx_cmd_stop_channel_switch { + struct wl1271_cmd_header header; +} __packed; + #endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index e66db69f8d17..674ad2a9e409 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -300,6 +300,21 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_stop_ba_event(wl); } + if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) { + wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " + "status = 0x%x", + mbox->channel_switch_status); + /* + * That event uses for two cases: + * 1) channel switch complete with status=0 + * 2) channel switch failed status=1 + */ + if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) && + (wl->vif)) + ieee80211_chswitch_done(wl->vif, + mbox->channel_switch_status ? false : true); + } + if ((vector & DUMMY_PACKET_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index b1b405b576cc..6b8a8a339f96 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2222,6 +2222,11 @@ static int wl1271_unjoin(struct wl1271 *wl) { int ret; + if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) { + wl12xx_cmd_stop_channel_switch(wl); + ieee80211_chswitch_done(wl->vif, false); + } + /* to stop listening to a channel, we disconnect */ ret = wl12xx_cmd_role_stop_sta(wl); if (ret < 0) @@ -4130,6 +4135,37 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, return 0; } +static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) +{ + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + mutex_unlock(&wl->mutex); + ieee80211_chswitch_done(wl->vif, false); + return; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_channel_switch(wl, ch_switch); + + if (!ret) + set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -4406,6 +4442,7 @@ static const struct ieee80211_ops wl1271_ops = { .ampdu_action = wl1271_op_ampdu_action, .tx_frames_pending = wl1271_tx_frames_pending, .set_bitrate_mask = wl12xx_set_bitrate_mask, + .channel_switch = wl12xx_op_channel_switch, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 997f53245011..02644b4fb697 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -348,6 +348,7 @@ enum wl12xx_flags { WL1271_FLAG_SOFT_GEMINI, WL1271_FLAG_RX_STREAMING_STARTED, WL1271_FLAG_RECOVERY_IN_PROGRESS, + WL1271_FLAG_CS_PROGRESS, }; struct wl1271_link { -- cgit v1.2.3 From 694440d93b9963a2c426708cb11494236c0b2552 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 5 Oct 2011 11:55:38 +0200 Subject: wl12xx: disable AP-mode-specific quirks The current wl12xx fw (7.3.0.0.77) supports both STA and AP mode, and we no longer use AP-mode-specific quirks. WL12XX_QUIRK_END_OF_TRANSACTION is still used for certain HWs, while WL12XX_QUIRK_LPD_MODE is not used anymore. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/boot.c | 3 --- drivers/net/wireless/wl12xx/cmd.c | 5 ----- drivers/net/wireless/wl12xx/main.c | 8 -------- drivers/net/wireless/wl12xx/wl12xx.h | 6 ------ 4 files changed, 22 deletions(-) (limited to 'drivers/net/wireless/wl12xx') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 9b400270397b..d4e628db76b0 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -770,9 +770,6 @@ int wl1271_load_firmware(struct wl1271 *wl) clk |= (wl->ref_clock << 1) << 4; } - if (wl->quirks & WL12XX_QUIRK_LPD_MODE) - clk |= SCRATCH_ENABLE_LPD; - wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 8c963a6bb0a5..a52299e548fa 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -134,11 +134,6 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) /* Override the REF CLK from the NVS with the one from platform data */ gen_parms->general_params.ref_clock = wl->ref_clock; - /* LPD mode enable (bits 6-7) in WL1271 AP mode only */ - if (wl->quirks & WL12XX_QUIRK_LPD_MODE) - gen_parms->general_params.general_settings |= - GENERAL_SETTINGS_DRPW_LPD; - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6b8a8a339f96..884f82b63219 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1333,14 +1333,6 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); - /* - * 'end-of-transaction flag' and 'LPD mode flag' - * should be set in wl127x AP mode only - */ - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION | - WL12XX_QUIRK_LPD_MODE); - ret = wl1271_setup(wl); if (ret < 0) goto out; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 02644b4fb697..1ec90fc7505e 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -672,12 +672,6 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); /* WL128X requires aggregated packets to be aligned to the SDIO block size */ #define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) -/* - * WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power - * consumption - */ -#define WL12XX_QUIRK_LPD_MODE BIT(3) - /* Older firmwares did not implement the FW logger over bus feature */ #define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) -- cgit v1.2.3