Commit 8715d941 authored by John W. Linville's avatar John W. Linville
parents ca994a36 51c4ed95
...@@ -6,3 +6,5 @@ wl1251_sdio-objs += sdio.o ...@@ -6,3 +6,5 @@ wl1251_sdio-objs += sdio.o
obj-$(CONFIG_WL1251) += wl1251.o obj-$(CONFIG_WL1251) += wl1251.o
obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o
obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
ccflags-y += -D__CHECK_ENDIAN__
...@@ -464,8 +464,6 @@ static int wl1251_boot_upload_nvs(struct wl1251 *wl) ...@@ -464,8 +464,6 @@ static int wl1251_boot_upload_nvs(struct wl1251 *wl)
val = (nvs_ptr[0] | (nvs_ptr[1] << 8) val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
val = cpu_to_le32(val);
wl1251_debug(DEBUG_BOOT, wl1251_debug(DEBUG_BOOT,
"nvs write table 0x%x: 0x%x", "nvs write table 0x%x: 0x%x",
nvs_start, val); nvs_start, val);
......
...@@ -36,16 +36,15 @@ ...@@ -36,16 +36,15 @@
static inline u32 wl1251_read32(struct wl1251 *wl, int addr) static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
{ {
u32 response; wl->if_ops->read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
wl->if_ops->read(wl, addr, &response, sizeof(u32));
return response; return le32_to_cpu(wl->buffer_32);
} }
static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
{ {
wl->if_ops->write(wl, addr, &val, sizeof(u32)); wl->buffer_32 = cpu_to_le32(val);
wl->if_ops->write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32));
} }
static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr) static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr)
......
...@@ -380,7 +380,7 @@ struct wl1251 { ...@@ -380,7 +380,7 @@ struct wl1251 {
struct wl1251_stats stats; struct wl1251_stats stats;
struct wl1251_debugfs debugfs; struct wl1251_debugfs debugfs;
u32 buffer_32; __le32 buffer_32;
u32 buffer_cmd; u32 buffer_cmd;
u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
struct wl1251_rx_descriptor *rx_descriptor; struct wl1251_rx_descriptor *rx_descriptor;
......
...@@ -11,3 +11,5 @@ obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o ...@@ -11,3 +11,5 @@ obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
# small builtin driver bit # small builtin driver bit
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
ccflags-y += -D__CHECK_ENDIAN__
...@@ -34,12 +34,14 @@ ...@@ -34,12 +34,14 @@
#include "reg.h" #include "reg.h"
#include "ps.h" #include "ps.h"
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif) int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 wake_up_event, u8 listen_interval)
{ {
struct acx_wake_up_condition *wake_up; struct acx_wake_up_condition *wake_up;
int ret; int ret;
wl1271_debug(DEBUG_ACX, "acx wake up conditions"); wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)",
wake_up_event, listen_interval);
wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
if (!wake_up) { if (!wake_up) {
...@@ -48,8 +50,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -48,8 +50,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
} }
wake_up->role_id = wlvif->role_id; wake_up->role_id = wlvif->role_id;
wake_up->wake_up_event = wl->conf.conn.wake_up_event; wake_up->wake_up_event = wake_up_event;
wake_up->listen_interval = wl->conf.conn.listen_interval; wake_up->listen_interval = listen_interval;
ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
wake_up, sizeof(*wake_up)); wake_up, sizeof(*wake_up));
...@@ -1459,9 +1461,10 @@ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, ...@@ -1459,9 +1461,10 @@ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
return ret; return ret;
} }
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u64 *mactime)
{ {
struct wl1271_acx_fw_tsf_information *tsf_info; struct wl12xx_acx_fw_tsf_information *tsf_info;
int ret; int ret;
tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
...@@ -1470,6 +1473,8 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) ...@@ -1470,6 +1473,8 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
goto out; goto out;
} }
tsf_info->role_id = wlvif->role_id;
ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
tsf_info, sizeof(*tsf_info)); tsf_info, sizeof(*tsf_info));
if (ret < 0) { if (ret < 0) {
......
...@@ -995,15 +995,17 @@ struct wl1271_acx_ba_receiver_setup { ...@@ -995,15 +995,17 @@ struct wl1271_acx_ba_receiver_setup {
u8 padding[2]; u8 padding[2];
} __packed; } __packed;
struct wl1271_acx_fw_tsf_information { struct wl12xx_acx_fw_tsf_information {
struct acx_header header; struct acx_header header;
u8 role_id;
u8 padding1[3];
__le32 current_tsf_high; __le32 current_tsf_high;
__le32 current_tsf_low; __le32 current_tsf_low;
__le32 last_bttt_high; __le32 last_bttt_high;
__le32 last_tbtt_low; __le32 last_tbtt_low;
u8 last_dtim_count; u8 last_dtim_count;
u8 padding[3]; u8 padding2[3];
} __packed; } __packed;
struct wl1271_acx_ps_rx_streaming { struct wl1271_acx_ps_rx_streaming {
...@@ -1151,79 +1153,81 @@ struct wl12xx_acx_config_hangover { ...@@ -1151,79 +1153,81 @@ struct wl12xx_acx_config_hangover {
} __packed; } __packed;
enum { enum {
ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_WAKE_UP_CONDITIONS = 0x0000,
ACX_MEM_CFG = 0x0003, ACX_MEM_CFG = 0x0001,
ACX_SLOT = 0x0004, ACX_SLOT = 0x0002,
ACX_AC_CFG = 0x0007, ACX_AC_CFG = 0x0003,
ACX_MEM_MAP = 0x0008, ACX_MEM_MAP = 0x0004,
ACX_AID = 0x000A, ACX_AID = 0x0005,
ACX_MEDIUM_USAGE = 0x000F, ACX_MEDIUM_USAGE = 0x0006,
ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ ACX_STATISTICS = 0x0007,
ACX_STATISTICS = 0x0013, /* Debug API */ ACX_PWR_CONSUMPTION_STATISTICS = 0x0008,
ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, ACX_TID_CFG = 0x0009,
ACX_FEATURE_CFG = 0x0015, ACX_PS_RX_STREAMING = 0x000A,
ACX_TID_CFG = 0x001A, ACX_BEACON_FILTER_OPT = 0x000B,
ACX_PS_RX_STREAMING = 0x001B, ACX_NOISE_HIST = 0x000C,
ACX_BEACON_FILTER_OPT = 0x001F, ACX_HDK_VERSION = 0x000D,
ACX_NOISE_HIST = 0x0021, ACX_PD_THRESHOLD = 0x000E,
ACX_HDK_VERSION = 0x0022, /* ??? */ ACX_TX_CONFIG_OPT = 0x000F,
ACX_PD_THRESHOLD = 0x0023, ACX_CCA_THRESHOLD = 0x0010,
ACX_TX_CONFIG_OPT = 0x0024, ACX_EVENT_MBOX_MASK = 0x0011,
ACX_CCA_THRESHOLD = 0x0025, ACX_CONN_MONIT_PARAMS = 0x0012,
ACX_EVENT_MBOX_MASK = 0x0026, ACX_DISABLE_BROADCASTS = 0x0013,
ACX_CONN_MONIT_PARAMS = 0x002D, ACX_BCN_DTIM_OPTIONS = 0x0014,
ACX_BCN_DTIM_OPTIONS = 0x0031, ACX_SG_ENABLE = 0x0015,
ACX_SG_ENABLE = 0x0032, ACX_SG_CFG = 0x0016,
ACX_SG_CFG = 0x0033, ACX_FM_COEX_CFG = 0x0017,
ACX_FM_COEX_CFG = 0x0034, ACX_BEACON_FILTER_TABLE = 0x0018,
ACX_BEACON_FILTER_TABLE = 0x0038, ACX_ARP_IP_FILTER = 0x0019,
ACX_ARP_IP_FILTER = 0x0039, ACX_ROAMING_STATISTICS_TBL = 0x001A,
ACX_ROAMING_STATISTICS_TBL = 0x003B, ACX_RATE_POLICY = 0x001B,
ACX_RATE_POLICY = 0x003D, ACX_CTS_PROTECTION = 0x001C,
ACX_CTS_PROTECTION = 0x003E, ACX_SLEEP_AUTH = 0x001D,
ACX_SLEEP_AUTH = 0x003F, ACX_PREAMBLE_TYPE = 0x001E,
ACX_PREAMBLE_TYPE = 0x0040, ACX_ERROR_CNT = 0x001F,
ACX_ERROR_CNT = 0x0041, ACX_IBSS_FILTER = 0x0020,
ACX_IBSS_FILTER = 0x0044, ACX_SERVICE_PERIOD_TIMEOUT = 0x0021,
ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, ACX_TSF_INFO = 0x0022,
ACX_TSF_INFO = 0x0046, ACX_CONFIG_PS_WMM = 0x0023,
ACX_CONFIG_PS_WMM = 0x0049, ACX_ENABLE_RX_DATA_FILTER = 0x0024,
ACX_ENABLE_RX_DATA_FILTER = 0x004A, ACX_SET_RX_DATA_FILTER = 0x0025,
ACX_SET_RX_DATA_FILTER = 0x004B, ACX_GET_DATA_FILTER_STATISTICS = 0x0026,
ACX_GET_DATA_FILTER_STATISTICS = 0x004C, ACX_RX_CONFIG_OPT = 0x0027,
ACX_RX_CONFIG_OPT = 0x004E, ACX_FRAG_CFG = 0x0028,
ACX_FRAG_CFG = 0x004F, ACX_BET_ENABLE = 0x0029,
ACX_BET_ENABLE = 0x0050, ACX_RSSI_SNR_TRIGGER = 0x002A,
ACX_RSSI_SNR_TRIGGER = 0x0051, ACX_RSSI_SNR_WEIGHTS = 0x002B,
ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_KEEP_ALIVE_MODE = 0x002C,
ACX_KEEP_ALIVE_MODE = 0x0053, ACX_SET_KEEP_ALIVE_CONFIG = 0x002D,
ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, ACX_BA_SESSION_INIT_POLICY = 0x002E,
ACX_BA_SESSION_INIT_POLICY = 0x0055, ACX_BA_SESSION_RX_SETUP = 0x002F,
ACX_BA_SESSION_RX_SETUP = 0x0056, ACX_PEER_HT_CAP = 0x0030,
ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0031,
ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0032,
ACX_COEX_ACTIVITY = 0x0059, ACX_BURST_MODE = 0x0033,
ACX_BURST_MODE = 0x005C, ACX_SET_RATE_MGMT_PARAMS = 0x0034,
ACX_SET_RATE_MGMT_PARAMS = 0x005D, ACX_GET_RATE_MGMT_PARAMS = 0x0035,
ACX_SET_RATE_ADAPT_PARAMS = 0x0060, ACX_SET_RATE_ADAPT_PARAMS = 0x0036,
ACX_SET_DCO_ITRIM_PARAMS = 0x0061, ACX_SET_DCO_ITRIM_PARAMS = 0x0037,
ACX_GEN_FW_CMD = 0x0070, ACX_GEN_FW_CMD = 0x0038,
ACX_HOST_IF_CFG_BITMAP = 0x0071, ACX_HOST_IF_CFG_BITMAP = 0x0039,
ACX_MAX_TX_FAILURE = 0x0072, ACX_MAX_TX_FAILURE = 0x003A,
ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073, ACX_UPDATE_INCONNECTION_STA_LIST = 0x003B,
DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_RX_MSDU_LIFE_TIME = 0x003C,
DOT11_CUR_TX_PWR = 0x100D, DOT11_CUR_TX_PWR = 0x003D,
DOT11_RX_DOT11_MODE = 0x1012, DOT11_RTS_THRESHOLD = 0x003E,
DOT11_RTS_THRESHOLD = 0x1013, DOT11_GROUP_ADDRESS_TBL = 0x003F,
DOT11_GROUP_ADDRESS_TBL = 0x1014, ACX_PM_CONFIG = 0x0040,
ACX_PM_CONFIG = 0x1016, ACX_CONFIG_PS = 0x0041,
ACX_CONFIG_PS = 0x1017, ACX_CONFIG_HANGOVER = 0x0042,
ACX_CONFIG_HANGOVER = 0x1018, ACX_FEATURE_CFG = 0x0043,
ACX_PROTECTION_CFG = 0x0044,
}; };
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, int wl1271_acx_wake_up_conditions(struct wl1271 *wl,
struct wl12xx_vif *wlvif); struct wl12xx_vif *wlvif,
u8 wake_up_event, u8 listen_interval);
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
int power); int power);
...@@ -1296,7 +1300,8 @@ int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, ...@@ -1296,7 +1300,8 @@ int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
struct wl12xx_vif *wlvif); struct wl12xx_vif *wlvif);
int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
u16 ssn, bool enable, u8 peer_hlid); u16 ssn, bool enable, u8 peer_hlid);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
bool enable); bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
......
...@@ -33,65 +33,6 @@ ...@@ -33,65 +33,6 @@
#include "event.h" #include "event.h"
#include "rx.h" #include "rx.h"
static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
.mem = {
.start = 0x00000000,
.size = 0x000177c0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x00008800
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
},
},
[PART_WORK] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x0000a000
},
.mem2 = {
.start = 0x003004f8,
.size = 0x00000004
},
.mem3 = {
.start = 0x00040404,
.size = 0x00000000
},
},
[PART_DRPW] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = DRPW_BASE,
.size = 0x00006000
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
}
}
};
static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
{ {
u32 cpu_ctrl; u32 cpu_ctrl;
...@@ -181,13 +122,13 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -181,13 +122,13 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
return -ENOMEM; return -ENOMEM;
} }
memcpy(&partition, &part_table[PART_DOWN], sizeof(partition)); memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition));
partition.mem.start = dest; partition.mem.start = dest;
wl1271_set_partition(wl, &partition); wl1271_set_partition(wl, &partition);
/* 10.1 set partition limit and chunk num */ /* 10.1 set partition limit and chunk num */
chunk_num = 0; chunk_num = 0;
partition_limit = part_table[PART_DOWN].mem.size; partition_limit = wl12xx_part_table[PART_DOWN].mem.size;
while (chunk_num < fw_data_len / CHUNK_SIZE) { while (chunk_num < fw_data_len / CHUNK_SIZE) {
/* 10.2 update partition, if needed */ /* 10.2 update partition, if needed */
...@@ -195,7 +136,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -195,7 +136,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
if (addr > partition_limit) { if (addr > partition_limit) {
addr = dest + chunk_num * CHUNK_SIZE; addr = dest + chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE + partition_limit = chunk_num * CHUNK_SIZE +
part_table[PART_DOWN].mem.size; wl12xx_part_table[PART_DOWN].mem.size;
partition.mem.start = addr; partition.mem.start = addr;
wl1271_set_partition(wl, &partition); wl1271_set_partition(wl, &partition);
} }
...@@ -317,12 +258,12 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -317,12 +258,12 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
} }
/* update current MAC address to NVS */ /* update current MAC address to NVS */
nvs_ptr[11] = wl->mac_addr[0]; nvs_ptr[11] = wl->addresses[0].addr[0];
nvs_ptr[10] = wl->mac_addr[1]; nvs_ptr[10] = wl->addresses[0].addr[1];
nvs_ptr[6] = wl->mac_addr[2]; nvs_ptr[6] = wl->addresses[0].addr[2];
nvs_ptr[5] = wl->mac_addr[3]; nvs_ptr[5] = wl->addresses[0].addr[3];
nvs_ptr[4] = wl->mac_addr[4]; nvs_ptr[4] = wl->addresses[0].addr[4];
nvs_ptr[3] = wl->mac_addr[5]; nvs_ptr[3] = wl->addresses[0].addr[5];
/* /*
* Layout before the actual NVS tables: * Layout before the actual NVS tables:
...@@ -383,7 +324,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -383,7 +324,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
nvs_len -= nvs_ptr - (u8 *)wl->nvs; nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* Now we must set the partition correctly */ /* Now we must set the partition correctly */
wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */ /* Copy the NVS tables to a new block to ensure alignment */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
...@@ -492,7 +433,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -492,7 +433,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */ /* set the working partition to its "running" mode offset */
wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
wl->cmd_box_addr, wl->event_box_addr); wl->cmd_box_addr, wl->event_box_addr);
...@@ -507,8 +448,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -507,8 +448,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
/* unmask required mbox events */ /* unmask required mbox events */
wl->event_mask = BSS_LOSE_EVENT_ID | wl->event_mask = BSS_LOSE_EVENT_ID |
SCAN_COMPLETE_EVENT_ID | SCAN_COMPLETE_EVENT_ID |
PS_REPORT_EVENT_ID | ROLE_STOP_COMPLETE_EVENT_ID |
DISCONNECT_EVENT_COMPLETE_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID | RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID |
...@@ -547,19 +487,6 @@ static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) ...@@ -547,19 +487,6 @@ static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
return 0; return 0;
} }
static void wl1271_boot_hw_version(struct wl1271 *wl)
{
u32 fuse;
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;
}
static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
{ {
u16 spare_reg; u16 spare_reg;
...@@ -698,7 +625,7 @@ static int wl127x_boot_clk(struct wl1271 *wl) ...@@ -698,7 +625,7 @@ static int wl127x_boot_clk(struct wl1271 *wl)
u32 pause; u32 pause;
u32 clk; u32 clk;
if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3) if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
if (wl->ref_clock == CONF_REF_CLK_19_2_E || if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
...@@ -753,8 +680,6 @@ int wl1271_load_firmware(struct wl1271 *wl) ...@@ -753,8 +680,6 @@ int wl1271_load_firmware(struct wl1271 *wl)
u32 tmp, clk; u32 tmp, clk;
int selected_clock = -1; int selected_clock = -1;
wl1271_boot_hw_version(wl);
if (wl->chip.id == CHIP_ID_1283_PG20) { if (wl->chip.id == CHIP_ID_1283_PG20) {
ret = wl128x_boot_clk(wl, &selected_clock); ret = wl128x_boot_clk(wl, &selected_clock);
if (ret < 0) if (ret < 0)
...@@ -769,7 +694,7 @@ int wl1271_load_firmware(struct wl1271 *wl) ...@@ -769,7 +694,7 @@ int wl1271_load_firmware(struct wl1271 *wl)
wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500); udelay(500);
wl1271_set_partition(wl, &part_table[PART_DRPW]); wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
/* Read-modify-write DRPW_SCRATCH_START register (see next state) /* Read-modify-write DRPW_SCRATCH_START register (see next state)
to be used by DRPw FW. The RTRIM value will be added by the FW to be used by DRPw FW. The RTRIM value will be added by the FW
...@@ -788,7 +713,7 @@ int wl1271_load_firmware(struct wl1271 *wl) ...@@ -788,7 +713,7 @@ int wl1271_load_firmware(struct wl1271 *wl)
wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
/* Disable interrupts */ /* Disable interrupts */
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
......
...@@ -55,16 +55,6 @@ struct wl1271_static_data { ...@@ -55,16 +55,6 @@ struct wl1271_static_data {
#define OCP_REG_CLK_POLARITY 0x0cb2 #define OCP_REG_CLK_POLARITY 0x0cb2
#define OCP_REG_CLK_PULL 0x0cb4 #define OCP_REG_CLK_PULL 0x0cb4
#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
#define PG_MAJOR_VER_MASK 0x3
#define PG_MAJOR_VER_OFFSET 0x0
#define PG_MINOR_VER_MASK 0xc
#define PG_MINOR_VER_OFFSET 0x2
#define CMD_MBOX_ADDRESS 0x407B4 #define CMD_MBOX_ADDRESS 0x407B4
#define POLARITY_LOW BIT(1) #define POLARITY_LOW BIT(1)
......
...@@ -566,7 +566,7 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, ...@@ -566,7 +566,7 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl,
goto out_free; goto out_free;
} }
ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID);
if (ret < 0) { if (ret < 0) {
wl1271_error("cmd role stop dev event completion error"); wl1271_error("cmd role stop dev event completion error");
goto out_free; goto out_free;
...@@ -715,6 +715,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -715,6 +715,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.dtim_interval = bss_conf->dtim_period;
cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
/* FIXME: Change when adding DFS */
cmd->ap.reset_tsf = 1; /* By default reset AP TSF */
cmd->channel = wlvif->channel; cmd->channel = wlvif->channel;
if (!bss_conf->hidden_ssid) { if (!bss_conf->hidden_ssid) {
...@@ -994,7 +996,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) ...@@ -994,7 +996,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
} }
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 ps_mode) u8 ps_mode, u16 auto_ps_timeout)
{ {
struct wl1271_cmd_ps_params *ps_params = NULL; struct wl1271_cmd_ps_params *ps_params = NULL;
int ret = 0; int ret = 0;
...@@ -1009,6 +1011,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1009,6 +1011,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
ps_params->role_id = wlvif->role_id; ps_params->role_id = wlvif->role_id;
ps_params->ps_mode = ps_mode; ps_params->ps_mode = ps_mode;
ps_params->auto_ps_timeout = auto_ps_timeout;
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params), 0); sizeof(*ps_params), 0);
...@@ -1022,13 +1025,15 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1022,13 +1025,15 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
return ret; return ret;
} }
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
void *buf, size_t buf_len, int index, u32 rates) u16 template_id, void *buf, size_t buf_len,
int index, u32 rates)
{ {
struct wl1271_cmd_template_set *cmd; struct wl1271_cmd_template_set *cmd;
int ret = 0; int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)",
template_id, role_id);
WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
...@@ -1039,6 +1044,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, ...@@ -1039,6 +1044,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
goto out; goto out;
} }
/* during initialization wlvif is NULL */
cmd->role_id = role_id;
cmd->len = cpu_to_le16(buf_len); cmd->len = cpu_to_le16(buf_len);
cmd->template_type = template_id; cmd->template_type = template_id;
cmd->enabled_rates = cpu_to_le32(rates); cmd->enabled_rates = cpu_to_le32(rates);
...@@ -1082,7 +1089,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -1082,7 +1089,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif)
ptr = skb->data; ptr = skb->data;
} }
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_NULL_DATA, ptr, size, 0,
wlvif->basic_rate); wlvif->basic_rate);
out: out:
...@@ -1105,7 +1113,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, ...@@ -1105,7 +1113,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
if (!skb) if (!skb)
goto out; goto out;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV,
skb->data, skb->len, skb->data, skb->len,
CMD_TEMPL_KLV_IDX_NULL_DATA, CMD_TEMPL_KLV_IDX_NULL_DATA,
wlvif->basic_rate); wlvif->basic_rate);
...@@ -1130,7 +1138,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1130,7 +1138,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (!skb) if (!skb)
goto out; goto out;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_PS_POLL, skb->data,
skb->len, 0, wlvif->basic_rate_set); skb->len, 0, wlvif->basic_rate_set);
out: out:
...@@ -1138,9 +1147,10 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1138,9 +1147,10 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
return ret; return ret;
} }
int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 role_id, u8 band,
const u8 *ssid, size_t ssid_len, const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band) const u8 *ie, size_t ie_len)
{ {
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1158,10 +1168,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1158,10 +1168,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
if (band == IEEE80211_BAND_2GHZ) if (band == IEEE80211_BAND_2GHZ)
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, ret = wl1271_cmd_template_set(wl, role_id,
CMD_TEMPL_CFG_PROBE_REQ_2_4,
skb->data, skb->len, 0, rate); skb->data, skb->len, 0, rate);
else else
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, ret = wl1271_cmd_template_set(wl, role_id,
CMD_TEMPL_CFG_PROBE_REQ_5,
skb->data, skb->len, 0, rate); skb->data, skb->len, 0, rate);
out: out:
...@@ -1186,10 +1198,12 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, ...@@ -1186,10 +1198,12 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
if (wlvif->band == IEEE80211_BAND_2GHZ) if (wlvif->band == IEEE80211_BAND_2GHZ)
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_CFG_PROBE_REQ_2_4,
skb->data, skb->len, 0, rate); skb->data, skb->len, 0, rate);
else else
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_CFG_PROBE_REQ_5,
skb->data, skb->len, 0, rate); skb->data, skb->len, 0, rate);
if (ret < 0) if (ret < 0)
...@@ -1199,32 +1213,34 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, ...@@ -1199,32 +1213,34 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
return skb; return skb;
} }
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
__be32 ip_addr)
{ {
int ret; int ret, extra;
u16 fc;
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
struct wl12xx_arp_rsp_template tmpl; struct sk_buff *skb;
struct wl12xx_arp_rsp_template *tmpl;
struct ieee80211_hdr_3addr *hdr; struct ieee80211_hdr_3addr *hdr;
struct arphdr *arp_hdr; struct arphdr *arp_hdr;
memset(&tmpl, 0, sizeof(tmpl)); skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) +
WL1271_EXTRA_SPACE_MAX);
if (!skb) {
wl1271_error("failed to allocate buffer for arp rsp template");
return -ENOMEM;
}
/* mac80211 header */ skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
hdr = &tmpl.hdr;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
IEEE80211_STYPE_DATA | memset(tmpl, 0, sizeof(tmpl));
IEEE80211_FCTL_TODS);
memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
memcpy(hdr->addr2, vif->addr, ETH_ALEN);
memset(hdr->addr3, 0xff, ETH_ALEN);
/* llc layer */ /* llc layer */
memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
tmpl.llc_type = cpu_to_be16(ETH_P_ARP); tmpl->llc_type = cpu_to_be16(ETH_P_ARP);
/* arp header */ /* arp header */
arp_hdr = &tmpl.arp_hdr; arp_hdr = &tmpl->arp_hdr;
arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_hln = ETH_ALEN;
...@@ -1232,13 +1248,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1232,13 +1248,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
/* arp payload */ /* arp payload */
memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN); memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN);
tmpl.sender_ip = ip_addr; tmpl->sender_ip = wlvif->ip_addr;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, /* encryption space */
&tmpl, sizeof(tmpl), 0, switch (wlvif->encryption_type) {
wlvif->basic_rate); case KEY_TKIP:
extra = WL1271_EXTRA_SPACE_TKIP;
break;
case KEY_AES:
extra = WL1271_EXTRA_SPACE_AES;
break;
case KEY_NONE:
case KEY_WEP:
case KEY_GEM:
extra = 0;
break;
default:
wl1271_warning("Unknown encryption type: %d",
wlvif->encryption_type);
ret = -EINVAL;
goto out;
}
if (extra) {
u8 *space = skb_push(skb, extra);
memset(space, 0, extra);
}
/* QoS header - BE */
if (wlvif->sta.qos)
memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16));
/* mac80211 header */
hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr));
memset(hdr, 0, sizeof(hdr));
fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
if (wlvif->sta.qos)
fc |= IEEE80211_STYPE_QOS_DATA;
else
fc |= IEEE80211_STYPE_DATA;
if (wlvif->encryption_type != KEY_NONE)
fc |= IEEE80211_FCTL_PROTECTED;
hdr->frame_control = cpu_to_le16(fc);
memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
memcpy(hdr->addr2, vif->addr, ETH_ALEN);
memset(hdr->addr3, 0xff, ETH_ALEN);
ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP,
skb->data, skb->len, 0,
wlvif->basic_rate);
out:
dev_kfree_skb(skb);
return ret; return ret;
} }
...@@ -1260,7 +1322,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) ...@@ -1260,7 +1322,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif)
/* FIXME: not sure what priority to use here */ /* FIXME: not sure what priority to use here */
template.qos_ctrl = cpu_to_le16(0); template.qos_ctrl = cpu_to_le16(0);
return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, return wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_QOS_NULL_DATA, &template,
sizeof(template), 0, sizeof(template), 0,
wlvif->basic_rate); wlvif->basic_rate);
} }
...@@ -1744,6 +1807,7 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id) ...@@ -1744,6 +1807,7 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id)
} }
int wl12xx_cmd_channel_switch(struct wl1271 *wl, int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch) struct ieee80211_channel_switch *ch_switch)
{ {
struct wl12xx_cmd_channel_switch *cmd; struct wl12xx_cmd_channel_switch *cmd;
...@@ -1757,10 +1821,13 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl, ...@@ -1757,10 +1821,13 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl,
goto out; goto out;
} }
cmd->role_id = wlvif->role_id;
cmd->channel = ch_switch->channel->hw_value; cmd->channel = ch_switch->channel->hw_value;
cmd->switch_time = ch_switch->count; cmd->switch_time = ch_switch->count;
cmd->tx_suspend = ch_switch->block_tx; cmd->stop_tx = ch_switch->block_tx;
cmd->flush = 0; /* this value is ignored by the FW */
/* FIXME: control from mac80211 in the future */
cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */
ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
if (ret < 0) { if (ret < 0) {
......
...@@ -51,22 +51,23 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); ...@@ -51,22 +51,23 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 ps_mode); u8 ps_mode, u16 auto_ps_timeout);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len); size_t len);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id,
void *buf, size_t buf_len, int index, u32 rates); u16 template_id, void *buf, size_t buf_len,
int index, u32 rates);
int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u16 aid); u16 aid);
int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 role_id, u8 band,
const u8 *ssid, size_t ssid_len, const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band); const u8 *ie, size_t ie_len);
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
struct wl12xx_vif *wlvif, struct wl12xx_vif *wlvif,
struct sk_buff *skb); struct sk_buff *skb);
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif);
__be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif); int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
struct wl12xx_vif *wlvif); struct wl12xx_vif *wlvif);
...@@ -89,6 +90,7 @@ int wl12xx_cmd_config_fwlog(struct wl1271 *wl); ...@@ -89,6 +90,7 @@ int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
int wl12xx_cmd_channel_switch(struct wl1271 *wl, int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch); struct ieee80211_channel_switch *ch_switch);
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
...@@ -96,62 +98,65 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -96,62 +98,65 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
enum wl1271_commands { enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/ CMD_INTERROGATE = 1, /* use this to read information elements */
CMD_CONFIGURE = 2, /*use this to write information elements*/ CMD_CONFIGURE = 2, /* use this to write information elements */
CMD_ENABLE_RX = 3, CMD_ENABLE_RX = 3,
CMD_ENABLE_TX = 4, CMD_ENABLE_TX = 4,
CMD_DISABLE_RX = 5, CMD_DISABLE_RX = 5,
CMD_DISABLE_TX = 6, CMD_DISABLE_TX = 6,
CMD_SCAN = 8, CMD_SCAN = 7,
CMD_STOP_SCAN = 9, CMD_STOP_SCAN = 8,
CMD_SET_KEYS = 12, CMD_SET_KEYS = 9,
CMD_READ_MEMORY = 13, CMD_READ_MEMORY = 10,
CMD_WRITE_MEMORY = 14, CMD_WRITE_MEMORY = 11,
CMD_SET_TEMPLATE = 19, CMD_SET_TEMPLATE = 12,
CMD_TEST = 23, CMD_TEST = 13,
CMD_NOISE_HIST = 28, CMD_NOISE_HIST = 14,
CMD_QUIET_ELEMENT_SET_STATE = 29, CMD_QUIET_ELEMENT_SET_STATE = 15,
CMD_SET_BCN_MODE = 33, CMD_SET_BCN_MODE = 16,
CMD_MEASUREMENT = 34,
CMD_STOP_MEASUREMENT = 35, CMD_MEASUREMENT = 17,
CMD_SET_PS_MODE = 37, CMD_STOP_MEASUREMENT = 18,
CMD_CHANNEL_SWITCH = 38, CMD_SET_PS_MODE = 19,
CMD_STOP_CHANNEL_SWICTH = 39, CMD_CHANNEL_SWITCH = 20,
CMD_AP_DISCOVERY = 40, CMD_STOP_CHANNEL_SWICTH = 21,
CMD_STOP_AP_DISCOVERY = 41, CMD_AP_DISCOVERY = 22,
CMD_HEALTH_CHECK = 45, CMD_STOP_AP_DISCOVERY = 23,
CMD_DEBUG = 46, CMD_HEALTH_CHECK = 24,
CMD_TRIGGER_SCAN_TO = 47, CMD_DEBUG = 25,
CMD_CONNECTION_SCAN_CFG = 48, CMD_TRIGGER_SCAN_TO = 26,
CMD_CONNECTION_SCAN_SSID_CFG = 49, CMD_CONNECTION_SCAN_CFG = 27,
CMD_START_PERIODIC_SCAN = 50, CMD_CONNECTION_SCAN_SSID_CFG = 28,
CMD_STOP_PERIODIC_SCAN = 51, CMD_START_PERIODIC_SCAN = 29,
CMD_SET_PEER_STATE = 52, CMD_STOP_PERIODIC_SCAN = 30,
CMD_REMAIN_ON_CHANNEL = 53, CMD_SET_PEER_STATE = 31,
CMD_CANCEL_REMAIN_ON_CHANNEL = 54, CMD_REMAIN_ON_CHANNEL = 32,
CMD_CANCEL_REMAIN_ON_CHANNEL = 33,
CMD_CONFIG_FWLOGGER = 55, CMD_CONFIG_FWLOGGER = 34,
CMD_START_FWLOGGER = 56, CMD_START_FWLOGGER = 35,
CMD_STOP_FWLOGGER = 57, CMD_STOP_FWLOGGER = 36,
/* AP commands */ /* Access point commands */
CMD_ADD_PEER = 62, CMD_ADD_PEER = 37,
CMD_REMOVE_PEER = 63, CMD_REMOVE_PEER = 38,
/* Role API */ /* Role API */
CMD_ROLE_ENABLE = 70, CMD_ROLE_ENABLE = 39,
CMD_ROLE_DISABLE = 71, CMD_ROLE_DISABLE = 40,
CMD_ROLE_START = 72, CMD_ROLE_START = 41,
CMD_ROLE_STOP = 73, CMD_ROLE_STOP = 42,
/* WIFI Direct */ /* DFS */
CMD_WFD_START_DISCOVERY = 80, CMD_START_RADAR_DETECTION = 43,
CMD_WFD_STOP_DISCOVERY = 81, CMD_STOP_RADAR_DETECTION = 44,
CMD_WFD_ATTRIBUTE_CONFIG = 82,
CMD_NOP = 100, /* WIFI Direct */
CMD_WFD_START_DISCOVERY = 45,
CMD_WFD_STOP_DISCOVERY = 46,
CMD_WFD_ATTRIBUTE_CONFIG = 47,
CMD_NOP = 48,
CMD_LAST_COMMAND,
NUM_COMMANDS,
MAX_COMMAND_ID = 0xFFFF, MAX_COMMAND_ID = 0xFFFF,
}; };
...@@ -191,7 +196,7 @@ enum cmd_templ { ...@@ -191,7 +196,7 @@ enum cmd_templ {
/* unit ms */ /* unit ms */
#define WL1271_COMMAND_TIMEOUT 2000 #define WL1271_COMMAND_TIMEOUT 2000
#define WL1271_CMD_TEMPL_DFLT_SIZE 252 #define WL1271_CMD_TEMPL_DFLT_SIZE 252
#define WL1271_CMD_TEMPL_MAX_SIZE 548 #define WL1271_CMD_TEMPL_MAX_SIZE 512
#define WL1271_EVENT_TIMEOUT 750 #define WL1271_EVENT_TIMEOUT 750
struct wl1271_cmd_header { struct wl1271_cmd_header {
...@@ -339,7 +344,9 @@ struct wl12xx_cmd_role_start { ...@@ -339,7 +344,9 @@ struct wl12xx_cmd_role_start {
u8 ssid_len; u8 ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 padding_1[5]; u8 reset_tsf;
u8 padding_1[4];
} __packed ap; } __packed ap;
}; };
} __packed; } __packed;
...@@ -364,14 +371,18 @@ struct cmd_enabledisable_path { ...@@ -364,14 +371,18 @@ struct cmd_enabledisable_path {
struct wl1271_cmd_template_set { struct wl1271_cmd_template_set {
struct wl1271_cmd_header header; struct wl1271_cmd_header header;
__le16 len; u8 role_id;
u8 template_type; u8 template_type;
__le16 len;
u8 index; /* relevant only for KLV_TEMPLATE type */ u8 index; /* relevant only for KLV_TEMPLATE type */
u8 padding[3];
__le32 enabled_rates; __le32 enabled_rates;
u8 short_retry_limit; u8 short_retry_limit;
u8 long_retry_limit; u8 long_retry_limit;
u8 aflags; u8 aflags;
u8 reserved; u8 reserved;
u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
} __packed; } __packed;
...@@ -388,6 +399,7 @@ struct wl1271_tim { ...@@ -388,6 +399,7 @@ struct wl1271_tim {
} __packed; } __packed;
enum wl1271_cmd_ps_mode { enum wl1271_cmd_ps_mode {
STATION_AUTO_PS_MODE, /* Dynamic Power Save */
STATION_ACTIVE_MODE, STATION_ACTIVE_MODE,
STATION_POWER_SAVE_MODE STATION_POWER_SAVE_MODE
}; };
...@@ -397,7 +409,7 @@ struct wl1271_cmd_ps_params { ...@@ -397,7 +409,7 @@ struct wl1271_cmd_ps_params {
u8 role_id; u8 role_id;
u8 ps_mode; /* STATION_* */ u8 ps_mode; /* STATION_* */
u8 padding[2]; u16 auto_ps_timeout;
} __packed; } __packed;
/* HW encryption keys */ /* HW encryption keys */
...@@ -695,14 +707,18 @@ struct wl12xx_cmd_stop_fwlog { ...@@ -695,14 +707,18 @@ struct wl12xx_cmd_stop_fwlog {
struct wl12xx_cmd_channel_switch { struct wl12xx_cmd_channel_switch {
struct wl1271_cmd_header header; struct wl1271_cmd_header header;
u8 role_id;
/* The new serving channel */ /* The new serving channel */
u8 channel; u8 channel;
/* Relative time of the serving channel switch in TBTT units */ /* Relative time of the serving channel switch in TBTT units */
u8 switch_time; u8 switch_time;
/* 1: Suspend TX till switch time; 0: Do not suspend TX */ /* Stop the role TX, should expect it after radar detection */
u8 tx_suspend; u8 stop_tx;
/* 1: Flush TX at switch time; 0: Do not flush */ /* The target channel tx status 1-stopped 0-open*/
u8 flush; u8 post_switch_tx_disable;
u8 padding[3];
} __packed; } __packed;
struct wl12xx_cmd_stop_channel_switch { struct wl12xx_cmd_stop_channel_switch {
......
...@@ -66,7 +66,8 @@ enum { ...@@ -66,7 +66,8 @@ enum {
}; };
enum { enum {
CONF_HW_RXTX_RATE_MCS7 = 0, CONF_HW_RXTX_RATE_MCS7_SGI = 0,
CONF_HW_RXTX_RATE_MCS7,
CONF_HW_RXTX_RATE_MCS6, CONF_HW_RXTX_RATE_MCS6,
CONF_HW_RXTX_RATE_MCS5, CONF_HW_RXTX_RATE_MCS5,
CONF_HW_RXTX_RATE_MCS4, CONF_HW_RXTX_RATE_MCS4,
...@@ -91,6 +92,10 @@ enum { ...@@ -91,6 +92,10 @@ enum {
CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
}; };
/* Rates between and including these are MCS rates */
#define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI
#define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0
enum { enum {
CONF_SG_DISABLE = 0, CONF_SG_DISABLE = 0,
CONF_SG_PROTECTIVE, CONF_SG_PROTECTIVE,
...@@ -312,6 +317,10 @@ enum { ...@@ -312,6 +317,10 @@ enum {
CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, CONF_AP_BT_ACL_VAL_BT_SERVE_TIME,
CONF_AP_BT_ACL_VAL_WL_SERVE_TIME, CONF_AP_BT_ACL_VAL_WL_SERVE_TIME,
/* CTS Diluting params */
CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH,
CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER,
CONF_SG_TEMP_PARAM_1, CONF_SG_TEMP_PARAM_1,
CONF_SG_TEMP_PARAM_2, CONF_SG_TEMP_PARAM_2,
CONF_SG_TEMP_PARAM_3, CONF_SG_TEMP_PARAM_3,
...@@ -809,6 +818,19 @@ struct conf_conn_settings { ...@@ -809,6 +818,19 @@ struct conf_conn_settings {
*/ */
u8 listen_interval; u8 listen_interval;
/*
* Firmware wakeup conditions during suspend
* Range: CONF_WAKE_UP_EVENT_*
*/
u8 suspend_wake_up_event;
/*
* Listen interval during suspend.
* Currently will be in DTIMs (1-10)
*
*/
u8 suspend_listen_interval;
/* /*
* Enable or disable the beacon filtering. * Enable or disable the beacon filtering.
* *
...@@ -867,13 +889,6 @@ struct conf_conn_settings { ...@@ -867,13 +889,6 @@ struct conf_conn_settings {
*/ */
u8 ps_poll_threshold; u8 ps_poll_threshold;
/*
* PS Poll failure recovery ACTIVE period length
*
* Range: u32 (ms)
*/
u32 ps_poll_recovery_period;
/* /*
* Configuration of signal average weights. * Configuration of signal average weights.
*/ */
...@@ -921,6 +936,18 @@ struct conf_conn_settings { ...@@ -921,6 +936,18 @@ struct conf_conn_settings {
*/ */
u8 psm_entry_nullfunc_retries; u8 psm_entry_nullfunc_retries;
/*
* Specifies the dynamic PS timeout in ms that will be used
* by the FW when in AUTO_PS mode
*/
u16 dynamic_ps_timeout;
/*
* Specifies whether dynamic PS should be disabled and PSM forced.
* This is required for certain WiFi certification tests.
*/
u8 forced_ps;
/* /*
* *
* Specifies the interval of the connection keep-alive null-func * Specifies the interval of the connection keep-alive null-func
...@@ -1055,6 +1082,14 @@ struct conf_scan_settings { ...@@ -1055,6 +1082,14 @@ struct conf_scan_settings {
*/ */
u16 num_probe_reqs; u16 num_probe_reqs;
/*
* Scan trigger (split scan) timeout. The FW will split the scan
* operation into slices of the given time and allow the FW to schedule
* other tasks in between.
*
* Range: u32 Microsecs
*/
u32 split_scan_timeout;
}; };
struct conf_sched_scan_settings { struct conf_sched_scan_settings {
......
...@@ -51,6 +51,7 @@ enum { ...@@ -51,6 +51,7 @@ enum {
DEBUG_FILTERS = BIT(15), DEBUG_FILTERS = BIT(15),
DEBUG_ADHOC = BIT(16), DEBUG_ADHOC = BIT(16),
DEBUG_AP = BIT(17), DEBUG_AP = BIT(17),
DEBUG_PROBE = BIT(18),
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
DEBUG_ALL = ~0, DEBUG_ALL = ~0,
}; };
......
...@@ -113,7 +113,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl) ...@@ -113,7 +113,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out; goto out;
if (wl->state == WL1271_STATE_ON && if (wl->state == WL1271_STATE_ON && !wl->plt &&
time_after(jiffies, wl->stats.fw_stats_update + time_after(jiffies, wl->stats.fw_stats_update +
msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
wl1271_acx_statistics(wl, wl->stats.fw_stats); wl1271_acx_statistics(wl, wl->stats.fw_stats);
...@@ -312,6 +312,181 @@ static const struct file_operations start_recovery_ops = { ...@@ -312,6 +312,181 @@ static const struct file_operations start_recovery_ops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t dynamic_ps_timeout_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
return wl1271_format_buffer(user_buf, count,
ppos, "%d\n",
wl->conf.conn.dynamic_ps_timeout);
}
static ssize_t dynamic_ps_timeout_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
struct wl12xx_vif *wlvif;
unsigned long value;
int ret;
ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value in dynamic_ps");
return -EINVAL;
}
if (value < 1 || value > 65535) {
wl1271_warning("dyanmic_ps_timeout is not in valid range");
return -ERANGE;
}
mutex_lock(&wl->mutex);
wl->conf.conn.dynamic_ps_timeout = value;
if (wl->state == WL1271_STATE_OFF)
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
/* In case we're already in PSM, trigger it again to set new timeout
* immediately without waiting for re-association
*/
wl12xx_for_each_wlvif_sta(wl, wlvif) {
if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);
}
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations dynamic_ps_timeout_ops = {
.read = dynamic_ps_timeout_read,
.write = dynamic_ps_timeout_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static ssize_t forced_ps_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
return wl1271_format_buffer(user_buf, count,
ppos, "%d\n",
wl->conf.conn.forced_ps);
}
static ssize_t forced_ps_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
struct wl12xx_vif *wlvif;
unsigned long value;
int ret, ps_mode;
ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value in forced_ps");
return -EINVAL;
}
if (value != 1 && value != 0) {
wl1271_warning("forced_ps should be either 0 or 1");
return -ERANGE;
}
mutex_lock(&wl->mutex);
if (wl->conf.conn.forced_ps == value)
goto out;
wl->conf.conn.forced_ps = value;
if (wl->state == WL1271_STATE_OFF)
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
/* In case we're already in PSM, trigger it again to switch mode
* immediately without waiting for re-association
*/
ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE;
wl12xx_for_each_wlvif_sta(wl, wlvif) {
if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
wl1271_ps_set_mode(wl, wlvif, ps_mode);
}
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations forced_ps_ops = {
.read = forced_ps_read,
.write = forced_ps_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static ssize_t split_scan_timeout_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
return wl1271_format_buffer(user_buf, count,
ppos, "%d\n",
wl->conf.scan.split_scan_timeout / 1000);
}
static ssize_t split_scan_timeout_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
unsigned long value;
int ret;
ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value in split_scan_timeout");
return -EINVAL;
}
if (value == 0)
wl1271_info("split scan will be disabled");
mutex_lock(&wl->mutex);
wl->conf.scan.split_scan_timeout = value * 1000;
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations split_scan_timeout_ops = {
.read = split_scan_timeout_read,
.write = split_scan_timeout_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static ssize_t driver_state_read(struct file *file, char __user *user_buf, static ssize_t driver_state_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
...@@ -446,6 +621,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, ...@@ -446,6 +621,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(sta.basic_rate_idx); VIF_STATE_PRINT_INT(sta.basic_rate_idx);
VIF_STATE_PRINT_INT(sta.ap_rate_idx); VIF_STATE_PRINT_INT(sta.ap_rate_idx);
VIF_STATE_PRINT_INT(sta.p2p_rate_idx); VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
VIF_STATE_PRINT_INT(sta.qos);
} else { } else {
VIF_STATE_PRINT_INT(ap.global_hlid); VIF_STATE_PRINT_INT(ap.global_hlid);
VIF_STATE_PRINT_INT(ap.bcast_hlid); VIF_STATE_PRINT_INT(ap.bcast_hlid);
...@@ -471,7 +647,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, ...@@ -471,7 +647,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(default_key); VIF_STATE_PRINT_INT(default_key);
VIF_STATE_PRINT_INT(aid); VIF_STATE_PRINT_INT(aid);
VIF_STATE_PRINT_INT(session_counter); VIF_STATE_PRINT_INT(session_counter);
VIF_STATE_PRINT_INT(ps_poll_failures);
VIF_STATE_PRINT_INT(psm_entry_retry); VIF_STATE_PRINT_INT(psm_entry_retry);
VIF_STATE_PRINT_INT(power_level); VIF_STATE_PRINT_INT(power_level);
VIF_STATE_PRINT_INT(rssi_thold); VIF_STATE_PRINT_INT(rssi_thold);
...@@ -562,6 +737,64 @@ static const struct file_operations dtim_interval_ops = { ...@@ -562,6 +737,64 @@ static const struct file_operations dtim_interval_ops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t suspend_dtim_interval_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
u8 value;
if (wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
value = wl->conf.conn.suspend_listen_interval;
else
value = 0;
return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
}
static ssize_t suspend_dtim_interval_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
unsigned long value;
int ret;
ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value for suspend_dtim_interval");
return -EINVAL;
}
if (value < 1 || value > 10) {
wl1271_warning("suspend_dtim value is not in valid range");
return -ERANGE;
}
mutex_lock(&wl->mutex);
wl->conf.conn.suspend_listen_interval = value;
/* for some reason there are different event types for 1 and >1 */
if (value == 1)
wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
else
wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
mutex_unlock(&wl->mutex);
return count;
}
static const struct file_operations suspend_dtim_interval_ops = {
.read = suspend_dtim_interval_read,
.write = suspend_dtim_interval_write,
.open = wl1271_open_file_generic,
.llseek = default_llseek,
};
static ssize_t beacon_interval_read(struct file *file, char __user *user_buf, static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
...@@ -886,8 +1119,12 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, ...@@ -886,8 +1119,12 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(driver_state, rootdir); DEBUGFS_ADD(driver_state, rootdir);
DEBUGFS_ADD(vifs_state, rootdir); DEBUGFS_ADD(vifs_state, rootdir);
DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(dtim_interval, rootdir);
DEBUGFS_ADD(suspend_dtim_interval, rootdir);
DEBUGFS_ADD(beacon_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir);
DEBUGFS_ADD(beacon_filtering, rootdir); DEBUGFS_ADD(beacon_filtering, rootdir);
DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
DEBUGFS_ADD(forced_ps, rootdir);
DEBUGFS_ADD(split_scan_timeout, rootdir);
streaming = debugfs_create_dir("rx_streaming", rootdir); streaming = debugfs_create_dir("rx_streaming", rootdir);
if (!streaming || IS_ERR(streaming)) if (!streaming || IS_ERR(streaming))
......
...@@ -30,133 +30,6 @@ ...@@ -30,133 +30,6 @@
#include "scan.h" #include "scan.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
void wl1271_pspoll_work(struct work_struct *work)
{
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
struct delayed_work *dwork;
struct wl1271 *wl;
int ret;
dwork = container_of(work, struct delayed_work, work);
wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work);
vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
wl = wlvif->wl;
wl1271_debug(DEBUG_EVENT, "pspoll work");
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
goto out;
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
goto out;
/*
* if we end up here, then we were in powersave when the pspoll
* delivery failure occurred, and no-one changed state since, so
* we should go back to powersave.
*/
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
wlvif->basic_rate, true);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
};
static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl,
struct wl12xx_vif *wlvif)
{
int delay = wl->conf.conn.ps_poll_recovery_period;
int ret;
wlvif->ps_poll_failures++;
if (wlvif->ps_poll_failures == 1)
wl1271_info("AP with dysfunctional ps-poll, "
"trying to work around it.");
/* force active mode receive data from the AP */
if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
wlvif->basic_rate, true);
if (ret < 0)
return;
set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work,
msecs_to_jiffies(delay));
}
/*
* If already in active mode, lets we should be getting data from
* the AP right away. If we enter PSM too fast after this, and data
* remains on the AP, we will get another event like this, and we'll
* go into active once more.
*/
}
static int wl1271_event_ps_report(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct event_mailbox *mbox,
bool *beacon_loss)
{
int ret = 0;
u32 total_retries = wl->conf.conn.psm_entry_retries;
wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
switch (mbox->ps_status) {
case EVENT_ENTER_POWER_SAVE_FAIL:
wl1271_debug(DEBUG_PSM, "PSM entry failed");
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
/* remain in active mode */
wlvif->psm_entry_retry = 0;
break;
}
if (wlvif->psm_entry_retry < total_retries) {
wlvif->psm_entry_retry++;
ret = wl1271_ps_set_mode(wl, wlvif,
STATION_POWER_SAVE_MODE,
wlvif->basic_rate, true);
} else {
wl1271_info("No ack to nullfunc from AP.");
wlvif->psm_entry_retry = 0;
*beacon_loss = true;
}
break;
case EVENT_ENTER_POWER_SAVE_SUCCESS:
wlvif->psm_entry_retry = 0;
/*
* BET has only a minor effect in 5GHz and masks
* channel switch IEs, so we only enable BET on 2.4GHz
*/
if (wlvif->band == IEEE80211_BAND_2GHZ)
/* enable beacon early termination */
ret = wl1271_acx_bet_enable(wl, wlvif, true);
if (wlvif->ps_compl) {
complete(wlvif->ps_compl);
wlvif->ps_compl = NULL;
}
break;
default:
break;
}
return ret;
}
static void wl1271_event_rssi_trigger(struct wl1271 *wl, static void wl1271_event_rssi_trigger(struct wl1271 *wl,
struct wl12xx_vif *wlvif, struct wl12xx_vif *wlvif,
struct event_mailbox *mbox) struct event_mailbox *mbox)
...@@ -205,21 +78,13 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -205,21 +78,13 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
u8 enable) u8 enable)
{ {
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
if (enable) { if (enable) {
/* disable dynamic PS when requested by the firmware */
wl12xx_for_each_wlvif_sta(wl, wlvif) {
vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_disable_dyn_ps(vif);
}
set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
} else { } else {
clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
wl12xx_for_each_wlvif_sta(wl, wlvif) { wl12xx_for_each_wlvif_sta(wl, wlvif) {
vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_enable_dyn_ps(vif);
wl1271_recalc_rx_streaming(wl, wlvif); wl1271_recalc_rx_streaming(wl, wlvif);
} }
} }
...@@ -237,7 +102,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -237,7 +102,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
{ {
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
int ret;
u32 vector; u32 vector;
bool beacon_loss = false; bool beacon_loss = false;
bool disconnect_sta = false; bool disconnect_sta = false;
...@@ -293,21 +157,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -293,21 +157,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
beacon_loss = true; beacon_loss = true;
} }
if (vector & PS_REPORT_EVENT_ID) {
wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
wl12xx_for_each_wlvif_sta(wl, wlvif) {
ret = wl1271_event_ps_report(wl, wlvif,
mbox, &beacon_loss);
if (ret < 0)
return ret;
}
}
if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
wl12xx_for_each_wlvif_sta(wl, wlvif) {
wl1271_event_pspoll_delivery_fail(wl, wlvif);
}
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
/* TODO: check actual multi-role support */ /* TODO: check actual multi-role support */
wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
...@@ -344,7 +193,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -344,7 +193,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
/* TODO: configure only the relevant vif */ /* TODO: configure only the relevant vif */
wl12xx_for_each_wlvif_sta(wl, wlvif) { wl12xx_for_each_wlvif_sta(wl, wlvif) {
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
bool success; bool success;
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
...@@ -352,6 +200,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -352,6 +200,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
continue; continue;
success = mbox->channel_switch_status ? false : true; success = mbox->channel_switch_status ? false : true;
vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_chswitch_done(vif, success); ieee80211_chswitch_done(vif, success);
} }
} }
......
...@@ -51,10 +51,10 @@ enum { ...@@ -51,10 +51,10 @@ enum {
SCAN_COMPLETE_EVENT_ID = BIT(10), SCAN_COMPLETE_EVENT_ID = BIT(10),
WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11), WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
PS_REPORT_EVENT_ID = BIT(13), RESERVED1 = BIT(13),
PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
DISCONNECT_EVENT_COMPLETE_ID = BIT(15), ROLE_STOP_COMPLETE_EVENT_ID = BIT(15),
/* BIT(16) is reserved */ RADAR_DETECTED_EVENT_ID = BIT(16),
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18), BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19), REGAINED_BSS_EVENT_ID = BIT(19),
...@@ -94,9 +94,9 @@ struct event_mailbox { ...@@ -94,9 +94,9 @@ struct event_mailbox {
u8 soft_gemini_sense_info; u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info; u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
u8 channel_switch_status; u8 change_auto_mode_timeout;
u8 scheduled_scan_status; u8 scheduled_scan_status;
u8 ps_status; u8 reserved4;
/* tuned channel (roc) */ /* tuned channel (roc) */
u8 roc_channel; u8 roc_channel;
...@@ -119,17 +119,21 @@ struct event_mailbox { ...@@ -119,17 +119,21 @@ struct event_mailbox {
u8 rx_ba_allowed; u8 rx_ba_allowed;
u8 reserved_6[2]; u8 reserved_6[2];
/* Channel switch results */
u8 channel_switch_role_id;
u8 channel_switch_status;
u8 reserved_7[2];
u8 ps_poll_delivery_failure_role_ids; u8 ps_poll_delivery_failure_role_ids;
u8 stopped_role_ids; u8 stopped_role_ids;
u8 started_role_ids; u8 started_role_ids;
u8 change_auto_mode_timeout;
u8 reserved_7[12]; u8 reserved_8[9];
} __packed; } __packed;
int wl1271_event_unmask(struct wl1271 *wl); int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl); void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox); int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wl1271_pspoll_work(struct work_struct *work);
#endif #endif
...@@ -37,54 +37,64 @@ ...@@ -37,54 +37,64 @@
int wl1271_init_templates_config(struct wl1271 *wl) int wl1271_init_templates_config(struct wl1271 *wl)
{ {
int ret, i; int ret, i;
size_t max_size;
/* send empty templates for fw memory reservation */ /* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
WL1271_CMD_TEMPL_DFLT_SIZE, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0, CMD_TEMPL_CFG_PROBE_REQ_5,
NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
WL1271_RATE_AUTOMATIC); WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template), sizeof(struct wl12xx_null_data_template),
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_PS_POLL, NULL,
sizeof(struct wl12xx_ps_poll_template), sizeof(struct wl12xx_ps_poll_template),
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_QOS_NULL_DATA, NULL,
sizeof sizeof
(struct ieee80211_qos_hdr), (struct ieee80211_qos_hdr),
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_PROBE_RESPONSE, NULL,
WL1271_CMD_TEMPL_DFLT_SIZE, WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_BEACON, NULL,
WL1271_CMD_TEMPL_DFLT_SIZE, WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL, max_size = sizeof(struct wl12xx_arp_rsp_template) +
sizeof WL1271_EXTRA_SPACE_MAX;
(struct wl12xx_arp_rsp_template), ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_ARP_RSP, NULL,
max_size,
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -93,19 +103,22 @@ int wl1271_init_templates_config(struct wl1271 *wl) ...@@ -93,19 +103,22 @@ int wl1271_init_templates_config(struct wl1271 *wl)
* Put very large empty placeholders for all templates. These * Put very large empty placeholders for all templates. These
* reserve memory for later. * reserve memory for later.
*/ */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
WL1271_CMD_TEMPL_MAX_SIZE, WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_AP_BEACON, NULL,
WL1271_CMD_TEMPL_MAX_SIZE, WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_DEAUTH_AP, NULL,
sizeof sizeof
(struct wl12xx_disconn_template), (struct wl12xx_disconn_template),
0, WL1271_RATE_AUTOMATIC); 0, WL1271_RATE_AUTOMATIC);
...@@ -113,7 +126,8 @@ int wl1271_init_templates_config(struct wl1271 *wl) ...@@ -113,7 +126,8 @@ int wl1271_init_templates_config(struct wl1271 *wl)
return ret; return ret;
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_KLV, NULL,
sizeof(struct ieee80211_qos_hdr), sizeof(struct ieee80211_qos_hdr),
i, WL1271_RATE_AUTOMATIC); i, WL1271_RATE_AUTOMATIC);
if (ret < 0) if (ret < 0)
...@@ -140,7 +154,8 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl, ...@@ -140,7 +154,8 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
IEEE80211_STYPE_DEAUTH); IEEE80211_STYPE_DEAUTH);
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_DEAUTH_AP,
tmpl, sizeof(*tmpl), 0, rate); tmpl, sizeof(*tmpl), 0, rate);
out: out:
...@@ -172,7 +187,8 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl, ...@@ -172,7 +187,8 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl,
memcpy(nullfunc->addr3, vif->addr, ETH_ALEN); memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_NULL_DATA, nullfunc,
sizeof(*nullfunc), 0, rate); sizeof(*nullfunc), 0, rate);
out: out:
...@@ -204,7 +220,8 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl, ...@@ -204,7 +220,8 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
memcpy(qosnull->addr3, vif->addr, ETH_ALEN); memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_QOS_NULL_DATA, qosnull,
sizeof(*qosnull), 0, rate); sizeof(*qosnull), 0, rate);
out: out:
......
...@@ -45,6 +45,65 @@ ...@@ -45,6 +45,65 @@
#define OCP_STATUS_REQ_FAILED 0x20000 #define OCP_STATUS_REQ_FAILED 0x20000
#define OCP_STATUS_RESP_ERROR 0x30000 #define OCP_STATUS_RESP_ERROR 0x30000
struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
.mem = {
.start = 0x00000000,
.size = 0x000177c0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x00008800
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
},
},
[PART_WORK] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x0000a000
},
.mem2 = {
.start = 0x003004f8,
.size = 0x00000004
},
.mem3 = {
.start = 0x00040404,
.size = 0x00000000
},
},
[PART_DRPW] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = DRPW_BASE,
.size = 0x00006000
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
}
}
};
bool wl1271_set_block_size(struct wl1271 *wl) bool wl1271_set_block_size(struct wl1271 *wl)
{ {
if (wl->if_ops->set_block_size) { if (wl->if_ops->set_block_size) {
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN];
struct wl1271; struct wl1271;
void wl1271_disable_interrupts(struct wl1271 *wl); void wl1271_disable_interrupts(struct wl1271 *wl);
......
/* /*
* This file is part of wl1271 * This file is part of wl1271
* *
...@@ -115,6 +116,9 @@ static struct conf_drv_settings default_conf = { ...@@ -115,6 +116,9 @@ static struct conf_drv_settings default_conf = {
[CONF_AP_CONNECTION_PROTECTION_TIME] = 0, [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
[CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
[CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
/* CTS Diluting params */
[CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
[CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
}, },
.state = CONF_SG_PROTECTIVE, .state = CONF_SG_PROTECTIVE,
}, },
...@@ -217,6 +221,8 @@ static struct conf_drv_settings default_conf = { ...@@ -217,6 +221,8 @@ static struct conf_drv_settings default_conf = {
.conn = { .conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM, .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
.listen_interval = 1, .listen_interval = 1,
.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
.suspend_listen_interval = 3,
.bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
.bcn_filt_ie_count = 2, .bcn_filt_ie_count = 2,
.bcn_filt_ie = { .bcn_filt_ie = {
...@@ -235,12 +241,13 @@ static struct conf_drv_settings default_conf = { ...@@ -235,12 +241,13 @@ static struct conf_drv_settings default_conf = {
.broadcast_timeout = 20000, .broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1, .rx_broadcast_in_ps = 1,
.ps_poll_threshold = 10, .ps_poll_threshold = 10,
.ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE, .bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 50, .bet_max_consecutive = 50,
.psm_entry_retries = 8, .psm_entry_retries = 8,
.psm_exit_retries = 16, .psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3, .psm_entry_nullfunc_retries = 3,
.dynamic_ps_timeout = 100,
.forced_ps = false,
.keep_alive_interval = 55000, .keep_alive_interval = 55000,
.max_listen_interval = 20, .max_listen_interval = 20,
}, },
...@@ -265,6 +272,7 @@ static struct conf_drv_settings default_conf = { ...@@ -265,6 +272,7 @@ static struct conf_drv_settings default_conf = {
.min_dwell_time_passive = 100000, .min_dwell_time_passive = 100000,
.max_dwell_time_passive = 100000, .max_dwell_time_passive = 100000,
.num_probe_reqs = 2, .num_probe_reqs = 2,
.split_scan_timeout = 50000,
}, },
.sched_scan = { .sched_scan = {
/* sched_scan requires dwell times in TU instead of TU/1000 */ /* sched_scan requires dwell times in TU instead of TU/1000 */
...@@ -672,8 +680,6 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -672,8 +680,6 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
if (ret < 0)
return ret;
/* Chip-specific initializations */ /* Chip-specific initializations */
ret = wl1271_chip_specific_init(wl); ret = wl1271_chip_specific_init(wl);
...@@ -985,16 +991,70 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) ...@@ -985,16 +991,70 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int wl1271_fetch_firmware(struct wl1271 *wl) struct vif_counter_data {
u8 counter;
struct ieee80211_vif *cur_vif;
bool cur_vif_running;
};
static void wl12xx_vif_count_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct vif_counter_data *counter = data;
counter->counter++;
if (counter->cur_vif == vif)
counter->cur_vif_running = true;
}
/* caller must not hold wl->mutex, as it might deadlock */
static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
struct ieee80211_vif *cur_vif,
struct vif_counter_data *data)
{
memset(data, 0, sizeof(*data));
data->cur_vif = cur_vif;
ieee80211_iterate_active_interfaces(hw,
wl12xx_vif_count_iter, data);
}
static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
{ {
const struct firmware *fw; const struct firmware *fw;
const char *fw_name; const char *fw_name;
enum wl12xx_fw_type fw_type;
int ret; int ret;
if (wl->chip.id == CHIP_ID_1283_PG20) if (plt) {
fw_name = WL128X_FW_NAME; fw_type = WL12XX_FW_TYPE_PLT;
else if (wl->chip.id == CHIP_ID_1283_PG20)
fw_name = WL127X_FW_NAME; fw_name = WL128X_PLT_FW_NAME;
else
fw_name = WL127X_PLT_FW_NAME;
} else {
/*
* we can't call wl12xx_get_vif_count() here because
* wl->mutex is taken, so use the cached last_vif_count value
*/
if (wl->last_vif_count > 1) {
fw_type = WL12XX_FW_TYPE_MULTI;
if (wl->chip.id == CHIP_ID_1283_PG20)
fw_name = WL128X_FW_NAME_MULTI;
else
fw_name = WL127X_FW_NAME_MULTI;
} else {
fw_type = WL12XX_FW_TYPE_NORMAL;
if (wl->chip.id == CHIP_ID_1283_PG20)
fw_name = WL128X_FW_NAME_SINGLE;
else
fw_name = WL127X_FW_NAME_SINGLE;
}
}
if (wl->fw_type == fw_type)
return 0;
wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
...@@ -1013,6 +1073,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) ...@@ -1013,6 +1073,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
} }
vfree(wl->fw); vfree(wl->fw);
wl->fw_type = WL12XX_FW_TYPE_NONE;
wl->fw_len = fw->size; wl->fw_len = fw->size;
wl->fw = vmalloc(wl->fw_len); wl->fw = vmalloc(wl->fw_len);
...@@ -1024,7 +1085,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) ...@@ -1024,7 +1085,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
memcpy(wl->fw, fw->data, wl->fw_len); memcpy(wl->fw, fw->data, wl->fw_len);
ret = 0; ret = 0;
wl->fw_type = fw_type;
out: out:
release_firmware(fw); release_firmware(fw);
...@@ -1152,7 +1213,7 @@ static void wl1271_recovery_work(struct work_struct *work) ...@@ -1152,7 +1213,7 @@ static void wl1271_recovery_work(struct work_struct *work)
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->state != WL1271_STATE_ON) if (wl->state != WL1271_STATE_ON || wl->plt)
goto out_unlock; goto out_unlock;
/* Avoid a recursive recovery */ /* Avoid a recursive recovery */
...@@ -1232,10 +1293,9 @@ static int wl1271_setup(struct wl1271 *wl) ...@@ -1232,10 +1293,9 @@ static int wl1271_setup(struct wl1271 *wl)
return 0; return 0;
} }
static int wl1271_chip_wakeup(struct wl1271 *wl) static int wl12xx_set_power_on(struct wl1271 *wl)
{ {
struct wl1271_partition_set partition; int ret;
int ret = 0;
msleep(WL1271_PRE_POWER_ON_SLEEP); msleep(WL1271_PRE_POWER_ON_SLEEP);
ret = wl1271_power_on(wl); ret = wl1271_power_on(wl);
...@@ -1245,20 +1305,22 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ...@@ -1245,20 +1305,22 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_io_reset(wl); wl1271_io_reset(wl);
wl1271_io_init(wl); wl1271_io_init(wl);
/* We don't need a real memory partition here, because we only want wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
* to use the registers at this point. */
memset(&partition, 0, sizeof(partition));
partition.reg.start = REGISTERS_BASE;
partition.reg.size = REGISTERS_DOWN_SIZE;
wl1271_set_partition(wl, &partition);
/* ELP module wake up */ /* ELP module wake up */
wl1271_fw_wakeup(wl); wl1271_fw_wakeup(wl);
/* whal_FwCtrl_BootSm() */ out:
return ret;
}
/* 0. read chip id from CHIP_ID */ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
wl->chip.id = wl1271_read32(wl, CHIP_ID_B); {
int ret = 0;
ret = wl12xx_set_power_on(wl);
if (ret < 0)
goto out;
/* /*
* For wl127x based devices we could use the default block * For wl127x based devices we could use the default block
...@@ -1307,11 +1369,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ...@@ -1307,11 +1369,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
goto out; goto out;
} }
if (wl->fw == NULL) { ret = wl12xx_fetch_firmware(wl, plt);
ret = wl1271_fetch_firmware(wl); if (ret < 0)
if (ret < 0) goto out;
goto out;
}
/* No NVS from netlink, try to get it from the filesystem */ /* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) { if (wl->nvs == NULL) {
...@@ -1343,7 +1403,7 @@ int wl1271_plt_start(struct wl1271 *wl) ...@@ -1343,7 +1403,7 @@ int wl1271_plt_start(struct wl1271 *wl)
while (retries) { while (retries) {
retries--; retries--;
ret = wl1271_chip_wakeup(wl); ret = wl12xx_chip_wakeup(wl, true);
if (ret < 0) if (ret < 0)
goto power_off; goto power_off;
...@@ -1355,7 +1415,8 @@ int wl1271_plt_start(struct wl1271 *wl) ...@@ -1355,7 +1415,8 @@ int wl1271_plt_start(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto irq_disable; goto irq_disable;
wl->state = WL1271_STATE_PLT; wl->plt = true;
wl->state = WL1271_STATE_ON;
wl1271_notice("firmware booted in PLT mode (%s)", wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver_str); wl->chip.fw_ver_str);
...@@ -1391,41 +1452,51 @@ int wl1271_plt_start(struct wl1271 *wl) ...@@ -1391,41 +1452,51 @@ int wl1271_plt_start(struct wl1271 *wl)
return ret; return ret;
} }
static int __wl1271_plt_stop(struct wl1271 *wl) int wl1271_plt_stop(struct wl1271 *wl)
{ {
int ret = 0; int ret = 0;
wl1271_notice("power down"); wl1271_notice("power down");
if (wl->state != WL1271_STATE_PLT) { /*
* Interrupts must be disabled before setting the state to OFF.
* Otherwise, the interrupt handler might be called and exit without
* reading the interrupt status.
*/
wl1271_disable_interrupts(wl);
mutex_lock(&wl->mutex);
if (!wl->plt) {
mutex_unlock(&wl->mutex);
/*
* This will not necessarily enable interrupts as interrupts
* may have been disabled when op_stop was called. It will,
* however, balance the above call to disable_interrupts().
*/
wl1271_enable_interrupts(wl);
wl1271_error("cannot power down because not in PLT " wl1271_error("cannot power down because not in PLT "
"state: %d", wl->state); "state: %d", wl->state);
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
wl1271_power_off(wl);
wl->state = WL1271_STATE_OFF;
wl->rx_counter = 0;
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
wl1271_disable_interrupts(wl);
wl1271_flush_deferred_work(wl); wl1271_flush_deferred_work(wl);
cancel_work_sync(&wl->netstack_work); cancel_work_sync(&wl->netstack_work);
cancel_work_sync(&wl->recovery_work); cancel_work_sync(&wl->recovery_work);
mutex_lock(&wl->mutex); cancel_delayed_work_sync(&wl->elp_work);
out:
return ret;
}
int wl1271_plt_stop(struct wl1271 *wl)
{
int ret;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
ret = __wl1271_plt_stop(wl); wl1271_power_off(wl);
wl->flags = 0;
wl->state = WL1271_STATE_OFF;
wl->plt = false;
wl->rx_counter = 0;
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
out:
return ret; return ret;
} }
...@@ -1574,38 +1645,16 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, ...@@ -1574,38 +1645,16 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
goto out_unlock; goto out_unlock;
/* enter psm if needed*/ ret = wl1271_acx_wake_up_conditions(wl, wlvif,
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) { wl->conf.conn.suspend_wake_up_event,
DECLARE_COMPLETION_ONSTACK(compl); wl->conf.conn.suspend_listen_interval);
wlvif->ps_compl = &compl; if (ret < 0)
ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE, wl1271_error("suspend: set wake up conditions failed: %d", ret);
wlvif->basic_rate, true);
if (ret < 0)
goto out_sleep;
/* we must unlock here so we will be able to get events */
wl1271_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
ret = wait_for_completion_timeout(
&compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
mutex_lock(&wl->mutex);
if (ret <= 0) {
wl1271_warning("couldn't enter ps mode!");
ret = -EBUSY;
goto out_cleanup;
}
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_cleanup;
}
out_sleep:
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out_cleanup:
wlvif->ps_compl = NULL;
out_unlock: out_unlock:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return ret; return ret;
...@@ -1648,11 +1697,11 @@ static int wl1271_configure_suspend(struct wl1271 *wl, ...@@ -1648,11 +1697,11 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
static void wl1271_configure_resume(struct wl1271 *wl, static void wl1271_configure_resume(struct wl1271 *wl,
struct wl12xx_vif *wlvif) struct wl12xx_vif *wlvif)
{ {
int ret; int ret = 0;
bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
if (!is_sta && !is_ap) if ((!is_ap) && (!is_sta))
return; return;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
...@@ -1661,12 +1710,16 @@ static void wl1271_configure_resume(struct wl1271 *wl, ...@@ -1661,12 +1710,16 @@ static void wl1271_configure_resume(struct wl1271 *wl,
goto out; goto out;
if (is_sta) { if (is_sta) {
/* exit psm if it wasn't configured */ ret = wl1271_acx_wake_up_conditions(wl, wlvif,
if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) wl->conf.conn.wake_up_event,
wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE, wl->conf.conn.listen_interval);
wlvif->basic_rate, true);
if (ret < 0)
wl1271_error("resume: wake up conditions failed: %d",
ret);
} else if (is_ap) { } else if (is_ap) {
wl1271_acx_beacon_filter_opt(wl, wlvif, false); ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
} }
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
...@@ -1709,9 +1762,6 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, ...@@ -1709,9 +1762,6 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_enable_interrupts(wl); wl1271_enable_interrupts(wl);
flush_work(&wl->tx_work); flush_work(&wl->tx_work);
wl12xx_for_each_wlvif(wl, wlvif) {
flush_delayed_work(&wlvif->pspoll_work);
}
flush_delayed_work(&wl->elp_work); flush_delayed_work(&wl->elp_work);
return 0; return 0;
...@@ -1778,11 +1828,25 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -1778,11 +1828,25 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
/*
* Interrupts must be disabled before setting the state to OFF.
* Otherwise, the interrupt handler might be called and exit without
* reading the interrupt status.
*/
wl1271_disable_interrupts(wl);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) { if (wl->state == WL1271_STATE_OFF) {
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
/*
* This will not necessarily enable interrupts as interrupts
* may have been disabled when op_stop was called. It will,
* however, balance the above call to disable_interrupts().
*/
wl1271_enable_interrupts(wl);
return; return;
} }
/* /*
* this must be before the cancel_work calls below, so that the work * this must be before the cancel_work calls below, so that the work
* functions don't perform further work. * functions don't perform further work.
...@@ -1794,7 +1858,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -1794,7 +1858,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
list_del(&wl->list); list_del(&wl->list);
mutex_unlock(&wl_list_mutex); mutex_unlock(&wl_list_mutex);
wl1271_disable_interrupts(wl);
wl1271_flush_deferred_work(wl); wl1271_flush_deferred_work(wl);
cancel_delayed_work_sync(&wl->scan_complete_work); cancel_delayed_work_sync(&wl->scan_complete_work);
cancel_work_sync(&wl->netstack_work); cancel_work_sync(&wl->netstack_work);
...@@ -1969,7 +2032,6 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) ...@@ -1969,7 +2032,6 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_rx_streaming_enable_work); wl1271_rx_streaming_enable_work);
INIT_WORK(&wlvif->rx_streaming_disable_work, INIT_WORK(&wlvif->rx_streaming_disable_work,
wl1271_rx_streaming_disable_work); wl1271_rx_streaming_disable_work);
INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
INIT_LIST_HEAD(&wlvif->list); INIT_LIST_HEAD(&wlvif->list);
setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
...@@ -1986,7 +2048,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl) ...@@ -1986,7 +2048,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
while (retries) { while (retries) {
retries--; retries--;
ret = wl1271_chip_wakeup(wl); ret = wl12xx_chip_wakeup(wl, false);
if (ret < 0) if (ret < 0)
goto power_off; goto power_off;
...@@ -2051,11 +2113,60 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) ...@@ -2051,11 +2113,60 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID; return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
} }
/*
* Check whether a fw switch (i.e. moving from one loaded
* fw to another) is needed. This function is also responsible
* for updating wl->last_vif_count, so it must be called before
* loading a non-plt fw (so the correct fw (single-role/multi-role)
* will be used).
*/
static bool wl12xx_need_fw_change(struct wl1271 *wl,
struct vif_counter_data vif_counter_data,
bool add)
{
enum wl12xx_fw_type current_fw = wl->fw_type;
u8 vif_count = vif_counter_data.counter;
if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
return false;
/* increase the vif count if this is a new vif */
if (add && !vif_counter_data.cur_vif_running)
vif_count++;
wl->last_vif_count = vif_count;
/* no need for fw change if the device is OFF */
if (wl->state == WL1271_STATE_OFF)
return false;
if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
return true;
if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
return true;
return false;
}
/*
* Enter "forced psm". Make sure the sta is in psm against the ap,
* to make the fw switch a bit more disconnection-persistent.
*/
static void wl12xx_force_active_psm(struct wl1271 *wl)
{
struct wl12xx_vif *wlvif;
wl12xx_for_each_wlvif_sta(wl, wlvif) {
wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
}
}
static int wl1271_op_add_interface(struct ieee80211_hw *hw, static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct vif_counter_data vif_count;
int ret = 0; int ret = 0;
u8 role_type; u8 role_type;
bool booted = false; bool booted = false;
...@@ -2066,18 +2177,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -2066,18 +2177,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
ieee80211_vif_type_p2p(vif), vif->addr); ieee80211_vif_type_p2p(vif), vif->addr);
wl12xx_get_vif_count(hw, vif, &vif_count);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl); ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0) if (ret < 0)
goto out_unlock; goto out_unlock;
if (wl->vif) {
wl1271_debug(DEBUG_MAC80211,
"multiple vifs are not supported yet");
ret = -EBUSY;
goto out;
}
/* /*
* in some very corner case HW recovery scenarios its possible to * in some very corner case HW recovery scenarios its possible to
* get here before __wl1271_op_remove_interface is complete, so * get here before __wl1271_op_remove_interface is complete, so
...@@ -2089,6 +2195,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -2089,6 +2195,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out; goto out;
} }
ret = wl12xx_init_vif_data(wl, vif); ret = wl12xx_init_vif_data(wl, vif);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -2100,6 +2207,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -2100,6 +2207,13 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out; goto out;
} }
if (wl12xx_need_fw_change(wl, vif_count, true)) {
wl12xx_force_active_psm(wl);
mutex_unlock(&wl->mutex);
wl1271_recovery_work(&wl->recovery_work);
return 0;
}
/* /*
* TODO: after the nvs issue will be solved, move this block * TODO: after the nvs issue will be solved, move this block
* to start(), and make sure here the driver is ON. * to start(), and make sure here the driver is ON.
...@@ -2109,7 +2223,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -2109,7 +2223,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
* we still need this in order to configure the fw * we still need this in order to configure the fw
* while uploading the nvs * while uploading the nvs
*/ */
memcpy(wl->mac_addr, vif->addr, ETH_ALEN); memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
booted = wl12xx_init_fw(wl); booted = wl12xx_init_fw(wl);
if (!booted) { if (!booted) {
...@@ -2142,7 +2256,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -2142,7 +2256,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
if (ret < 0) if (ret < 0)
goto out; goto out;
wl->vif = vif;
list_add(&wlvif->list, &wl->wlvif_list); list_add(&wlvif->list, &wl->wlvif_list);
set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
...@@ -2175,18 +2288,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2175,18 +2288,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
return; return;
wl->vif = NULL;
/* because of hardware recovery, we may get here twice */ /* because of hardware recovery, we may get here twice */
if (wl->state != WL1271_STATE_ON) if (wl->state != WL1271_STATE_ON)
return; return;
wl1271_info("down"); wl1271_info("down");
/* enable dyn ps just in case (if left on due to fw crash etc) */
if (wlvif->bss_type == BSS_TYPE_STA_BSS)
ieee80211_enable_dyn_ps(vif);
if (wl->scan.state != WL1271_SCAN_STATE_IDLE && if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
wl->scan_vif == vif) { wl->scan_vif == vif) {
wl->scan.state = WL1271_SCAN_STATE_IDLE; wl->scan.state = WL1271_SCAN_STATE_IDLE;
...@@ -2253,10 +2360,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2253,10 +2360,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->sta_count--; wl->sta_count--;
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
del_timer_sync(&wlvif->rx_streaming_timer); del_timer_sync(&wlvif->rx_streaming_timer);
cancel_work_sync(&wlvif->rx_streaming_enable_work); cancel_work_sync(&wlvif->rx_streaming_enable_work);
cancel_work_sync(&wlvif->rx_streaming_disable_work); cancel_work_sync(&wlvif->rx_streaming_disable_work);
cancel_delayed_work_sync(&wlvif->pspoll_work);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
} }
...@@ -2267,7 +2374,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ...@@ -2267,7 +2374,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct wl12xx_vif *iter; struct wl12xx_vif *iter;
struct vif_counter_data vif_count;
bool cancel_recovery = true;
wl12xx_get_vif_count(hw, vif, &vif_count);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF || if (wl->state == WL1271_STATE_OFF ||
...@@ -2286,20 +2396,33 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ...@@ -2286,20 +2396,33 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
break; break;
} }
WARN_ON(iter != wlvif); WARN_ON(iter != wlvif);
if (wl12xx_need_fw_change(wl, vif_count, false)) {
wl12xx_force_active_psm(wl);
wl12xx_queue_recovery_work(wl);
cancel_recovery = false;
}
out: out:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->recovery_work); if (cancel_recovery)
cancel_work_sync(&wl->recovery_work);
} }
static int wl12xx_op_change_interface(struct ieee80211_hw *hw, static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
enum nl80211_iftype new_type, bool p2p) enum nl80211_iftype new_type, bool p2p)
{ {
struct wl1271 *wl = hw->priv;
int ret;
set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
wl1271_op_remove_interface(hw, vif); wl1271_op_remove_interface(hw, vif);
vif->type = ieee80211_iftype_p2p(new_type, p2p); vif->type = ieee80211_iftype_p2p(new_type, p2p);
vif->p2p = p2p; vif->p2p = p2p;
return wl1271_op_add_interface(hw, vif); ret = wl1271_op_add_interface(hw, vif);
clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
return ret;
} }
static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
...@@ -2320,6 +2443,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -2320,6 +2443,9 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
wl1271_info("JOIN while associated."); wl1271_info("JOIN while associated.");
/* clear encryption type */
wlvif->encryption_type = KEY_NONE;
if (set_assoc) if (set_assoc)
set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
...@@ -2503,38 +2629,41 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -2503,38 +2629,41 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
} }
} }
/* if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
* if mac80211 changes the PSM mode, make sure the mode is not
* incorrectly changed after the pspoll failure active window.
*/
if (changed & IEEE80211_CONF_CHANGE_PS)
clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
if (conf->flags & IEEE80211_CONF_PS && if ((conf->flags & IEEE80211_CONF_PS) &&
!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) { test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
/* int ps_mode;
* We enter PSM only if we're already associated. char *ps_mode_str;
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
*/
if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
wl1271_debug(DEBUG_PSM, "psm enabled");
ret = wl1271_ps_set_mode(wl, wlvif,
STATION_POWER_SAVE_MODE,
wlvif->basic_rate, true);
}
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
wl1271_debug(DEBUG_PSM, "psm disabled");
clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags); if (wl->conf.conn.forced_ps) {
ps_mode = STATION_POWER_SAVE_MODE;
ps_mode_str = "forced";
} else {
ps_mode = STATION_AUTO_PS_MODE;
ps_mode_str = "auto";
}
wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
if (ret < 0)
wl1271_warning("enter %s ps failed %d",
ps_mode_str, ret);
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
wl1271_debug(DEBUG_PSM, "auto ps disabled");
if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
ret = wl1271_ps_set_mode(wl, wlvif, ret = wl1271_ps_set_mode(wl, wlvif,
STATION_ACTIVE_MODE, STATION_ACTIVE_MODE);
wlvif->basic_rate, true); if (ret < 0)
wl1271_warning("exit auto ps failed %d", ret);
}
} }
if (conf->power_level != wlvif->power_level) { if (conf->power_level != wlvif->power_level) {
...@@ -2974,6 +3103,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2974,6 +3103,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
wl1271_error("Could not add or replace key"); wl1271_error("Could not add or replace key");
goto out_sleep; goto out_sleep;
} }
/*
* reconfiguring arp response if the unicast (or common)
* encryption key type was changed
*/
if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
(sta || key_type == KEY_WEP) &&
wlvif->encryption_type != key_type) {
wlvif->encryption_type = key_type;
ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
if (ret < 0) {
wl1271_warning("build arp rsp failed: %d", ret);
goto out_sleep;
}
}
break; break;
case DISABLE_KEY: case DISABLE_KEY:
...@@ -3043,10 +3187,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, ...@@ -3043,10 +3187,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
goto out_sleep; goto out_sleep;
} }
/* cancel ROC before scanning */
if (wl12xx_dev_role_started(wlvif))
wl12xx_stop_dev(wl, wlvif);
ret = wl1271_scan(hw->priv, vif, ssid, len, req); ret = wl1271_scan(hw->priv, vif, ssid, len, req);
out_sleep: out_sleep:
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
...@@ -3108,6 +3248,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, ...@@ -3108,6 +3248,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
ret = -EAGAIN;
goto out;
}
ret = wl1271_ps_elp_wakeup(wl); ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -3139,6 +3284,9 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, ...@@ -3139,6 +3284,9 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF)
goto out;
ret = wl1271_ps_elp_wakeup(wl); ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -3266,6 +3414,7 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb, ...@@ -3266,6 +3414,7 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates, static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct sk_buff *skb; struct sk_buff *skb;
int ret; int ret;
...@@ -3273,7 +3422,7 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates, ...@@ -3273,7 +3422,7 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
if (!skb) if (!skb)
return -EOPNOTSUPP; return -EOPNOTSUPP;
ret = wl1271_cmd_template_set(wl, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_AP_PROBE_RESPONSE, CMD_TEMPL_AP_PROBE_RESPONSE,
skb->data, skb->data,
skb->len, 0, skb->len, 0,
...@@ -3297,7 +3446,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, ...@@ -3297,7 +3446,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
/* no need to change probe response if the SSID is set correctly */ /* no need to change probe response if the SSID is set correctly */
if (wlvif->ssid_len > 0) if (wlvif->ssid_len > 0)
return wl1271_cmd_template_set(wl, return wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_AP_PROBE_RESPONSE, CMD_TEMPL_AP_PROBE_RESPONSE,
probe_rsp_data, probe_rsp_data,
probe_rsp_len, 0, probe_rsp_len, 0,
...@@ -3334,7 +3483,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, ...@@ -3334,7 +3483,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
ptr, probe_rsp_len - (ptr - probe_rsp_data)); ptr, probe_rsp_len - (ptr - probe_rsp_data));
templ_len += probe_rsp_len - (ptr - probe_rsp_data); templ_len += probe_rsp_len - (ptr - probe_rsp_data);
return wl1271_cmd_template_set(wl, return wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_AP_PROBE_RESPONSE, CMD_TEMPL_AP_PROBE_RESPONSE,
probe_rsp_templ, probe_rsp_templ,
templ_len, 0, templ_len, 0,
...@@ -3431,7 +3580,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, ...@@ -3431,7 +3580,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
CMD_TEMPL_BEACON; CMD_TEMPL_BEACON;
ret = wl1271_cmd_template_set(wl, tmpl_id, ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
beacon->data, beacon->data,
beacon->len, 0, beacon->len, 0,
min_rate); min_rate);
...@@ -3470,7 +3619,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, ...@@ -3470,7 +3619,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
beacon->len, beacon->len,
min_rate); min_rate);
else else
ret = wl1271_cmd_template_set(wl, ret = wl1271_cmd_template_set(wl, wlvif->role_id,
CMD_TEMPL_PROBE_RESPONSE, CMD_TEMPL_PROBE_RESPONSE,
beacon->data, beacon->data,
beacon->len, 0, beacon->len, 0,
...@@ -3634,7 +3783,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3634,7 +3783,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif->rssi_thold = bss_conf->cqm_rssi_thold; wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
} }
if (changed & BSS_CHANGED_BSSID) if (changed & BSS_CHANGED_BSSID &&
(is_ibss || bss_conf->assoc))
if (!is_zero_ether_addr(bss_conf->bssid)) { if (!is_zero_ether_addr(bss_conf->bssid)) {
ret = wl12xx_cmd_build_null_data(wl, wlvif); ret = wl12xx_cmd_build_null_data(wl, wlvif);
if (ret < 0) if (ret < 0)
...@@ -3673,8 +3823,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3673,8 +3823,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif->aid = bss_conf->aid; wlvif->aid = bss_conf->aid;
set_assoc = true; set_assoc = true;
wlvif->ps_poll_failures = 0;
/* /*
* use basic rates from AP, and determine lowest rate * use basic rates from AP, and determine lowest rate
* to use with control frames. * to use with control frames.
...@@ -3734,9 +3882,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3734,9 +3882,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
dev_kfree_skb(wlvif->probereq); dev_kfree_skb(wlvif->probereq);
wlvif->probereq = NULL; wlvif->probereq = NULL;
/* re-enable dynamic ps - just in case */
ieee80211_enable_dyn_ps(vif);
/* revert back to minimum rates for the current band */ /* revert back to minimum rates for the current band */
wl1271_set_band_rate(wl, wlvif); wl1271_set_band_rate(wl, wlvif);
wlvif->basic_rate = wlvif->basic_rate =
...@@ -3810,34 +3955,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3810,34 +3955,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
goto out; goto out;
if (changed & BSS_CHANGED_ARP_FILTER) {
__be32 addr = bss_conf->arp_addr_list[0];
WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
if (bss_conf->arp_addr_cnt == 1 &&
bss_conf->arp_filter_enabled) {
/*
* The template should have been configured only upon
* association. however, it seems that the correct ip
* isn't being set (when sending), so we have to
* reconfigure the template upon every ip change.
*/
ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
if (ret < 0) {
wl1271_warning("build arp rsp failed: %d", ret);
goto out;
}
ret = wl1271_acx_arp_ip_filter(wl, wlvif,
ACX_ARP_FILTER_ARP_FILTERING,
addr);
} else
ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
if (ret < 0)
goto out;
}
if (do_join) { if (do_join) {
ret = wl1271_join(wl, wlvif, set_assoc); ret = wl1271_join(wl, wlvif, set_assoc);
if (ret < 0) { if (ret < 0) {
...@@ -3863,19 +3980,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3863,19 +3980,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
goto out; goto out;
} }
/* If we want to go in PSM but we're not there yet */
if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
enum wl1271_cmd_ps_mode mode;
mode = STATION_POWER_SAVE_MODE;
ret = wl1271_ps_set_mode(wl, wlvif, mode,
wlvif->basic_rate,
true);
if (ret < 0)
goto out;
}
} }
/* Handle new association with HT. Do this after join. */ /* Handle new association with HT. Do this after join. */
...@@ -3917,6 +4021,41 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3917,6 +4021,41 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
} }
} }
/* Handle arp filtering. Done after join. */
if ((changed & BSS_CHANGED_ARP_FILTER) ||
(!is_ibss && (changed & BSS_CHANGED_QOS))) {
__be32 addr = bss_conf->arp_addr_list[0];
wlvif->sta.qos = bss_conf->qos;
WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
if (bss_conf->arp_addr_cnt == 1 &&
bss_conf->arp_filter_enabled) {
wlvif->ip_addr = addr;
/*
* The template should have been configured only upon
* association. however, it seems that the correct ip
* isn't being set (when sending), so we have to
* reconfigure the template upon every ip change.
*/
ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
if (ret < 0) {
wl1271_warning("build arp rsp failed: %d", ret);
goto out;
}
ret = wl1271_acx_arp_ip_filter(wl, wlvif,
(ACX_ARP_FILTER_ARP_FILTERING |
ACX_ARP_FILTER_AUTO_ARP),
addr);
} else {
wlvif->ip_addr = 0;
ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
}
if (ret < 0)
goto out;
}
out: out:
return; return;
} }
...@@ -4012,6 +4151,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, ...@@ -4012,6 +4151,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
u64 mactime = ULLONG_MAX; u64 mactime = ULLONG_MAX;
int ret; int ret;
...@@ -4026,7 +4166,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, ...@@ -4026,7 +4166,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = wl1271_acx_tsf_info(wl, &mactime); ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
if (ret < 0) if (ret < 0)
goto out_sleep; goto out_sleep;
...@@ -4373,7 +4513,7 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, ...@@ -4373,7 +4513,7 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
/* TODO: change mac80211 to pass vif as param */ /* TODO: change mac80211 to pass vif as param */
wl12xx_for_each_wlvif_sta(wl, wlvif) { wl12xx_for_each_wlvif_sta(wl, wlvif) {
ret = wl12xx_cmd_channel_switch(wl, ch_switch); ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
if (!ret) if (!ret)
set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
...@@ -4467,6 +4607,7 @@ static struct ieee80211_channel wl1271_channels[] = { ...@@ -4467,6 +4607,7 @@ static struct ieee80211_channel wl1271_channels[] = {
/* mapping to indexes for wl1271_rates */ /* mapping to indexes for wl1271_rates */
static const u8 wl1271_rate_to_idx_2ghz[] = { static const u8 wl1271_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */ /* MCS rates are used only with 11n */
7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* CONF_HW_RXTX_RATE_MCS7 */ 7, /* CONF_HW_RXTX_RATE_MCS7 */
6, /* CONF_HW_RXTX_RATE_MCS6 */ 6, /* CONF_HW_RXTX_RATE_MCS6 */
5, /* CONF_HW_RXTX_RATE_MCS5 */ 5, /* CONF_HW_RXTX_RATE_MCS5 */
...@@ -4588,6 +4729,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = { ...@@ -4588,6 +4729,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
/* mapping to indexes for wl1271_rates_5ghz */ /* mapping to indexes for wl1271_rates_5ghz */
static const u8 wl1271_rate_to_idx_5ghz[] = { static const u8 wl1271_rate_to_idx_5ghz[] = {
/* MCS rates are used only with 11n */ /* MCS rates are used only with 11n */
7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* CONF_HW_RXTX_RATE_MCS7 */ 7, /* CONF_HW_RXTX_RATE_MCS7 */
6, /* CONF_HW_RXTX_RATE_MCS6 */ 6, /* CONF_HW_RXTX_RATE_MCS6 */
5, /* CONF_HW_RXTX_RATE_MCS5 */ 5, /* CONF_HW_RXTX_RATE_MCS5 */
...@@ -4828,13 +4970,120 @@ static struct bin_attribute fwlog_attr = { ...@@ -4828,13 +4970,120 @@ static struct bin_attribute fwlog_attr = {
.read = wl1271_sysfs_read_fwlog, .read = wl1271_sysfs_read_fwlog,
}; };
static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
{
bool supported = false;
u8 major, minor;
if (wl->chip.id == CHIP_ID_1283_PG20) {
major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
/* in wl128x we have the MAC address if the PG is >= (2, 1) */
if (major > 2 || (major == 2 && minor >= 1))
supported = true;
} else {
major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
/* in wl127x we have the MAC address if the PG is >= (3, 1) */
if (major == 3 && minor >= 1)
supported = true;
}
wl1271_debug(DEBUG_PROBE,
"PG Ver major = %d minor = %d, MAC %s present",
major, minor, supported ? "is" : "is not");
return supported;
}
static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
u32 oui, u32 nic, int n)
{
int i;
wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
oui, nic, n);
if (nic + n - 1 > 0xffffff)
wl1271_warning("NIC part of the MAC address wraps around!");
for (i = 0; i < n; i++) {
wl->addresses[i].addr[0] = (u8)(oui >> 16);
wl->addresses[i].addr[1] = (u8)(oui >> 8);
wl->addresses[i].addr[2] = (u8) oui;
wl->addresses[i].addr[3] = (u8)(nic >> 16);
wl->addresses[i].addr[4] = (u8)(nic >> 8);
wl->addresses[i].addr[5] = (u8) nic;
nic++;
}
wl->hw->wiphy->n_addresses = n;
wl->hw->wiphy->addresses = wl->addresses;
}
static void wl12xx_get_fuse_mac(struct wl1271 *wl)
{
u32 mac1, mac2;
wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
/* these are the two parts of the BD_ADDR */
wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
((mac1 & 0xff000000) >> 24);
wl->fuse_nic_addr = mac1 & 0xffffff;
wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
}
static int wl12xx_get_hw_info(struct wl1271 *wl)
{
int ret;
u32 die_info;
ret = wl12xx_set_power_on(wl);
if (ret < 0)
goto out;
wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
if (wl->chip.id == CHIP_ID_1283_PG20)
die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
else
die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
if (!wl12xx_mac_in_fuse(wl)) {
wl->fuse_oui_addr = 0;
wl->fuse_nic_addr = 0;
} else {
wl12xx_get_fuse_mac(wl);
}
wl1271_power_off(wl);
out:
return ret;
}
static int wl1271_register_hw(struct wl1271 *wl) static int wl1271_register_hw(struct wl1271 *wl)
{ {
int ret; int ret;
u32 oui_addr = 0, nic_addr = 0;
if (wl->mac80211_registered) if (wl->mac80211_registered)
return 0; return 0;
ret = wl12xx_get_hw_info(wl);
if (ret < 0) {
wl1271_error("couldn't get hw info");
goto out;
}
ret = wl1271_fetch_nvs(wl); ret = wl1271_fetch_nvs(wl);
if (ret == 0) { if (ret == 0) {
/* NOTE: The wl->nvs->nvs element must be first, in /* NOTE: The wl->nvs->nvs element must be first, in
...@@ -4843,20 +5092,25 @@ static int wl1271_register_hw(struct wl1271 *wl) ...@@ -4843,20 +5092,25 @@ static int wl1271_register_hw(struct wl1271 *wl)
*/ */
u8 *nvs_ptr = (u8 *)wl->nvs; u8 *nvs_ptr = (u8 *)wl->nvs;
wl->mac_addr[0] = nvs_ptr[11]; oui_addr =
wl->mac_addr[1] = nvs_ptr[10]; (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
wl->mac_addr[2] = nvs_ptr[6]; nic_addr =
wl->mac_addr[3] = nvs_ptr[5]; (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
wl->mac_addr[4] = nvs_ptr[4];
wl->mac_addr[5] = nvs_ptr[3];
} }
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); /* if the MAC address is zeroed in the NVS derive from fuse */
if (oui_addr == 0 && nic_addr == 0) {
oui_addr = wl->fuse_oui_addr;
/* fuse has the BD_ADDR, the WLAN addresses are the next two */
nic_addr = wl->fuse_nic_addr + 1;
}
wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
ret = ieee80211_register_hw(wl->hw); ret = ieee80211_register_hw(wl->hw);
if (ret < 0) { if (ret < 0) {
wl1271_error("unable to register mac80211 hw: %d", ret); wl1271_error("unable to register mac80211 hw: %d", ret);
return ret; goto out;
} }
wl->mac80211_registered = true; wl->mac80211_registered = true;
...@@ -4867,13 +5121,14 @@ static int wl1271_register_hw(struct wl1271 *wl) ...@@ -4867,13 +5121,14 @@ static int wl1271_register_hw(struct wl1271 *wl)
wl1271_notice("loaded"); wl1271_notice("loaded");
return 0; out:
return ret;
} }
static void wl1271_unregister_hw(struct wl1271 *wl) static void wl1271_unregister_hw(struct wl1271 *wl)
{ {
if (wl->state == WL1271_STATE_PLT) if (wl->plt)
__wl1271_plt_stop(wl); wl1271_plt_stop(wl);
unregister_netdevice_notifier(&wl1271_dev_notifier); unregister_netdevice_notifier(&wl1271_dev_notifier);
ieee80211_unregister_hw(wl->hw); ieee80211_unregister_hw(wl->hw);
...@@ -4892,7 +5147,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -4892,7 +5147,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
}; };
/* The tx descriptor buffer and the TKIP space. */ /* The tx descriptor buffer and the TKIP space. */
wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
sizeof(struct wl1271_tx_hw_descr); sizeof(struct wl1271_tx_hw_descr);
/* unit us */ /* unit us */
...@@ -4902,6 +5157,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -4902,6 +5157,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_CONNECTION_MONITOR |
...@@ -4909,7 +5165,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -4909,7 +5165,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_AP_LINK_PS | IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW; IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
IEEE80211_HW_SCAN_WHILE_IDLE;
wl->hw->wiphy->cipher_suites = cipher_suites; wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
...@@ -4925,10 +5182,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -4925,10 +5182,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
* should be the maximum length possible for a template, without * should be the maximum length possible for a template, without
* the IEEE80211 header of the template * the IEEE80211 header of the template
*/ */
wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
sizeof(struct ieee80211_header); sizeof(struct ieee80211_header);
wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
sizeof(struct ieee80211_header); sizeof(struct ieee80211_header);
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
...@@ -5022,7 +5279,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5022,7 +5279,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl->rx_counter = 0; wl->rx_counter = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->band = IEEE80211_BAND_2GHZ; wl->band = IEEE80211_BAND_2GHZ;
wl->vif = NULL;
wl->flags = 0; wl->flags = 0;
wl->sg_enabled = true; wl->sg_enabled = true;
wl->hw_pg_ver = -1; wl->hw_pg_ver = -1;
...@@ -5047,6 +5303,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5047,6 +5303,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
spin_lock_init(&wl->wl_lock); spin_lock_init(&wl->wl_lock);
wl->state = WL1271_STATE_OFF; wl->state = WL1271_STATE_OFF;
wl->fw_type = WL12XX_FW_TYPE_NONE;
mutex_init(&wl->mutex); mutex_init(&wl->mutex);
/* Apply default driver configuration. */ /* Apply default driver configuration. */
...@@ -5114,6 +5371,7 @@ static int wl1271_free_hw(struct wl1271 *wl) ...@@ -5114,6 +5371,7 @@ static int wl1271_free_hw(struct wl1271 *wl)
vfree(wl->fw); vfree(wl->fw);
wl->fw = NULL; wl->fw = NULL;
wl->fw_type = WL12XX_FW_TYPE_NONE;
kfree(wl->nvs); kfree(wl->nvs);
wl->nvs = NULL; wl->nvs = NULL;
...@@ -5300,7 +5558,7 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); ...@@ -5300,7 +5558,7 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
module_param_named(fwlog, fwlog_param, charp, 0); module_param_named(fwlog, fwlog_param, charp, 0);
MODULE_PARM_DESC(keymap, MODULE_PARM_DESC(fwlog,
"FW logger options: continuous, ondemand, dbgpins or disable"); "FW logger options: continuous, ondemand, dbgpins or disable");
module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
......
...@@ -56,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work) ...@@ -56,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work)
if (wlvif->bss_type == BSS_TYPE_AP_BSS) if (wlvif->bss_type == BSS_TYPE_AP_BSS)
goto out; goto out;
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
goto out; goto out;
} }
...@@ -84,7 +84,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) ...@@ -84,7 +84,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
if (wlvif->bss_type == BSS_TYPE_AP_BSS) if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return; return;
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
return; return;
} }
...@@ -160,28 +160,39 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) ...@@ -160,28 +160,39 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
} }
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
enum wl1271_cmd_ps_mode mode, u32 rates, bool send) enum wl1271_cmd_ps_mode mode)
{ {
int ret; int ret;
u16 timeout = wl->conf.conn.dynamic_ps_timeout;
switch (mode) { switch (mode) {
case STATION_AUTO_PS_MODE:
case STATION_POWER_SAVE_MODE: case STATION_POWER_SAVE_MODE:
wl1271_debug(DEBUG_PSM, "entering psm"); wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)",
mode, timeout);
ret = wl1271_acx_wake_up_conditions(wl, wlvif); ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.wake_up_event,
wl->conf.conn.listen_interval);
if (ret < 0) { if (ret < 0) {
wl1271_error("couldn't set wake up conditions"); wl1271_error("couldn't set wake up conditions");
return ret; return ret;
} }
ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE); ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout);
if (ret < 0) if (ret < 0)
return ret; return ret;
set_bit(WLVIF_FLAG_PSM, &wlvif->flags); set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
/* enable beacon early termination. Not relevant for 5GHz */
if (wlvif->band == IEEE80211_BAND_2GHZ) {
ret = wl1271_acx_bet_enable(wl, wlvif, true);
if (ret < 0)
return ret;
}
break; break;
case STATION_ACTIVE_MODE: case STATION_ACTIVE_MODE:
default:
wl1271_debug(DEBUG_PSM, "leaving psm"); wl1271_debug(DEBUG_PSM, "leaving psm");
/* disable beacon early termination */ /* disable beacon early termination */
...@@ -191,12 +202,15 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -191,12 +202,15 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
return ret; return ret;
} }
ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE); ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
clear_bit(WLVIF_FLAG_PSM, &wlvif->flags); clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
break; break;
default:
wl1271_warning("trying to set ps to unsupported mode %d", mode);
ret = -EINVAL;
} }
return ret; return ret;
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "acx.h" #include "acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
enum wl1271_cmd_ps_mode mode, u32 rates, bool send); enum wl1271_cmd_ps_mode mode);
void wl1271_ps_elp_sleep(struct wl1271 *wl); void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl); int wl1271_ps_elp_wakeup(struct wl1271 *wl);
void wl1271_elp_work(struct work_struct *work); void wl1271_elp_work(struct work_struct *work);
......
...@@ -525,4 +525,31 @@ b12-b0 - Supported Rate indicator bits as defined below. ...@@ -525,4 +525,31 @@ b12-b0 - Supported Rate indicator bits as defined below.
*/ */
#define INTR_TRIG_TX_PROC1 BIT(18) #define INTR_TRIG_TX_PROC1 BIT(18)
#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
#define WL127X_PG_MAJOR_VER_MASK 0x3
#define WL127X_PG_MAJOR_VER_OFFSET 0x0
#define WL127X_PG_MINOR_VER_MASK 0xc
#define WL127X_PG_MINOR_VER_OFFSET 0x2
#define WL128X_PG_MAJOR_VER_MASK 0xc
#define WL128X_PG_MAJOR_VER_OFFSET 0x2
#define WL128X_PG_MINOR_VER_MASK 0x3
#define WL128X_PG_MINOR_VER_OFFSET 0x0
#define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \
WL127X_PG_MAJOR_VER_OFFSET)
#define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \
WL127X_PG_MINOR_VER_OFFSET)
#define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \
WL128X_PG_MAJOR_VER_OFFSET)
#define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \
WL128X_PG_MINOR_VER_OFFSET)
#define WL12XX_REG_FUSE_BD_ADDR_1 0x00310eb4
#define WL12XX_REG_FUSE_BD_ADDR_2 0x00310eb8
#endif #endif
...@@ -113,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -113,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
* In PLT mode we seem to get frames and mac80211 warns about them, * In PLT mode we seem to get frames and mac80211 warns about them,
* workaround this by not retrieving them at all. * workaround this by not retrieving them at all.
*/ */
if (unlikely(wl->state == WL1271_STATE_PLT)) if (unlikely(wl->plt))
return -EINVAL; return -EINVAL;
/* the data read starts with the descriptor */ /* the data read starts with the descriptor */
......
...@@ -38,7 +38,6 @@ void wl1271_scan_complete_work(struct work_struct *work) ...@@ -38,7 +38,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
int ret; int ret;
bool is_sta, is_ibss;
dwork = container_of(work, struct delayed_work, work); dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work); wl = container_of(dwork, struct wl1271, scan_complete_work);
...@@ -70,15 +69,6 @@ void wl1271_scan_complete_work(struct work_struct *work) ...@@ -70,15 +69,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq);
} }
/* return to ROC if needed */
is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS);
is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
(is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) &&
!test_bit(wlvif->dev_role_id, wl->roc_map)) {
/* restore remain on channel */
wl12xx_start_dev(wl, wlvif);
}
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
if (wl->scan.failed) { if (wl->scan.failed) {
...@@ -182,14 +172,23 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -182,14 +172,23 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
goto out; goto out;
} }
if (wl->conf.scan.split_scan_timeout)
scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
if (passive) if (passive)
scan_options |= WL1271_SCAN_OPT_PASSIVE; scan_options |= WL1271_SCAN_OPT_PASSIVE;
if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) { if (wlvif->bss_type == BSS_TYPE_AP_BSS ||
test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
cmd->params.role_id = wlvif->role_id;
else
cmd->params.role_id = wlvif->dev_role_id;
if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
cmd->params.role_id = wlvif->role_id;
cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.scan_options = cpu_to_le16(scan_options);
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
...@@ -202,7 +201,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -202,7 +201,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
cmd->params.tid_trigger = 0; cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
if (band == IEEE80211_BAND_2GHZ) if (band == IEEE80211_BAND_2GHZ)
...@@ -217,16 +216,17 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, ...@@ -217,16 +216,17 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
memcpy(cmd->addr, vif->addr, ETH_ALEN); memcpy(cmd->addr, vif->addr, ETH_ALEN);
ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid, ret = wl12xx_cmd_build_probe_req(wl, wlvif,
wl->scan.ssid_len, wl->scan.req->ie, cmd->params.role_id, band,
wl->scan.req->ie_len, band); wl->scan.ssid, wl->scan.ssid_len,
wl->scan.req->ie,
wl->scan.req->ie_len);
if (ret < 0) { if (ret < 0) {
wl1271_error("PROBE request template failed"); wl1271_error("PROBE request template failed");
goto out; goto out;
} }
/* disable the timeout */ trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
trigger->timeout = 0;
ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
sizeof(*trigger), 0); sizeof(*trigger), 0);
if (ret < 0) { if (ret < 0) {
...@@ -658,11 +658,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, ...@@ -658,11 +658,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
} }
if (!force_passive && cfg->active[0]) { if (!force_passive && cfg->active[0]) {
ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid, u8 band = IEEE80211_BAND_2GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
wlvif->dev_role_id, band,
req->ssids[0].ssid,
req->ssids[0].ssid_len, req->ssids[0].ssid_len,
ies->ie[IEEE80211_BAND_2GHZ], ies->ie[band],
ies->len[IEEE80211_BAND_2GHZ], ies->len[band]);
IEEE80211_BAND_2GHZ);
if (ret < 0) { if (ret < 0) {
wl1271_error("2.4GHz PROBE request template failed"); wl1271_error("2.4GHz PROBE request template failed");
goto out; goto out;
...@@ -670,11 +672,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, ...@@ -670,11 +672,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
} }
if (!force_passive && cfg->active[1]) { if (!force_passive && cfg->active[1]) {
ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid, u8 band = IEEE80211_BAND_5GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
wlvif->dev_role_id, band,
req->ssids[0].ssid,
req->ssids[0].ssid_len, req->ssids[0].ssid_len,
ies->ie[IEEE80211_BAND_5GHZ], ies->ie[band],
ies->len[IEEE80211_BAND_5GHZ], ies->len[band]);
IEEE80211_BAND_5GHZ);
if (ret < 0) { if (ret < 0) {
wl1271_error("5GHz PROBE request template failed"); wl1271_error("5GHz PROBE request template failed");
goto out; goto out;
......
...@@ -48,7 +48,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl); ...@@ -48,7 +48,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_CURRENT_TX_PWR 0 #define WL1271_SCAN_CURRENT_TX_PWR 0
#define WL1271_SCAN_OPT_ACTIVE 0 #define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1 #define WL1271_SCAN_OPT_PASSIVE 1
#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2 #define WL1271_SCAN_OPT_SPLIT_SCAN 2
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 #define WL1271_SCAN_OPT_PRIORITY_HIGH 4
/* scan even if we fail to enter psm */ /* scan even if we fail to enter psm */
#define WL1271_SCAN_OPT_FORCE 8 #define WL1271_SCAN_OPT_FORCE 8
......
...@@ -74,6 +74,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, ...@@ -74,6 +74,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
struct sdio_func *func = dev_to_sdio_func(glue->dev); struct sdio_func *func = dev_to_sdio_func(glue->dev);
sdio_claim_host(func);
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
...@@ -88,6 +90,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, ...@@ -88,6 +90,8 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
addr, len); addr, len);
} }
sdio_release_host(func);
if (ret) if (ret)
dev_err(child->parent, "sdio read failed (%d)\n", ret); dev_err(child->parent, "sdio read failed (%d)\n", ret);
} }
...@@ -99,6 +103,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, ...@@ -99,6 +103,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
struct sdio_func *func = dev_to_sdio_func(glue->dev); struct sdio_func *func = dev_to_sdio_func(glue->dev);
sdio_claim_host(func);
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
...@@ -113,6 +119,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, ...@@ -113,6 +119,8 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
ret = sdio_memcpy_toio(func, addr, buf, len); ret = sdio_memcpy_toio(func, addr, buf, len);
} }
sdio_release_host(func);
if (ret) if (ret)
dev_err(child->parent, "sdio write failed (%d)\n", ret); dev_err(child->parent, "sdio write failed (%d)\n", ret);
} }
...@@ -136,6 +144,7 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) ...@@ -136,6 +144,7 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
sdio_claim_host(func); sdio_claim_host(func);
sdio_enable_func(func); sdio_enable_func(func);
sdio_release_host(func);
out: out:
return ret; return ret;
...@@ -146,6 +155,7 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) ...@@ -146,6 +155,7 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
int ret; int ret;
struct sdio_func *func = dev_to_sdio_func(glue->dev); struct sdio_func *func = dev_to_sdio_func(glue->dev);
sdio_claim_host(func);
sdio_disable_func(func); sdio_disable_func(func);
sdio_release_host(func); sdio_release_host(func);
...@@ -314,9 +324,6 @@ static int wl1271_suspend(struct device *dev) ...@@ -314,9 +324,6 @@ static int wl1271_suspend(struct device *dev)
dev_err(dev, "error while trying to keep power\n"); dev_err(dev, "error while trying to keep power\n");
goto out; goto out;
} }
/* release host */
sdio_release_host(func);
} }
out: out:
return ret; return ret;
...@@ -324,15 +331,7 @@ static int wl1271_suspend(struct device *dev) ...@@ -324,15 +331,7 @@ static int wl1271_suspend(struct device *dev)
static int wl1271_resume(struct device *dev) static int wl1271_resume(struct device *dev)
{ {
struct sdio_func *func = dev_to_sdio_func(dev);
struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
struct wl1271 *wl = platform_get_drvdata(glue->core);
dev_dbg(dev, "wl1271 resume\n"); dev_dbg(dev, "wl1271 resume\n");
if (wl->wow_enabled) {
/* claim back host */
sdio_claim_host(func);
}
return 0; return 0;
} }
...@@ -371,5 +370,9 @@ module_exit(wl1271_exit); ...@@ -371,5 +370,9 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL127X_FW_NAME); MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
MODULE_FIRMWARE(WL128X_FW_NAME); MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
...@@ -433,6 +433,10 @@ module_exit(wl1271_exit); ...@@ -433,6 +433,10 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL127X_FW_NAME); MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
MODULE_FIRMWARE(WL128X_FW_NAME); MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
MODULE_ALIAS("spi:wl1271"); MODULE_ALIAS("spi:wl1271");
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "acx.h" #include "acx.h"
#include "reg.h" #include "reg.h"
#include "ps.h" #include "ps.h"
#include "io.h"
#define WL1271_TM_MAX_DATA_LENGTH 1024 #define WL1271_TM_MAX_DATA_LENGTH 1024
...@@ -41,6 +42,7 @@ enum wl1271_tm_commands { ...@@ -41,6 +42,7 @@ enum wl1271_tm_commands {
WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */
WL1271_TM_CMD_SET_PLT_MODE, WL1271_TM_CMD_SET_PLT_MODE,
WL1271_TM_CMD_RECOVER, WL1271_TM_CMD_RECOVER,
WL1271_TM_CMD_GET_MAC,
__WL1271_TM_CMD_AFTER_LAST __WL1271_TM_CMD_AFTER_LAST
}; };
...@@ -264,6 +266,52 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) ...@@ -264,6 +266,52 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
return 0; return 0;
} }
static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[])
{
struct sk_buff *skb;
u8 mac_addr[ETH_ALEN];
int ret = 0;
mutex_lock(&wl->mutex);
if (!wl->plt) {
ret = -EINVAL;
goto out;
}
if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) {
ret = -EOPNOTSUPP;
goto out;
}
mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16);
mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8);
mac_addr[2] = (u8) wl->fuse_oui_addr;
mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16);
mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8);
mac_addr[5] = (u8) wl->fuse_nic_addr;
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN);
if (!skb) {
ret = -ENOMEM;
goto out;
}
NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr);
ret = cfg80211_testmode_reply(skb);
if (ret < 0)
goto out;
out:
mutex_unlock(&wl->mutex);
return ret;
nla_put_failure:
kfree_skb(skb);
ret = -EMSGSIZE;
goto out;
}
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
...@@ -288,6 +336,8 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) ...@@ -288,6 +336,8 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
return wl1271_tm_cmd_set_plt_mode(wl, tb); return wl1271_tm_cmd_set_plt_mode(wl, tb);
case WL1271_TM_CMD_RECOVER: case WL1271_TM_CMD_RECOVER:
return wl1271_tm_cmd_recover(wl, tb); return wl1271_tm_cmd_recover(wl, tb);
case WL1271_TM_CMD_GET_MAC:
return wl12xx_tm_cmd_get_mac(wl, tb);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -77,35 +77,6 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id) ...@@ -77,35 +77,6 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
} }
} }
static int wl1271_tx_update_filters(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
int ret;
hdr = (struct ieee80211_hdr *)skb->data;
/*
* stop bssid-based filtering before transmitting authentication
* requests. this way the hw will never drop authentication
* responses coming from BSSIDs it isn't familiar with (e.g. on
* roaming)
*/
if (!ieee80211_is_auth(hdr->frame_control))
return 0;
if (wlvif->dev_hlid != WL12XX_INVALID_LINK_ID)
goto out;
wl1271_debug(DEBUG_CMD, "starting device role for roaming");
ret = wl12xx_start_dev(wl, wlvif);
if (ret < 0)
goto out;
out:
return 0;
}
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -187,8 +158,6 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -187,8 +158,6 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (wlvif->bss_type == BSS_TYPE_AP_BSS) if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return wl12xx_tx_get_hlid_ap(wl, wlvif, skb); return wl12xx_tx_get_hlid_ap(wl, wlvif, skb);
wl1271_tx_update_filters(wl, wlvif, skb);
if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
!ieee80211_is_auth(hdr->frame_control) && !ieee80211_is_auth(hdr->frame_control) &&
...@@ -286,16 +255,20 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -286,16 +255,20 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
int aligned_len, ac, rate_idx; int aligned_len, ac, rate_idx;
s64 hosttime; s64 hosttime;
u16 tx_attr = 0; u16 tx_attr = 0;
__le16 frame_control;
struct ieee80211_hdr *hdr;
u8 *frame_start;
bool is_dummy; bool is_dummy;
desc = (struct wl1271_tx_hw_descr *) skb->data; desc = (struct wl1271_tx_hw_descr *) skb->data;
frame_start = (u8 *)(desc + 1);
hdr = (struct ieee80211_hdr *)(frame_start + extra);
frame_control = hdr->frame_control;
/* relocate space for security header */ /* relocate space for security header */
if (extra) { if (extra) {
void *framestart = skb->data + sizeof(*desc); int hdrlen = ieee80211_hdrlen(frame_control);
u16 fc = *(u16 *)(framestart + extra); memmove(frame_start, hdr, hdrlen);
int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc));
memmove(framestart, framestart + extra, hdrlen);
} }
/* configure packet life time */ /* configure packet life time */
...@@ -384,6 +357,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -384,6 +357,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
desc->wl127x_mem.total_mem_blocks); desc->wl127x_mem.total_mem_blocks);
} }
/* for WEP shared auth - no fw encryption is needed */
if (ieee80211_is_auth(frame_control) &&
ieee80211_has_protected(frame_control))
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
desc->tx_attr = cpu_to_le16(tx_attr); desc->tx_attr = cpu_to_le16(tx_attr);
} }
...@@ -408,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -408,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (info->control.hw_key && if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
extra = WL1271_TKIP_IV_SPACE; extra = WL1271_EXTRA_SPACE_TKIP;
if (info->control.hw_key) { if (info->control.hw_key) {
bool is_wep; bool is_wep;
...@@ -795,6 +773,18 @@ void wl1271_tx_work(struct work_struct *work) ...@@ -795,6 +773,18 @@ void wl1271_tx_work(struct work_struct *work)
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
} }
static u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
{
u8 flags = 0;
if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN &&
rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX)
flags |= IEEE80211_TX_RC_MCS;
if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI)
flags |= IEEE80211_TX_RC_SHORT_GI;
return flags;
}
static void wl1271_tx_complete_packet(struct wl1271 *wl, static void wl1271_tx_complete_packet(struct wl1271 *wl,
struct wl1271_tx_hw_res_descr *result) struct wl1271_tx_hw_res_descr *result)
{ {
...@@ -804,6 +794,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -804,6 +794,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
struct sk_buff *skb; struct sk_buff *skb;
int id = result->id; int id = result->id;
int rate = -1; int rate = -1;
u8 rate_flags = 0;
u8 retries = 0; u8 retries = 0;
/* check for id legality */ /* check for id legality */
...@@ -830,6 +821,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -830,6 +821,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
rate = wl1271_rate_to_idx(result->rate_class_index, rate = wl1271_rate_to_idx(result->rate_class_index,
wlvif->band); wlvif->band);
rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
retries = result->ack_failures; retries = result->ack_failures;
} else if (result->status == TX_RETRY_EXCEEDED) { } else if (result->status == TX_RETRY_EXCEEDED) {
wl->stats.excessive_retries++; wl->stats.excessive_retries++;
...@@ -838,7 +830,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -838,7 +830,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
info->status.rates[0].idx = rate; info->status.rates[0].idx = rate;
info->status.rates[0].count = retries; info->status.rates[0].count = retries;
info->status.rates[0].flags = 0; info->status.rates[0].flags = rate_flags;
info->status.ack_signal = -1; info->status.ack_signal = -1;
wl->stats.retry_count += result->ack_failures; wl->stats.retry_count += result->ack_failures;
...@@ -869,8 +861,9 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -869,8 +861,9 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
if (info->control.hw_key && if (info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb); int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
skb_pull(skb, WL1271_TKIP_IV_SPACE); hdrlen);
skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
} }
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
...@@ -1012,9 +1005,9 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ...@@ -1012,9 +1005,9 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
info->control.hw_key->cipher == info->control.hw_key->cipher ==
WLAN_CIPHER_SUITE_TKIP) { WLAN_CIPHER_SUITE_TKIP) {
int hdrlen = ieee80211_get_hdrlen_from_skb(skb); int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + WL1271_TKIP_IV_SPACE, memmove(skb->data + WL1271_EXTRA_SPACE_TKIP,
skb->data, hdrlen); skb->data, hdrlen);
skb_pull(skb, WL1271_TKIP_IV_SPACE); skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
} }
info->status.rates[0].idx = -1; info->status.rates[0].idx = -1;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11))
#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12)
#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) #define TX_HW_ATTR_TX_DUMMY_REQ BIT(13)
#define TX_HW_ATTR_HOST_ENCRYPT BIT(14)
#define TX_HW_ATTR_OFST_SAVE_RETRIES 0 #define TX_HW_ATTR_OFST_SAVE_RETRIES 0
#define TX_HW_ATTR_OFST_HEADER_PAD 1 #define TX_HW_ATTR_OFST_HEADER_PAD 1
...@@ -51,7 +52,9 @@ ...@@ -51,7 +52,9 @@
#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf
#define WL1271_TX_ALIGN_TO 4 #define WL1271_TX_ALIGN_TO 4
#define WL1271_TKIP_IV_SPACE 4 #define WL1271_EXTRA_SPACE_TKIP 4
#define WL1271_EXTRA_SPACE_AES 8
#define WL1271_EXTRA_SPACE_MAX 8
/* Used for management frames and dummy packets */ /* Used for management frames and dummy packets */
#define WL1271_TID_MGMT 7 #define WL1271_TID_MGMT 7
......
...@@ -35,8 +35,14 @@ ...@@ -35,8 +35,14 @@
#include "conf.h" #include "conf.h"
#include "ini.h" #include "ini.h"
#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin" #define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin" #define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
/* /*
* wl127x and wl128x are using the same NVS file name. However, the * wl127x and wl128x are using the same NVS file name. However, the
...@@ -90,7 +96,13 @@ ...@@ -90,7 +96,13 @@
enum wl1271_state { enum wl1271_state {
WL1271_STATE_OFF, WL1271_STATE_OFF,
WL1271_STATE_ON, WL1271_STATE_ON,
WL1271_STATE_PLT, };
enum wl12xx_fw_type {
WL12XX_FW_TYPE_NONE,
WL12XX_FW_TYPE_NORMAL,
WL12XX_FW_TYPE_MULTI,
WL12XX_FW_TYPE_PLT,
}; };
enum wl1271_partition_type { enum wl1271_partition_type {
...@@ -247,6 +259,7 @@ enum wl12xx_flags { ...@@ -247,6 +259,7 @@ enum wl12xx_flags {
WL1271_FLAG_PENDING_WORK, WL1271_FLAG_PENDING_WORK,
WL1271_FLAG_SOFT_GEMINI, WL1271_FLAG_SOFT_GEMINI,
WL1271_FLAG_RECOVERY_IN_PROGRESS, WL1271_FLAG_RECOVERY_IN_PROGRESS,
WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
}; };
enum wl12xx_vif_flags { enum wl12xx_vif_flags {
...@@ -254,8 +267,7 @@ enum wl12xx_vif_flags { ...@@ -254,8 +267,7 @@ enum wl12xx_vif_flags {
WLVIF_FLAG_STA_ASSOCIATED, WLVIF_FLAG_STA_ASSOCIATED,
WLVIF_FLAG_IBSS_JOINED, WLVIF_FLAG_IBSS_JOINED,
WLVIF_FLAG_AP_STARTED, WLVIF_FLAG_AP_STARTED,
WLVIF_FLAG_PSM, WLVIF_FLAG_IN_PS,
WLVIF_FLAG_PSM_REQUESTED,
WLVIF_FLAG_STA_STATE_SENT, WLVIF_FLAG_STA_STATE_SENT,
WLVIF_FLAG_RX_STREAMING_STARTED, WLVIF_FLAG_RX_STREAMING_STARTED,
WLVIF_FLAG_PSPOLL_FAILURE, WLVIF_FLAG_PSPOLL_FAILURE,
...@@ -295,6 +307,9 @@ struct wl1271 { ...@@ -295,6 +307,9 @@ struct wl1271 {
spinlock_t wl_lock; spinlock_t wl_lock;
enum wl1271_state state; enum wl1271_state state;
enum wl12xx_fw_type fw_type;
bool plt;
u8 last_vif_count;
struct mutex mutex; struct mutex mutex;
unsigned long flags; unsigned long flags;
...@@ -313,7 +328,12 @@ struct wl1271 { ...@@ -313,7 +328,12 @@ struct wl1271 {
s8 hw_pg_ver; s8 hw_pg_ver;
u8 mac_addr[ETH_ALEN]; /* address read from the fuse ROM */
u32 fuse_oui_addr;
u32 fuse_nic_addr;
/* we have up to 2 MAC addresses */
struct mac_address addresses[2];
int channel; int channel;
u8 system_hlid; u8 system_hlid;
...@@ -425,8 +445,6 @@ struct wl1271 { ...@@ -425,8 +445,6 @@ struct wl1271 {
struct wl12xx_fw_status *fw_status; struct wl12xx_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if; struct wl1271_tx_hw_res_if *tx_res_if;
struct ieee80211_vif *vif;
/* Current chipset configuration */ /* Current chipset configuration */
struct conf_drv_settings conf; struct conf_drv_settings conf;
...@@ -503,6 +521,8 @@ struct wl12xx_vif { ...@@ -503,6 +521,8 @@ struct wl12xx_vif {
u8 basic_rate_idx; u8 basic_rate_idx;
u8 ap_rate_idx; u8 ap_rate_idx;
u8 p2p_rate_idx; u8 p2p_rate_idx;
bool qos;
} sta; } sta;
struct { struct {
u8 global_hlid; u8 global_hlid;
...@@ -560,12 +580,6 @@ struct wl12xx_vif { ...@@ -560,12 +580,6 @@ struct wl12xx_vif {
/* Session counter for the chipset */ /* Session counter for the chipset */
int session_counter; int session_counter;
struct completion *ps_compl;
struct delayed_work pspoll_work;
/* counter for ps-poll delivery failures */
int ps_poll_failures;
/* retry counter for PSM entries */ /* retry counter for PSM entries */
u8 psm_entry_retry; u8 psm_entry_retry;
...@@ -575,6 +589,10 @@ struct wl12xx_vif { ...@@ -575,6 +589,10 @@ struct wl12xx_vif {
int rssi_thold; int rssi_thold;
int last_rssi_event; int last_rssi_event;
/* save the current encryption type for auto-arp config */
u8 encryption_type;
__be32 ip_addr;
/* RX BA constraint value */ /* RX BA constraint value */
bool ba_support; bool ba_support;
bool ba_allowed; bool ba_allowed;
......
...@@ -117,7 +117,7 @@ struct wl12xx_ps_poll_template { ...@@ -117,7 +117,7 @@ struct wl12xx_ps_poll_template {
} __packed; } __packed;
struct wl12xx_arp_rsp_template { struct wl12xx_arp_rsp_template {
struct ieee80211_hdr_3addr hdr; /* not including ieee80211 header */
u8 llc_hdr[sizeof(rfc1042_header)]; u8 llc_hdr[sizeof(rfc1042_header)];
__be16 llc_type; __be16 llc_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment