提交 ea508435 编写于 作者: E Eliad Peller 提交者: Luciano Coelho

wlcore: allow fw commands to fail

Currently, each fw command/acx that return a status code
different than CMD_STATUS_SUCCESS will trigger a recovery
in the driver.

However, it is a valid for some fw commands to fail (e.g.
due to temporary lack of resources), so add new functions
that allow passing bitmap of valid error return values.

(make the current wl1271_cmd_send/wl1271_cmd_configure
wrappers around the new functions, in order to avoid
changing the whole driver)
Signed-off-by: NEliad Peller <eliad@wizery.com>
Signed-off-by: NArik Nemtsov <arik@wizery.com>
Signed-off-by: NLuciano Coelho <coelho@ti.com>
上级 d88949b7
...@@ -48,14 +48,15 @@ ...@@ -48,14 +48,15 @@
* @id: command id * @id: command id
* @buf: buffer containing the command, must work with dma * @buf: buffer containing the command, must work with dma
* @len: length of the buffer * @len: length of the buffer
* return the cmd status code on success.
*/ */
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf,
size_t res_len) size_t len, size_t res_len)
{ {
struct wl1271_cmd_header *cmd; struct wl1271_cmd_header *cmd;
unsigned long timeout; unsigned long timeout;
u32 intr; u32 intr;
int ret = 0; int ret;
u16 status; u16 status;
u16 poll_count = 0; u16 poll_count = 0;
...@@ -71,7 +72,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -71,7 +72,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false);
if (ret < 0) if (ret < 0)
goto fail; return ret;
/* /*
* TODO: we just need this because one bit is in a different * TODO: we just need this because one bit is in a different
...@@ -79,19 +80,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -79,19 +80,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
*/ */
ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
if (ret < 0) if (ret < 0)
goto fail; return ret;
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0) if (ret < 0)
goto fail; return ret;
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout"); wl1271_error("command complete timeout");
ret = -ETIMEDOUT; return -ETIMEDOUT;
goto fail;
} }
poll_count++; poll_count++;
...@@ -102,7 +102,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -102,7 +102,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0) if (ret < 0)
goto fail; return ret;
} }
/* read back the status code of the command */ /* read back the status code of the command */
...@@ -111,28 +111,60 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -111,28 +111,60 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false);
if (ret < 0) if (ret < 0)
goto fail; return ret;
status = le16_to_cpu(cmd->status); 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, ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE); WL1271_ACX_INTR_CMD_COMPLETE);
if (ret < 0)
return ret;
return status;
}
/*
* 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) if (ret < 0)
goto fail; goto fail;
return 0; /* 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: fail:
wl12xx_queue_recovery_work(wl); wl12xx_queue_recovery_work(wl);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(wl1271_cmd_send); EXPORT_SYMBOL_GPL(wl1271_cmd_send);
/*
* wrapper for wlcore_cmd_send that accept only CMD_STATUS_SUCCESS
* return 0 on success.
*/
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len)
{
int ret = wlcore_cmd_send_failsafe(wl, id, buf, len, res_len, 0);
if (ret < 0)
return ret;
return 0;
}
/* /*
* Poll the mailbox event field until any of the bits in the mask is set or a * Poll the mailbox event field until any of the bits in the mask is set or a
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs) * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
...@@ -791,8 +823,11 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) ...@@ -791,8 +823,11 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
* @id: acx id * @id: acx id
* @buf: buffer containing acx, including all headers, must work with dma * @buf: buffer containing acx, including all headers, must work with dma
* @len: length of buf * @len: length of buf
* @valid_rets: bitmap of valid cmd status codes (i.e. return values).
* return the cmd status on success.
*/ */
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,
size_t len, unsigned long valid_rets)
{ {
struct acx_header *acx = buf; struct acx_header *acx = buf;
int ret; int ret;
...@@ -804,12 +839,26 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) ...@@ -804,12 +839,26 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
/* payload length, does not include any headers */ /* payload length, does not include any headers */
acx->len = cpu_to_le16(len - sizeof(*acx)); acx->len = cpu_to_le16(len - sizeof(*acx));
ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); ret = wlcore_cmd_send_failsafe(wl, CMD_CONFIGURE, acx, len, 0,
valid_rets);
if (ret < 0) { if (ret < 0) {
wl1271_warning("CONFIGURE command NOK"); wl1271_warning("CONFIGURE command NOK");
return ret; return ret;
} }
return ret;
}
/*
* wrapper for wlcore_cmd_configure that accepts only success status.
* return 0 on success
*/
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
{
int ret = wlcore_cmd_configure_failsafe(wl, id, buf, len, 0);
if (ret < 0)
return ret;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(wl1271_cmd_configure); EXPORT_SYMBOL_GPL(wl1271_cmd_configure);
......
...@@ -31,6 +31,8 @@ struct acx_header; ...@@ -31,6 +31,8 @@ struct acx_header;
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); size_t res_len);
int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len, unsigned long valid_rets);
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
u8 *role_id); u8 *role_id);
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
...@@ -45,6 +47,8 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); ...@@ -45,6 +47,8 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_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 wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,
size_t len, unsigned long valid_rets);
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, u16 auto_ps_timeout); u8 ps_mode, u16 auto_ps_timeout);
...@@ -234,7 +238,8 @@ enum { ...@@ -234,7 +238,8 @@ enum {
CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
CMD_STATUS_TEMPLATE_OOM = 23, CMD_STATUS_TEMPLATE_OOM = 23,
CMD_STATUS_NO_RX_BA_SESSION = 24, CMD_STATUS_NO_RX_BA_SESSION = 24,
MAX_COMMAND_STATUS = 0xff
MAX_COMMAND_STATUS
}; };
#define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_HEADER_LEN 4
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册