diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/Kconfig | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_acx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_boot.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.c | 99 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_conf.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_event.c | 53 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_event.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_init.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_rx.c | 2 |
13 files changed, 132 insertions, 82 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 88060e11754..785e0244e30 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -1,6 +1,6 @@ menuconfig WL12XX tristate "TI wl12xx driver support" - depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && EXPERIMENTAL ---help--- This will enable TI wl12xx driver support. The drivers make use of the mac80211 stack. @@ -42,6 +42,7 @@ config WL1251_SDIO config WL1271 tristate "TI wl1271 support" depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS + depends on INET select FW_LOADER select CRC7 ---help--- diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 48b0bfd6c55..da3bf1cebc0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1311,7 +1311,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->channel_change_time = 10000; wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_SUPPORTS_PS; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 566f1521ec2..94359b1a861 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -417,6 +417,9 @@ struct wl1271 { /* PSM mode requested */ bool psm_requested; + /* retry counter for PSM entries */ + u8 psm_entry_retry; + /* in dBm */ int power_level; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index bf5a8680a46..5cc89bbdac7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -141,7 +141,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) * calibration, to avoid distortions */ /* acx->current_tx_power = power * 10; */ - acx->current_tx_power = 70; + acx->current_tx_power = 120; ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index ba4a2b4f0f5..b7c96454cca 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -380,7 +380,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) } } - if (loop >= INIT_LOOP) { + if (loop > INIT_LOOP) { wl1271_error("timeout waiting for the hardware to " "complete initialization"); return -EIO; @@ -407,7 +407,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) /* unmask required mbox events */ wl->event_mask = BSS_LOSE_EVENT_ID | - SCAN_COMPLETE_EVENT_ID; + SCAN_COMPLETE_EVENT_ID | + PS_REPORT_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 0666328ce9a..990eb01b4c7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -42,12 +42,14 @@ * @buf: buffer containing the command, must work with dma * @len: length of the buffer */ -int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; u32 intr; int ret = 0; + u16 status; cmd = buf; cmd->id = cpu_to_le16(id); @@ -74,6 +76,17 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); } + /* read back the status code of the command */ + if (res_len == 0) + res_len = sizeof(struct wl1271_cmd_header); + wl1271_spi_read(wl, wl->cmd_box_addr, cmd, res_len, false); + + status = le16_to_cpu(cmd->status); + if (status != CMD_STATUS_SUCCESS) { + wl1271_error("command execute failure %d", status); + ret = -EIO; + } + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); @@ -262,7 +275,7 @@ int wl1271_cmd_join(struct wl1271 *wl) wl->tx_security_seq_16 = 0; wl->tx_security_seq_32 = 0; - ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0); if (ret < 0) { wl1271_error("failed to initiate cmd join"); goto out_free; @@ -294,35 +307,21 @@ out: int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) { int ret; + size_t res_len = 0; wl1271_debug(DEBUG_CMD, "cmd test"); - ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); + if (answer) + res_len = buf_len; + + ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); if (ret < 0) { wl1271_warning("TEST command failed"); return ret; } - if (answer) { - struct wl1271_command *cmd_answer; - u16 status; - - /* - * The test command got in, we can read the answer. - * The answer would be a wl1271_command, where the - * parameter array contains the actual answer. - */ - wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false); - - cmd_answer = buf; - status = le16_to_cpu(cmd_answer->header.status); - - if (status != CMD_STATUS_SUCCESS) - wl1271_error("TEST command answer error: %d", status); - } - - return 0; + return ret; } /** @@ -345,21 +344,10 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) /* payload length, does not include any headers */ acx->len = cpu_to_le16(len - sizeof(*acx)); - ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); - if (ret < 0) { + ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); + if (ret < 0) wl1271_error("INTERROGATE command failed"); - goto out; - } - /* the interrogate command got in, we can read the answer */ - wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false); - - acx = buf; - if (le16_to_cpu(acx->cmd.status) != CMD_STATUS_SUCCESS) - wl1271_error("INTERROGATE command error: %d", - le16_to_cpu(acx->cmd.status)); - -out: return ret; } @@ -383,7 +371,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) /* payload length, does not include any headers */ acx->len = cpu_to_le16(len - sizeof(*acx)); - ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); + ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); if (ret < 0) { wl1271_warning("CONFIGURE command NOK"); return ret; @@ -416,7 +404,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) cmd_tx = CMD_DISABLE_TX; } - ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("rx %s cmd for channel %d failed", enable ? "start" : "stop", channel); @@ -426,7 +414,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); - ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); @@ -468,7 +456,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params)); + sizeof(*ps_params), 0); if (ret < 0) { wl1271_error("cmd set_ps_mode failed"); goto out; @@ -499,19 +487,14 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, cmd->addr = cpu_to_le32(addr); cmd->size = cpu_to_le32(len); - ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd), + sizeof(*cmd)); if (ret < 0) { wl1271_error("read memory command failed: %d", ret); goto out; } - /* the read command got in, we can now read the answer */ - wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false); - - if (le16_to_cpu(cmd->header.status) != CMD_STATUS_SUCCESS) - wl1271_error("error in read command result: %d", - le16_to_cpu(cmd->header.status)); - + /* the read command got in */ memcpy(answer, cmd->value, len); out: @@ -613,7 +596,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, trigger->timeout = 0; ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger)); + sizeof(*trigger), 0); if (ret < 0) { wl1271_error("trigger scan to failed for hw scan"); goto out; @@ -636,20 +619,10 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, } } - ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); if (ret < 0) { wl1271_error("SCAN failed"); - goto out; - } - - wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params), - false); - - if (le16_to_cpu(params->header.status) != CMD_STATUS_SUCCESS) { - wl1271_error("Scan command error: %d", - le16_to_cpu(params->header.status)); wl->scanning = false; - ret = -EIO; goto out; } @@ -684,7 +657,7 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, if (buf) memcpy(cmd->template_data, buf, buf_len); - ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("cmd set_template failed: %d", ret); goto out_free; @@ -863,7 +836,7 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) cmd->key_action = cpu_to_le16(KEY_SET_ID); cmd->key_type = KEY_WEP; - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("cmd set_default_wep_key failed: %d", ret); goto out; @@ -920,7 +893,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("could not set keys"); goto out; @@ -950,7 +923,7 @@ int wl1271_cmd_disconnect(struct wl1271 *wl) /* disconnect reason is not used in immediate disconnections */ cmd->type = DISCONNECT_IMMEDIATE; - ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to send disconnect command"); goto out_free; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 174b8209dbf..9d7061b3c8a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -29,7 +29,8 @@ struct acx_header; -int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len); +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len); int wl1271_cmd_join(struct wl1271 *wl); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 061d47520a3..565373ede26 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -712,6 +712,14 @@ struct conf_conn_settings { * Range 0 - 255 */ u8 bet_max_consecutive; + + /* + * Specifies the maximum number of times to try PSM entry if it fails + * (if sending the appropriate null-func message fails.) + * + * Range 0 - 255 + */ + u8 psm_entry_retries; }; #define CONF_SR_ERR_TBL_MAX_VALUES 14 diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 31d396ba918..e135d894b42 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -68,6 +68,40 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, return 0; } +static int wl1271_event_ps_report(struct wl1271 *wl, + struct event_mailbox *mbox, + bool *beacon_loss) +{ + int ret = 0; + + wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); + + switch (mbox->ps_status) { + case EVENT_ENTER_POWER_SAVE_FAIL: + if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { + wl->psm_entry_retry++; + wl1271_error("PSM entry failed, retrying %d\n", + wl->psm_entry_retry); + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else { + wl->psm_entry_retry = 0; + *beacon_loss = true; + } + break; + case EVENT_ENTER_POWER_SAVE_SUCCESS: + wl->psm_entry_retry = 0; + break; + case EVENT_EXIT_POWER_SAVE_FAIL: + wl1271_info("PSM exit failed"); + break; + case EVENT_EXIT_POWER_SAVE_SUCCESS: + default: + break; + } + + return ret; +} + static void wl1271_event_mbox_dump(struct event_mailbox *mbox) { wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); @@ -79,6 +113,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { int ret; u32 vector; + bool beacon_loss = false; wl1271_event_mbox_dump(mbox); @@ -101,7 +136,25 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); /* indicate to the stack, that beacons have been lost */ + beacon_loss = true; + } + + if (vector & PS_REPORT_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); + ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); + if (ret < 0) + return ret; + } + + if (beacon_loss) { + /* Obviously, it's dangerous to release the mutex while + we are holding many of the variables in the wl struct. + That's why it's done last in the function, and care must + be taken that nothing more is done after this function + returns. */ + mutex_unlock(&wl->mutex); ieee80211_beacon_loss(wl->vif); + mutex_lock(&wl->mutex); } return 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h index 3ab53d331f1..4e3f55ebb1a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.h +++ b/drivers/net/wireless/wl12xx/wl1271_event.h @@ -63,6 +63,13 @@ enum { EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, }; +enum { + EVENT_ENTER_POWER_SAVE_FAIL = 0, + EVENT_ENTER_POWER_SAVE_SUCCESS, + EVENT_EXIT_POWER_SAVE_FAIL, + EVENT_EXIT_POWER_SAVE_SUCCESS, +}; + struct event_debug_report { u8 debug_event_id; u8 num_params; diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 417b4152feb..7c2017f480e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -303,12 +303,15 @@ int wl1271_hw_init(struct wl1271 *wl) { int ret; + /* FIXME: the following parameter setting functions return error + * codes - the reason is so far unknown. The -EIO is therefore + * ignored for the time being. */ ret = wl1271_init_general_parms(wl); - if (ret < 0) + if (ret < 0 && ret != -EIO) return ret; ret = wl1271_init_radio_parms(wl); - if (ret < 0) + if (ret < 0 && ret != -EIO) return ret; /* Template settings */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 86132bb0078..d2149fcd3cf 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -222,7 +222,8 @@ static struct conf_drv_settings default_conf = { .snr_pkt_avg_weight = 10 }, .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 100 + .bet_max_consecutive = 100, + .psm_entry_retries = 3 }, .init = { .sr_err_tbl = { @@ -973,6 +974,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->rx_counter = 0; wl->elp = false; wl->psm = 0; + wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; @@ -1067,11 +1069,11 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, ret = wl1271_cmd_join(wl); if (ret < 0) goto out_sleep; - } - ret = wl1271_cmd_build_null_data(wl); - if (ret < 0) - goto out_sleep; + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) + goto out_sleep; + } wl->ssid_len = conf->ssid_len; if (wl->ssid_len) @@ -1137,10 +1139,6 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl->channel = channel; } - ret = wl1271_cmd_build_null_data(wl); - if (ret < 0) - goto out_sleep; - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { wl1271_info("psm enabled"); @@ -1165,7 +1163,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (conf->power_level != wl->power_level) { ret = wl1271_acx_tx_power(wl, conf->power_level); if (ret < 0) - goto out; + goto out_sleep; wl->power_level = conf->power_level; } @@ -1826,6 +1824,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->elp = false; wl->psm = 0; wl->psm_requested = false; + wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 37d81ab6acc..ca645f38109 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -159,7 +159,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) u8 *buf; u8 beacon = 0; - skb = dev_alloc_skb(length); + skb = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return; |