void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; vif = wl->scan_vif; wlvif = wl12xx_vif_to_data(vif); /* * Rearm the tx watchdog just before idling scan. This * prevents just-finished scans from triggering the watchdog */ wl12xx_rearm_tx_watchdog_locked(wl); wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { /* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } wlcore_cmd_regdomain_config_locked(wl); ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) { wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); wl12xx_queue_recovery_work(wl); return 0; }
int wl1271_ps_elp_wakeup(struct wl1271 *wl) { DECLARE_COMPLETION_ONSTACK(compl); unsigned long flags; int ret; u32 start_time = jiffies; bool pending = false; if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)) return 0; cancel_delayed_work(&wl->elp_work); if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) return 0; wl1271_debug(DEBUG_PSM, "waking up chip from elp"); spin_lock_irqsave(&wl->wl_lock, flags); if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) pending = true; else wl->elp_compl = &compl; spin_unlock_irqrestore(&wl->wl_lock, flags); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); if (!pending) { ret = wait_for_completion_timeout( &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); if (ret == 0) { wl1271_error("ELP wakeup timeout!"); wl12xx_queue_recovery_work(wl); ret = -ETIMEDOUT; goto err; } else if (ret < 0) { wl1271_error("ELP wakeup completion error."); goto err; } } clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies - start_time)); goto out; err: spin_lock_irqsave(&wl->wl_lock, flags); wl->elp_compl = NULL; spin_unlock_irqrestore(&wl->wl_lock, flags); return ret; out: return 0; }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; int ret; bool is_sta, is_ibss; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { /* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req(wl, wl->probereq); } /* return to ROC if needed */ is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); is_ibss = (wl->bss_type == BSS_TYPE_IBSS); if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) && !test_bit(wl->dev_role_id, wl->roc_map)) { /* restore remain on channel */ wl12xx_cmd_role_start_dev(wl); wl12xx_roc(wl, wl->dev_role_id); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
static ssize_t start_recovery_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; mutex_lock(&wl->mutex); wl12xx_queue_recovery_work(wl); mutex_unlock(&wl->mutex); return count; }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; vif = wl->scan_vif; wlvif = wl12xx_vif_to_data(vif); wl12xx_rearm_tx_watchdog_locked(wl); wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) { int ret; ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); if (ret != 0) { wl12xx_queue_recovery_work(wl); return ret; } return 0; }
/* use this function to stop ibss as well */ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_stop *cmd; int ret; bool timeout = false; if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) return -EINVAL; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id); cmd->role_id = wlvif->role_id; cmd->disc_type = DISCONNECT_IMMEDIATE; cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd role stop sta"); goto out_free; } /* * Sometimes the firmware doesn't send this event, so we just * time out without failing. Queue recovery for other * failures. */ ret = wl1271_cmd_wait_for_event_or_timeout(wl, ROLE_STOP_COMPLETE_EVENT_ID, &timeout); if (ret) wl12xx_queue_recovery_work(wl); wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: kfree(cmd); out: return ret; }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, false); /* restore hardware connection monitoring template */ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { if (wl1271_ps_elp_wakeup(wl) == 0) { wl1271_cmd_build_ap_probe_req(wl, wl->probereq); wl1271_ps_elp_sleep(wl); } } if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } out: mutex_unlock(&wl->mutex); }
/* * send command to fw and return cmd status on success * valid_rets contains a bitmap of allowed error codes */ int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len, unsigned long valid_rets) { int ret = __wlcore_cmd_send(wl, id, buf, len, res_len); if (ret < 0) goto fail; /* success is always a valid status */ valid_rets |= BIT(CMD_STATUS_SUCCESS); if (ret >= MAX_COMMAND_STATUS || !test_bit(ret, &valid_rets)) { wl1271_error("command execute failure %d", ret); ret = -EIO; goto fail; } return ret; fail: wl12xx_queue_recovery_work(wl); return ret; }
/* * send command to firmware * * @wl: wl struct * @id: command id * @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, size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; u32 intr; int ret = 0; u16 status; u16 poll_count = 0; if (WARN_ON(unlikely(wl->state == WLCORE_STATE_RESTARTING))) return -EIO; cmd = buf; cmd->id = cpu_to_le16(id); cmd->status = 0; WARN_ON(len % 4 != 0); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); if (ret < 0) goto fail; /* * TODO: we just need this because one bit is in a different * place. Is there any better way? */ ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); if (ret < 0) goto fail; timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) goto fail; while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); ret = -ETIMEDOUT; goto fail; } poll_count++; if (poll_count < WL1271_CMD_FAST_POLL_COUNT) udelay(10); else msleep(1); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) goto fail; } /* read back the status code of the command */ if (res_len == 0) res_len = sizeof(struct wl1271_cmd_header); ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); if (ret < 0) goto fail; status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { wl1271_error("command execute failure %d", status); ret = -EIO; goto fail; } ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); if (ret < 0) goto fail; return 0; fail: wl12xx_queue_recovery_work(wl); return ret; }
/* * send command to firmware * * @wl: wl struct * @id: command id * @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, size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; u32 intr; int ret = 0; u16 status; u16 poll_count = 0; cmd = buf; cmd->id = cpu_to_le16(id); cmd->status = 0; WARN_ON(len % 4 != 0); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); wl1271_write(wl, wl->cmd_box_addr, buf, len, false); wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); ret = -ETIMEDOUT; goto fail; } poll_count++; if (poll_count < WL1271_CMD_FAST_POLL_COUNT) udelay(10); else msleep(1); intr = wl1271_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_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; goto fail; } wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); return 0; fail: WARN_ON(1); wl12xx_queue_recovery_work(wl); return ret; }