/* * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) */ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask, bool *timeout) { u32 *events_vector; u32 event; unsigned long timeout_time; u16 poll_count = 0; int ret = 0; *timeout = false; events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA); if (!events_vector) return -ENOMEM; timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); do { if (time_after(jiffies, timeout_time)) { wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", (int)mask); *timeout = true; goto out; } poll_count++; if (poll_count < WL1271_WAIT_EVENT_FAST_POLL_COUNT) usleep_range(50, 51); else usleep_range(1000, 5000); /* read from both event fields */ ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector, sizeof(*events_vector), false); if (ret < 0) goto out; event = *events_vector & mask; ret = wlcore_read(wl, wl->mbox_ptr[1], events_vector, sizeof(*events_vector), false); if (ret < 0) goto out; event |= *events_vector & mask; } while (!event); out: kfree(events_vector); return ret; }
static int wlcore_boot_static_data(struct wl1271 *wl) { struct wl1271_static_data *static_data; size_t len = sizeof(*static_data) + wl->static_data_priv_len; int ret; static_data = kmalloc(len, GFP_KERNEL); if (!static_data) { ret = -ENOMEM; goto out; } ret = wlcore_read(wl, wl->cmd_box_addr, static_data, len, false); if (ret < 0) goto out_free; ret = wlcore_boot_parse_fw_ver(wl, static_data); if (ret < 0) goto out_free; ret = wlcore_validate_fw_ver(wl); if (ret < 0) goto out_free; ret = wlcore_handle_static_data(wl, static_data); if (ret < 0) goto out_free; out_free: kfree(static_data); out: 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 * return the cmd status code on success. */ static int __wlcore_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; u16 status; u16 poll_count = 0; if (unlikely(wl->state == WLCORE_STATE_RESTARTING && id != CMD_STOP_FWLOGGER)) return -EIO; if (WARN_ON_ONCE(len < sizeof(*cmd))) 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) return ret; /* * 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) return ret; timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) return ret; while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); return -ETIMEDOUT; } 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) return ret; } /* 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) return ret; status = le16_to_cpu(cmd->status); ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); if (ret < 0) return ret; return status; }