Commit a572ac1a authored by Luciano Coelho's avatar Luciano Coelho

Merge branch 'wl12xx-next' into for-linville

parents 6bcfe67f 680c6055
This diff is collapsed.
...@@ -32,25 +32,21 @@ enum { ...@@ -32,25 +32,21 @@ enum {
/* numbers of bits the length field takes (add 1 for the actual number) */ /* numbers of bits the length field takes (add 1 for the actual number) */
#define WL18XX_HOST_IF_LEN_SIZE_FIELD 15 #define WL18XX_HOST_IF_LEN_SIZE_FIELD 15
#define WL18XX_ACX_EVENTS_VECTOR_PG1 (WL1271_ACX_INTR_WATCHDOG | \ #define WL18XX_ACX_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \
WL1271_ACX_INTR_INIT_COMPLETE | \ WL1271_ACX_INTR_INIT_COMPLETE | \
WL1271_ACX_INTR_EVENT_A | \ WL1271_ACX_INTR_EVENT_A | \
WL1271_ACX_INTR_EVENT_B | \ WL1271_ACX_INTR_EVENT_B | \
WL1271_ACX_INTR_CMD_COMPLETE | \ WL1271_ACX_INTR_CMD_COMPLETE | \
WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA) WL1271_ACX_INTR_DATA | \
WL1271_ACX_SW_INTR_WATCHDOG)
#define WL18XX_ACX_EVENTS_VECTOR_PG2 (WL18XX_ACX_EVENTS_VECTOR_PG1 | \
WL1271_ACX_SW_INTR_WATCHDOG) #define WL18XX_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
WL1271_ACX_INTR_EVENT_A | \
#define WL18XX_INTR_MASK_PG1 (WL1271_ACX_INTR_WATCHDOG | \ WL1271_ACX_INTR_EVENT_B | \
WL1271_ACX_INTR_EVENT_A | \ WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_EVENT_B | \ WL1271_ACX_INTR_DATA | \
WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_SW_INTR_WATCHDOG)
WL1271_ACX_INTR_DATA)
#define WL18XX_INTR_MASK_PG2 (WL18XX_INTR_MASK_PG1 | \
WL1271_ACX_SW_INTR_WATCHDOG)
struct wl18xx_acx_host_config_bitmap { struct wl18xx_acx_host_config_bitmap {
struct acx_header header; struct acx_header header;
......
...@@ -24,37 +24,52 @@ ...@@ -24,37 +24,52 @@
#include "io.h" #include "io.h"
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) int wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{ {
u32 tmp; u32 tmp;
int ret;
if (WARN_ON(addr % 2)) if (WARN_ON(addr % 2))
return; return -EINVAL;
if ((addr % 4) == 0) { if ((addr % 4) == 0) {
tmp = wl1271_read32(wl, addr); ret = wlcore_read32(wl, addr, &tmp);
if (ret < 0)
goto out;
tmp = (tmp & 0xffff0000) | val; tmp = (tmp & 0xffff0000) | val;
wl1271_write32(wl, addr, tmp); ret = wlcore_write32(wl, addr, tmp);
} else { } else {
tmp = wl1271_read32(wl, addr - 2); ret = wlcore_read32(wl, addr - 2, &tmp);
if (ret < 0)
goto out;
tmp = (tmp & 0xffff) | (val << 16); tmp = (tmp & 0xffff) | (val << 16);
wl1271_write32(wl, addr - 2, tmp); ret = wlcore_write32(wl, addr - 2, tmp);
} }
out:
return ret;
} }
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr) int wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out)
{ {
u32 val; u32 val;
int ret;
if (WARN_ON(addr % 2)) if (WARN_ON(addr % 2))
return 0; return -EINVAL;
if ((addr % 4) == 0) { if ((addr % 4) == 0) {
/* address is 4-bytes aligned */ /* address is 4-bytes aligned */
val = wl1271_read32(wl, addr); ret = wlcore_read32(wl, addr, &val);
return val & 0xffff; if (ret >= 0 && out)
*out = val & 0xffff;
} else { } else {
val = wl1271_read32(wl, addr - 2); ret = wlcore_read32(wl, addr - 2, &val);
return (val & 0xffff0000) >> 16; if (ret >= 0 && out)
*out = (val & 0xffff0000) >> 16;
} }
return ret;
} }
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#ifndef __WL18XX_IO_H__ #ifndef __WL18XX_IO_H__
#define __WL18XX_IO_H__ #define __WL18XX_IO_H__
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val); int __must_check wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val);
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr); int __must_check wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out);
#endif /* __WL18XX_IO_H__ */ #endif /* __WL18XX_IO_H__ */
This diff is collapsed.
...@@ -33,16 +33,22 @@ ...@@ -33,16 +33,22 @@
#include "rx.h" #include "rx.h"
#include "hw_ops.h" #include "hw_ops.h"
static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) static int wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
{ {
u32 cpu_ctrl; u32 cpu_ctrl;
int ret;
/* 10.5.0 run the firmware (I) */ /* 10.5.0 run the firmware (I) */
cpu_ctrl = wlcore_read_reg(wl, REG_ECPU_CONTROL); ret = wlcore_read_reg(wl, REG_ECPU_CONTROL, &cpu_ctrl);
if (ret < 0)
goto out;
/* 10.5.1 run the firmware (II) */ /* 10.5.1 run the firmware (II) */
cpu_ctrl |= flag; cpu_ctrl |= flag;
wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl); ret = wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
out:
return ret;
} }
static int wlcore_boot_parse_fw_ver(struct wl1271 *wl, static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
...@@ -87,7 +93,9 @@ static int wlcore_boot_static_data(struct wl1271 *wl) ...@@ -87,7 +93,9 @@ static int wlcore_boot_static_data(struct wl1271 *wl)
goto out; goto out;
} }
wl1271_read(wl, wl->cmd_box_addr, static_data, len, false); 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); ret = wlcore_boot_parse_fw_ver(wl, static_data);
if (ret < 0) if (ret < 0)
...@@ -109,6 +117,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -109,6 +117,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
struct wlcore_partition_set partition; struct wlcore_partition_set partition;
int addr, chunk_num, partition_limit; int addr, chunk_num, partition_limit;
u8 *p, *chunk; u8 *p, *chunk;
int ret;
/* whal_FwCtrl_LoadFwImageSm() */ /* whal_FwCtrl_LoadFwImageSm() */
...@@ -130,7 +139,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -130,7 +139,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition)); memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
partition.mem.start = dest; partition.mem.start = dest;
wlcore_set_partition(wl, &partition); ret = wlcore_set_partition(wl, &partition);
if (ret < 0)
return ret;
/* 10.1 set partition limit and chunk num */ /* 10.1 set partition limit and chunk num */
chunk_num = 0; chunk_num = 0;
...@@ -144,7 +155,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -144,7 +155,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
partition_limit = chunk_num * CHUNK_SIZE + partition_limit = chunk_num * CHUNK_SIZE +
wl->ptable[PART_DOWN].mem.size; wl->ptable[PART_DOWN].mem.size;
partition.mem.start = addr; partition.mem.start = addr;
wlcore_set_partition(wl, &partition); ret = wlcore_set_partition(wl, &partition);
if (ret < 0)
return ret;
} }
/* 10.3 upload the chunk */ /* 10.3 upload the chunk */
...@@ -153,7 +166,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -153,7 +166,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, CHUNK_SIZE); memcpy(chunk, p, CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr); p, addr);
wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); ret = wlcore_write(wl, addr, chunk, CHUNK_SIZE, false);
if (ret < 0)
goto out;
chunk_num++; chunk_num++;
} }
...@@ -164,10 +179,11 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -164,10 +179,11 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, fw_data_len % CHUNK_SIZE); memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr); fw_data_len % CHUNK_SIZE, p, addr);
wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); ret = wlcore_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
out:
kfree(chunk); kfree(chunk);
return 0; return ret;
} }
int wlcore_boot_upload_firmware(struct wl1271 *wl) int wlcore_boot_upload_firmware(struct wl1271 *wl)
...@@ -210,6 +226,7 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) ...@@ -210,6 +226,7 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
int i; int i;
u32 dest_addr, val; u32 dest_addr, val;
u8 *nvs_ptr, *nvs_aligned; u8 *nvs_ptr, *nvs_aligned;
int ret;
if (wl->nvs == NULL) { if (wl->nvs == NULL) {
wl1271_error("NVS file is needed during boot"); wl1271_error("NVS file is needed during boot");
...@@ -307,7 +324,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) ...@@ -307,7 +324,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, wl1271_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x", "nvs burst write 0x%x: 0x%x",
dest_addr, val); dest_addr, val);
wl1271_write32(wl, dest_addr, val); ret = wlcore_write32(wl, dest_addr, val);
if (ret < 0)
return ret;
nvs_ptr += 4; nvs_ptr += 4;
dest_addr += 4; dest_addr += 4;
...@@ -333,7 +352,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) ...@@ -333,7 +352,9 @@ int wlcore_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 */
wlcore_set_partition(wl, &wl->ptable[PART_WORK]); ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
if (ret < 0)
return ret;
/* 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);
...@@ -341,11 +362,11 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) ...@@ -341,11 +362,11 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
return -ENOMEM; return -ENOMEM;
/* And finally we upload the NVS tables */ /* And finally we upload the NVS tables */
wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, ret = wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, nvs_aligned, nvs_len,
nvs_aligned, nvs_len, false); false);
kfree(nvs_aligned); kfree(nvs_aligned);
return 0; return ret;
out_badnvs: out_badnvs:
wl1271_error("nvs data is malformed"); wl1271_error("nvs data is malformed");
...@@ -359,11 +380,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) ...@@ -359,11 +380,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
u32 chip_id, intr; u32 chip_id, intr;
/* Make sure we have the boot partition */ /* Make sure we have the boot partition */
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
return ret;
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); ret = wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
if (ret < 0)
return ret;
chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B); ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &chip_id);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
...@@ -376,7 +403,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) ...@@ -376,7 +403,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
loop = 0; loop = 0;
while (loop++ < INIT_LOOP) { while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY); udelay(INIT_LOOP_DELAY);
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
return ret;
if (intr == 0xffffffff) { if (intr == 0xffffffff) {
wl1271_error("error reading hardware complete " wl1271_error("error reading hardware complete "
...@@ -385,8 +414,10 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) ...@@ -385,8 +414,10 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
} }
/* check that ACX_INTR_INIT_COMPLETE is enabled */ /* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
wlcore_write_reg(wl, REG_INTERRUPT_ACK, ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE); WL1271_ACX_INTR_INIT_COMPLETE);
if (ret < 0)
return ret;
break; break;
} }
} }
...@@ -398,12 +429,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) ...@@ -398,12 +429,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
} }
/* get hardware config command mail box */ /* get hardware config command mail box */
wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR); ret = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR, &wl->cmd_box_addr);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr); wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr);
/* get hardware config event mail box */ /* get hardware config event mail box */
wl->mbox_ptr[0] = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR); ret = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR, &wl->mbox_ptr[0]);
if (ret < 0)
return ret;
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
...@@ -445,9 +481,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) ...@@ -445,9 +481,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
} }
/* set the working partition to its "running" mode offset */ /* set the working partition to its "running" mode offset */
wlcore_set_partition(wl, &wl->ptable[PART_WORK]); ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
/* firmware startup completed */ /* firmware startup completed */
return 0; return ret;
} }
EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware); EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);
...@@ -65,17 +65,24 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -65,17 +65,24 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
WARN_ON(len % 4 != 0); WARN_ON(len % 4 != 0);
WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags));
wl1271_write(wl, wl->cmd_box_addr, buf, len, false); 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 * TODO: we just need this because one bit is in a different
* place. Is there any better way? * place. Is there any better way?
*/ */
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)
goto fail;
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
goto fail;
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");
...@@ -89,13 +96,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -89,13 +96,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
else else
msleep(1); msleep(1);
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
goto fail;
} }
/* read back the status code of the command */ /* read back the status code of the command */
if (res_len == 0) if (res_len == 0)
res_len = sizeof(struct wl1271_cmd_header); res_len = sizeof(struct wl1271_cmd_header);
wl1271_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)
goto fail;
status = le16_to_cpu(cmd->status); status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) { if (status != CMD_STATUS_SUCCESS) {
...@@ -104,11 +116,14 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -104,11 +116,14 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
goto fail; goto fail;
} }
wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
if (ret < 0)
goto fail;
return 0; return 0;
fail: fail:
WARN_ON(1);
wl12xx_queue_recovery_work(wl); wl12xx_queue_recovery_work(wl);
return ret; return ret;
} }
...@@ -117,35 +132,45 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -117,35 +132,45 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
* 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)
*/ */
static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
u32 mask, bool *timeout)
{ {
u32 *events_vector; u32 *events_vector;
u32 event; u32 event;
unsigned long timeout; unsigned long timeout_time;
int ret = 0; int ret = 0;
*timeout = false;
events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA); events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
if (!events_vector) if (!events_vector)
return -ENOMEM; return -ENOMEM;
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
do { do {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout_time)) {
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
(int)mask); (int)mask);
ret = -ETIMEDOUT; *timeout = true;
goto out; goto out;
} }
msleep(1); msleep(1);
/* read from both event fields */ /* read from both event fields */
wl1271_read(wl, wl->mbox_ptr[0], events_vector, ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector,
sizeof(*events_vector), false); sizeof(*events_vector), false);
if (ret < 0)
goto out;
event = *events_vector & mask; event = *events_vector & mask;
wl1271_read(wl, wl->mbox_ptr[1], events_vector,
sizeof(*events_vector), false); ret = wlcore_read(wl, wl->mbox_ptr[1], events_vector,
sizeof(*events_vector), false);
if (ret < 0)
goto out;
event |= *events_vector & mask; event |= *events_vector & mask;
} while (!event); } while (!event);
...@@ -157,9 +182,10 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) ...@@ -157,9 +182,10 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
{ {
int ret; int ret;
bool timeout = false;
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
if (ret != 0) { if (ret != 0 || timeout) {
wl12xx_queue_recovery_work(wl); wl12xx_queue_recovery_work(wl);
return ret; return ret;
} }
...@@ -1412,6 +1438,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) ...@@ -1412,6 +1438,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
{ {
struct wl12xx_cmd_remove_peer *cmd; struct wl12xx_cmd_remove_peer *cmd;
int ret; int ret;
bool timeout = false;
wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
...@@ -1432,12 +1459,16 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) ...@@ -1432,12 +1459,16 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
goto out_free; goto out_free;
} }
ret = wl1271_cmd_wait_for_event_or_timeout(wl,
PEER_REMOVE_COMPLETE_EVENT_ID,
&timeout);
/* /*
* We are ok with a timeout here. The event is sometimes not sent * We are ok with a timeout here. The event is sometimes not sent
* due to a firmware bug. * due to a firmware bug. In case of another error (like SDIO timeout)
* queue a recovery.
*/ */
wl1271_cmd_wait_for_event_or_timeout(wl, if (ret)
PEER_REMOVE_COMPLETE_EVENT_ID); wl12xx_queue_recovery_work(wl);
out_free: out_free:
kfree(cmd); kfree(cmd);
...@@ -1754,7 +1785,9 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -1754,7 +1785,9 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
return -EINVAL; return -EINVAL;
/* flush all pending packets */ /* flush all pending packets */
wl1271_tx_work_locked(wl); ret = wlcore_tx_work_locked(wl);
if (ret < 0)
goto out;
if (test_bit(wlvif->dev_role_id, wl->roc_map)) { if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
ret = wl12xx_croc(wl, wlvif->dev_role_id); ret = wl12xx_croc(wl, wlvif->dev_role_id);
......
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
/* ms */ /* ms */
#define WL1271_DEBUGFS_STATS_LIFETIME 1000 #define WL1271_DEBUGFS_STATS_LIFETIME 1000
#define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE))
/* debugfs macros idea from mac80211 */ /* debugfs macros idea from mac80211 */
int wl1271_format_buffer(char __user *userbuf, size_t count, int wl1271_format_buffer(char __user *userbuf, size_t count,
loff_t *ppos, char *fmt, ...) loff_t *ppos, char *fmt, ...)
...@@ -1025,6 +1027,195 @@ static const struct file_operations sleep_auth_ops = { ...@@ -1025,6 +1027,195 @@ static const struct file_operations sleep_auth_ops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t dev_mem_read(struct file *file,
char __user *user_buf, size_t count,
loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
struct wlcore_partition_set part, old_part;
size_t bytes = count;
int ret;
char *buf;
/* only requests of dword-aligned size and offset are supported */
if (bytes % 4)
return -EINVAL;
if (*ppos % 4)
return -EINVAL;
/* function should return in reasonable time */
bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
if (bytes == 0)
return -EINVAL;
memset(&part, 0, sizeof(part));
part.mem.start = file->f_pos;
part.mem.size = bytes;
buf = kmalloc(bytes, GFP_KERNEL);
if (!buf)
return -ENOMEM;
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
ret = -EFAULT;
goto skip_read;
}
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto skip_read;
/* store current partition and switch partition */
memcpy(&old_part, &wl->curr_part, sizeof(old_part));
ret = wlcore_set_partition(wl, &part);
if (ret < 0)
goto part_err;
ret = wlcore_raw_read(wl, 0, buf, bytes, false);
if (ret < 0)
goto read_err;
read_err:
/* recover partition */
ret = wlcore_set_partition(wl, &old_part);
if (ret < 0)
goto part_err;
part_err:
wl1271_ps_elp_sleep(wl);
skip_read:
mutex_unlock(&wl->mutex);
if (ret == 0) {
ret = copy_to_user(user_buf, buf, bytes);
if (ret < bytes) {
bytes -= ret;
*ppos += bytes;
ret = 0;
} else {
ret = -EFAULT;
}
}
kfree(buf);
return ((ret == 0) ? bytes : ret);
}
static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
struct wlcore_partition_set part, old_part;
size_t bytes = count;
int ret;
char *buf;
/* only requests of dword-aligned size and offset are supported */
if (bytes % 4)
return -EINVAL;
if (*ppos % 4)
return -EINVAL;
/* function should return in reasonable time */
bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
if (bytes == 0)
return -EINVAL;
memset(&part, 0, sizeof(part));
part.mem.start = file->f_pos;
part.mem.size = bytes;
buf = kmalloc(bytes, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = copy_from_user(buf, user_buf, bytes);
if (ret) {
ret = -EFAULT;
goto err_out;
}
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
ret = -EFAULT;
goto skip_write;
}
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto skip_write;
/* store current partition and switch partition */
memcpy(&old_part, &wl->curr_part, sizeof(old_part));
ret = wlcore_set_partition(wl, &part);
if (ret < 0)
goto part_err;
ret = wlcore_raw_write(wl, 0, buf, bytes, false);
if (ret < 0)
goto write_err;
write_err:
/* recover partition */
ret = wlcore_set_partition(wl, &old_part);
if (ret < 0)
goto part_err;
part_err:
wl1271_ps_elp_sleep(wl);
skip_write:
mutex_unlock(&wl->mutex);
if (ret == 0)
*ppos += bytes;
err_out:
kfree(buf);
return ((ret == 0) ? bytes : ret);
}
static loff_t dev_mem_seek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
/* only requests of dword-aligned size and offset are supported */
if (offset % 4)
return -EINVAL;
switch (orig) {
case SEEK_SET:
file->f_pos = offset;
ret = file->f_pos;
break;
case SEEK_CUR:
file->f_pos += offset;
ret = file->f_pos;
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct file_operations dev_mem_ops = {
.open = simple_open,
.read = dev_mem_read,
.write = dev_mem_write,
.llseek = dev_mem_seek,
};
static int wl1271_debugfs_add_files(struct wl1271 *wl, static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir) struct dentry *rootdir)
{ {
...@@ -1059,6 +1250,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, ...@@ -1059,6 +1250,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming); DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming);
DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming); DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming);
DEBUGFS_ADD_PREFIX(dev, mem, rootdir);
return 0; return 0;
......
...@@ -105,6 +105,7 @@ static int wl1271_event_process(struct wl1271 *wl) ...@@ -105,6 +105,7 @@ static int wl1271_event_process(struct wl1271 *wl)
u32 vector; u32 vector;
bool disconnect_sta = false; bool disconnect_sta = false;
unsigned long sta_bitmap = 0; unsigned long sta_bitmap = 0;
int ret;
wl1271_event_mbox_dump(mbox); wl1271_event_mbox_dump(mbox);
...@@ -228,7 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl) ...@@ -228,7 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl)
if ((vector & DUMMY_PACKET_EVENT_ID)) { if ((vector & DUMMY_PACKET_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
wl1271_tx_dummy_packet(wl); ret = wl1271_tx_dummy_packet(wl);
if (ret < 0)
return ret;
} }
/* /*
...@@ -301,8 +304,10 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) ...@@ -301,8 +304,10 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return -EINVAL; return -EINVAL;
/* first we read the mbox descriptor */ /* first we read the mbox descriptor */
wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
sizeof(*wl->mbox), false); sizeof(*wl->mbox), false);
if (ret < 0)
return ret;
/* process the descriptor */ /* process the descriptor */
ret = wl1271_event_process(wl); ret = wl1271_event_process(wl);
...@@ -313,7 +318,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) ...@@ -313,7 +318,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
* TODO: we just need this because one bit is in a different * TODO: we just need this because one bit is in a different
* place. Is there any better way? * place. Is there any better way?
*/ */
wl->ops->ack_event(wl); ret = wl->ops->ack_event(wl);
return 0; return ret;
} }
...@@ -65,11 +65,13 @@ wlcore_hw_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) ...@@ -65,11 +65,13 @@ wlcore_hw_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
return wl->ops->get_rx_buf_align(wl, rx_desc); return wl->ops->get_rx_buf_align(wl, rx_desc);
} }
static inline void static inline int
wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{ {
if (wl->ops->prepare_read) if (wl->ops->prepare_read)
wl->ops->prepare_read(wl, rx_desc, len); return wl->ops->prepare_read(wl, rx_desc, len);
return 0;
} }
static inline u32 static inline u32
...@@ -81,10 +83,12 @@ wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len) ...@@ -81,10 +83,12 @@ wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len)
return wl->ops->get_rx_packet_len(wl, rx_data, data_len); return wl->ops->get_rx_packet_len(wl, rx_data, data_len);
} }
static inline void wlcore_hw_tx_delayed_compl(struct wl1271 *wl) static inline int wlcore_hw_tx_delayed_compl(struct wl1271 *wl)
{ {
if (wl->ops->tx_delayed_compl) if (wl->ops->tx_delayed_compl)
wl->ops->tx_delayed_compl(wl); return wl->ops->tx_delayed_compl(wl);
return 0;
} }
static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl) static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl)
......
...@@ -48,6 +48,12 @@ void wlcore_disable_interrupts(struct wl1271 *wl) ...@@ -48,6 +48,12 @@ void wlcore_disable_interrupts(struct wl1271 *wl)
} }
EXPORT_SYMBOL_GPL(wlcore_disable_interrupts); EXPORT_SYMBOL_GPL(wlcore_disable_interrupts);
void wlcore_disable_interrupts_nosync(struct wl1271 *wl)
{
disable_irq_nosync(wl->irq);
}
EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync);
void wlcore_enable_interrupts(struct wl1271 *wl) void wlcore_enable_interrupts(struct wl1271 *wl)
{ {
enable_irq(wl->irq); enable_irq(wl->irq);
...@@ -122,9 +128,11 @@ EXPORT_SYMBOL_GPL(wlcore_translate_addr); ...@@ -122,9 +128,11 @@ EXPORT_SYMBOL_GPL(wlcore_translate_addr);
* | | * | |
* *
*/ */
void wlcore_set_partition(struct wl1271 *wl, int wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p) const struct wlcore_partition_set *p)
{ {
int ret;
/* copy partition info */ /* copy partition info */
memcpy(&wl->curr_part, p, sizeof(*p)); memcpy(&wl->curr_part, p, sizeof(*p));
...@@ -137,28 +145,41 @@ void wlcore_set_partition(struct wl1271 *wl, ...@@ -137,28 +145,41 @@ void wlcore_set_partition(struct wl1271 *wl,
wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X", wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X",
p->mem3.start, p->mem3.size); p->mem3.start, p->mem3.size);
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); ret = wlcore_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); if (ret < 0)
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); goto out;
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); ret = wlcore_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
if (ret < 0)
goto out;
/* /*
* We don't need the size of the last partition, as it is * We don't need the size of the last partition, as it is
* automatically calculated based on the total memory size and * automatically calculated based on the total memory size and
* the sizes of the previous partitions. * the sizes of the previous partitions.
*/ */
wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
}
EXPORT_SYMBOL_GPL(wlcore_set_partition);
void wlcore_select_partition(struct wl1271 *wl, u8 part) out:
{ return ret;
wl1271_debug(DEBUG_IO, "setting partition %d", part);
wlcore_set_partition(wl, &wl->ptable[part]);
} }
EXPORT_SYMBOL_GPL(wlcore_select_partition); EXPORT_SYMBOL_GPL(wlcore_set_partition);
void wl1271_io_reset(struct wl1271 *wl) void wl1271_io_reset(struct wl1271 *wl)
{ {
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
struct wl1271; struct wl1271;
void wlcore_disable_interrupts(struct wl1271 *wl); void wlcore_disable_interrupts(struct wl1271 *wl);
void wlcore_disable_interrupts_nosync(struct wl1271 *wl);
void wlcore_enable_interrupts(struct wl1271 *wl); void wlcore_enable_interrupts(struct wl1271 *wl);
void wl1271_io_reset(struct wl1271 *wl); void wl1271_io_reset(struct wl1271 *wl);
...@@ -52,79 +53,113 @@ void wl1271_io_init(struct wl1271 *wl); ...@@ -52,79 +53,113 @@ void wl1271_io_init(struct wl1271 *wl);
int wlcore_translate_addr(struct wl1271 *wl, int addr); int wlcore_translate_addr(struct wl1271 *wl, int addr);
/* Raw target IO, address is not translated */ /* Raw target IO, address is not translated */
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl->if_ops->write(wl->dev, addr, buf, len, fixed); int ret;
if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags))
return -EIO;
ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed);
if (ret)
set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags);
return ret;
} }
static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl->if_ops->read(wl->dev, addr, buf, len, fixed); int ret;
if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags))
return -EIO;
ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed);
if (ret)
set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags);
return ret;
} }
static inline void wlcore_raw_read_data(struct wl1271 *wl, int reg, void *buf, static inline int __must_check wlcore_raw_read_data(struct wl1271 *wl, int reg,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl1271_raw_read(wl, wl->rtable[reg], buf, len, fixed); return wlcore_raw_read(wl, wl->rtable[reg], buf, len, fixed);
} }
static inline void wlcore_raw_write_data(struct wl1271 *wl, int reg, void *buf, static inline int __must_check wlcore_raw_write_data(struct wl1271 *wl, int reg,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl1271_raw_write(wl, wl->rtable[reg], buf, len, fixed); return wlcore_raw_write(wl, wl->rtable[reg], buf, len, fixed);
} }
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
u32 *val)
{ {
wl1271_raw_read(wl, addr, &wl->buffer_32, int ret;
sizeof(wl->buffer_32), false);
ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
if (ret < 0)
return ret;
if (val)
*val = le32_to_cpu(wl->buffer_32);
return le32_to_cpu(wl->buffer_32); return 0;
} }
static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
u32 val)
{ {
wl->buffer_32 = cpu_to_le32(val); wl->buffer_32 = cpu_to_le32(val);
wl1271_raw_write(wl, addr, &wl->buffer_32, return wlcore_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false); sizeof(wl->buffer_32), false);
} }
static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
int physical; int physical;
physical = wlcore_translate_addr(wl, addr); physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed); return wlcore_raw_read(wl, physical, buf, len, fixed);
} }
static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, static inline int __must_check wlcore_write(struct wl1271 *wl, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
int physical; int physical;
physical = wlcore_translate_addr(wl, addr); physical = wlcore_translate_addr(wl, addr);
wl1271_raw_write(wl, physical, buf, len, fixed); return wlcore_raw_write(wl, physical, buf, len, fixed);
} }
static inline void wlcore_write_data(struct wl1271 *wl, int reg, void *buf, static inline int __must_check wlcore_write_data(struct wl1271 *wl, int reg,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl1271_write(wl, wl->rtable[reg], buf, len, fixed); return wlcore_write(wl, wl->rtable[reg], buf, len, fixed);
} }
static inline void wlcore_read_data(struct wl1271 *wl, int reg, void *buf, static inline int __must_check wlcore_read_data(struct wl1271 *wl, int reg,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl1271_read(wl, wl->rtable[reg], buf, len, fixed); return wlcore_read(wl, wl->rtable[reg], buf, len, fixed);
} }
static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
void *buf, size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
int physical; int physical;
int addr; int addr;
...@@ -134,34 +169,47 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, ...@@ -134,34 +169,47 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
physical = wlcore_translate_addr(wl, addr); physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed); return wlcore_raw_read(wl, physical, buf, len, fixed);
} }
static inline u32 wl1271_read32(struct wl1271 *wl, int addr) static inline int __must_check wlcore_read32(struct wl1271 *wl, int addr,
u32 *val)
{ {
return wl1271_raw_read32(wl, wlcore_translate_addr(wl, addr)); return wlcore_raw_read32(wl, wlcore_translate_addr(wl, addr), val);
} }
static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) static inline int __must_check wlcore_write32(struct wl1271 *wl, int addr,
u32 val)
{ {
wl1271_raw_write32(wl, wlcore_translate_addr(wl, addr), val); return wlcore_raw_write32(wl, wlcore_translate_addr(wl, addr), val);
} }
static inline u32 wlcore_read_reg(struct wl1271 *wl, int reg) static inline int __must_check wlcore_read_reg(struct wl1271 *wl, int reg,
u32 *val)
{ {
return wl1271_raw_read32(wl, return wlcore_raw_read32(wl,
wlcore_translate_addr(wl, wl->rtable[reg])); wlcore_translate_addr(wl, wl->rtable[reg]),
val);
} }
static inline void wlcore_write_reg(struct wl1271 *wl, int reg, u32 val) static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg,
u32 val)
{ {
wl1271_raw_write32(wl, wlcore_translate_addr(wl, wl->rtable[reg]), val); return wlcore_raw_write32(wl,
wlcore_translate_addr(wl, wl->rtable[reg]),
val);
} }
static inline void wl1271_power_off(struct wl1271 *wl) static inline void wl1271_power_off(struct wl1271 *wl)
{ {
wl->if_ops->power(wl->dev, false); int ret;
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags))
return;
ret = wl->if_ops->power(wl->dev, false);
if (!ret)
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
} }
static inline int wl1271_power_on(struct wl1271 *wl) static inline int wl1271_power_on(struct wl1271 *wl)
...@@ -173,8 +221,8 @@ static inline int wl1271_power_on(struct wl1271 *wl) ...@@ -173,8 +221,8 @@ static inline int wl1271_power_on(struct wl1271 *wl)
return ret; return ret;
} }
void wlcore_set_partition(struct wl1271 *wl, int wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p); const struct wlcore_partition_set *p);
bool wl1271_set_block_size(struct wl1271 *wl); bool wl1271_set_block_size(struct wl1271 *wl);
...@@ -182,6 +230,4 @@ bool wl1271_set_block_size(struct wl1271 *wl); ...@@ -182,6 +230,4 @@ bool wl1271_set_block_size(struct wl1271 *wl);
int wl1271_tx_dummy_packet(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl);
void wlcore_select_partition(struct wl1271 *wl, u8 part);
#endif #endif
This diff is collapsed.
...@@ -35,6 +35,7 @@ void wl1271_elp_work(struct work_struct *work) ...@@ -35,6 +35,7 @@ void wl1271_elp_work(struct work_struct *work)
struct delayed_work *dwork; struct delayed_work *dwork;
struct wl1271 *wl; struct wl1271 *wl;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
int ret;
dwork = container_of(work, struct delayed_work, work); dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, elp_work); wl = container_of(dwork, struct wl1271, elp_work);
...@@ -63,7 +64,12 @@ void wl1271_elp_work(struct work_struct *work) ...@@ -63,7 +64,12 @@ void wl1271_elp_work(struct work_struct *work)
} }
wl1271_debug(DEBUG_PSM, "chip to elp"); wl1271_debug(DEBUG_PSM, "chip to elp");
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
if (ret < 0) {
wl12xx_queue_recovery_work(wl);
goto out;
}
set_bit(WL1271_FLAG_IN_ELP, &wl->flags); set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
out: out:
...@@ -135,7 +141,11 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) ...@@ -135,7 +141,11 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl->elp_compl = &compl; wl->elp_compl = &compl;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
if (ret < 0) {
wl12xx_queue_recovery_work(wl);
goto err;
}
if (!pending) { if (!pending) {
ret = wait_for_completion_timeout( ret = wait_for_completion_timeout(
......
...@@ -200,7 +200,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -200,7 +200,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return is_data; return is_data;
} }
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
{ {
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
u32 buf_size; u32 buf_size;
...@@ -211,6 +211,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) ...@@ -211,6 +211,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
u32 pkt_offset, des; u32 pkt_offset, des;
u8 hlid; u8 hlid;
enum wl_rx_buf_align rx_align; enum wl_rx_buf_align rx_align;
int ret = 0;
while (drv_rx_counter != fw_rx_counter) { while (drv_rx_counter != fw_rx_counter) {
buf_size = 0; buf_size = 0;
...@@ -234,9 +235,14 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) ...@@ -234,9 +235,14 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
/* Read all available packets at once */ /* Read all available packets at once */
des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]); des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
wlcore_hw_prepare_read(wl, des, buf_size); ret = wlcore_hw_prepare_read(wl, des, buf_size);
wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, if (ret < 0)
buf_size, true); goto out;
ret = wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_size, true);
if (ret < 0)
goto out;
/* Split data into separate packets */ /* Split data into separate packets */
pkt_offset = 0; pkt_offset = 0;
...@@ -273,11 +279,17 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) ...@@ -273,11 +279,17 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
* Write the driver's packet counter to the FW. This is only required * Write the driver's packet counter to the FW. This is only required
* for older hardware revisions * for older hardware revisions
*/ */
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER, ret = wlcore_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
wl->rx_counter); wl->rx_counter);
if (ret < 0)
goto out;
}
wl12xx_rearm_rx_streaming(wl, active_hlids); wl12xx_rearm_rx_streaming(wl, active_hlids);
out:
return ret;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -306,14 +318,19 @@ int wl1271_rx_filter_enable(struct wl1271 *wl, ...@@ -306,14 +318,19 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,
return 0; return 0;
} }
void wl1271_rx_filter_clear_all(struct wl1271 *wl) int wl1271_rx_filter_clear_all(struct wl1271 *wl)
{ {
int i; int i, ret = 0;
for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) { for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
if (!wl->rx_filter_enabled[i]) if (!wl->rx_filter_enabled[i])
continue; continue;
wl1271_rx_filter_enable(wl, i, 0, NULL); ret = wl1271_rx_filter_enable(wl, i, 0, NULL);
if (ret)
goto out;
} }
out:
return ret;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
...@@ -143,11 +143,11 @@ struct wl1271_rx_descriptor { ...@@ -143,11 +143,11 @@ struct wl1271_rx_descriptor {
u8 reserved; u8 reserved;
} __packed; } __packed;
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status); int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
int wl1271_rx_filter_enable(struct wl1271 *wl, int wl1271_rx_filter_enable(struct wl1271 *wl,
int index, bool enable, int index, bool enable,
struct wl12xx_rx_filter *filter); struct wl12xx_rx_filter *filter);
void wl1271_rx_filter_clear_all(struct wl1271 *wl); int wl1271_rx_filter_clear_all(struct wl1271 *wl);
#endif #endif
...@@ -71,8 +71,8 @@ static void wl1271_sdio_set_block_size(struct device *child, ...@@ -71,8 +71,8 @@ static void wl1271_sdio_set_block_size(struct device *child,
sdio_release_host(func); sdio_release_host(func);
} }
static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
int ret; int ret;
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
...@@ -103,12 +103,14 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, ...@@ -103,12 +103,14 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
sdio_release_host(func); sdio_release_host(func);
if (ret) if (WARN_ON(ret))
dev_err(child->parent, "sdio read failed (%d)\n", ret); dev_err(child->parent, "sdio read failed (%d)\n", ret);
return ret;
} }
static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, static int __must_check wl12xx_sdio_raw_write(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
int ret; int ret;
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
...@@ -139,25 +141,30 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, ...@@ -139,25 +141,30 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
sdio_release_host(func); sdio_release_host(func);
if (ret) if (WARN_ON(ret))
dev_err(child->parent, "sdio write failed (%d)\n", ret); dev_err(child->parent, "sdio write failed (%d)\n", ret);
return ret;
} }
static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) static int wl12xx_sdio_power_on(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);
struct mmc_card *card = func->card;
/* If enabled, tell runtime PM not to power off the card */ ret = pm_runtime_get_sync(&card->dev);
if (pm_runtime_enabled(&func->dev)) { if (ret) {
ret = pm_runtime_get_sync(&func->dev); /*
if (ret < 0) * Runtime PM might be temporarily disabled, or the device
goto out; * might have a positive reference counter. Make sure it is
} else { * really powered on.
/* Runtime PM is disabled: power up the card manually */ */
ret = mmc_power_restore_host(func->card->host); ret = mmc_power_restore_host(card->host);
if (ret < 0) if (ret < 0) {
pm_runtime_put_sync(&card->dev);
goto out; goto out;
}
} }
sdio_claim_host(func); sdio_claim_host(func);
...@@ -172,20 +179,21 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) ...@@ -172,20 +179,21 @@ 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);
struct mmc_card *card = func->card;
sdio_claim_host(func); sdio_claim_host(func);
sdio_disable_func(func); sdio_disable_func(func);
sdio_release_host(func); sdio_release_host(func);
/* Power off the card manually, even if runtime PM is enabled. */ /* Power off the card manually in case it wasn't powered off above */
ret = mmc_power_save_host(func->card->host); ret = mmc_power_save_host(card->host);
if (ret < 0) if (ret < 0)
return ret; goto out;
/* If enabled, let runtime PM know the card is powered off */ /* Let runtime PM know the card is powered off */
if (pm_runtime_enabled(&func->dev)) pm_runtime_put_sync(&card->dev);
ret = pm_runtime_put_sync(&func->dev);
out:
return ret; return ret;
} }
......
...@@ -193,8 +193,8 @@ static int wl12xx_spi_read_busy(struct device *child) ...@@ -193,8 +193,8 @@ static int wl12xx_spi_read_busy(struct device *child)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
struct wl1271 *wl = dev_get_drvdata(child); struct wl1271 *wl = dev_get_drvdata(child);
...@@ -238,7 +238,7 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, ...@@ -238,7 +238,7 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
wl12xx_spi_read_busy(child)) { wl12xx_spi_read_busy(child)) {
memset(buf, 0, chunk_len); memset(buf, 0, chunk_len);
return; return 0;
} }
spi_message_init(&m); spi_message_init(&m);
...@@ -256,10 +256,12 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, ...@@ -256,10 +256,12 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
buf += chunk_len; buf += chunk_len;
len -= chunk_len; len -= chunk_len;
} }
return 0;
} }
static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
...@@ -304,6 +306,8 @@ static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, ...@@ -304,6 +306,8 @@ static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf,
} }
spi_sync(to_spi_device(glue->dev), &m); spi_sync(to_spi_device(glue->dev), &m);
return 0;
} }
static struct wl1271_if_operations spi_ops = { static struct wl1271_if_operations spi_ops = {
......
...@@ -352,8 +352,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -352,8 +352,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
bool is_dummy; bool is_dummy;
bool is_gem = false; bool is_gem = false;
if (!skb) if (!skb) {
wl1271_error("discarding null skb");
return -EINVAL; return -EINVAL;
}
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
...@@ -662,7 +664,17 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) ...@@ -662,7 +664,17 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
} }
} }
void wl1271_tx_work_locked(struct wl1271 *wl) /*
* Returns failure values only in case of failed bus ops within this function.
* wl1271_prepare_tx_frame retvals won't be returned in order to avoid
* triggering recovery by higher layers when not necessary.
* In case a FW command fails within wl1271_prepare_tx_frame fails a recovery
* will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame
* can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING
* within prepare_tx_frame code but there's nothing we should do about those
* as well.
*/
int wlcore_tx_work_locked(struct wl1271 *wl)
{ {
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -670,10 +682,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -670,10 +682,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
u32 buf_offset = 0, last_len = 0; u32 buf_offset = 0, last_len = 0;
bool sent_packets = false; bool sent_packets = false;
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
int ret; int ret = 0;
int bus_ret = 0;
if (unlikely(wl->state == WL1271_STATE_OFF)) if (unlikely(wl->state == WL1271_STATE_OFF))
return; return 0;
while ((skb = wl1271_skb_dequeue(wl))) { while ((skb = wl1271_skb_dequeue(wl))) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
...@@ -694,8 +707,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -694,8 +707,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
last_len); last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA,
buf_offset, true); wl->aggr_buf, buf_offset, true);
if (bus_ret < 0)
goto out;
sent_packets = true; sent_packets = true;
buf_offset = 0; buf_offset = 0;
continue; continue;
...@@ -731,8 +747,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -731,8 +747,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
out_ack: out_ack:
if (buf_offset) { if (buf_offset) {
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len); buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true); buf_offset, true);
if (bus_ret < 0)
goto out;
sent_packets = true; sent_packets = true;
} }
if (sent_packets) { if (sent_packets) {
...@@ -740,13 +759,19 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -740,13 +759,19 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
* Interrupt the firmware with the new packets. This is only * Interrupt the firmware with the new packets. This is only
* required for older hardware revisions * required for older hardware revisions
*/ */
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
wl1271_write32(wl, WL12XX_HOST_WR_ACCESS, bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS,
wl->tx_packets_count); wl->tx_packets_count);
if (bus_ret < 0)
goto out;
}
wl1271_handle_tx_low_watermark(wl); wl1271_handle_tx_low_watermark(wl);
} }
wl12xx_rearm_rx_streaming(wl, active_hlids); wl12xx_rearm_rx_streaming(wl, active_hlids);
out:
return bus_ret;
} }
void wl1271_tx_work(struct work_struct *work) void wl1271_tx_work(struct work_struct *work)
...@@ -759,7 +784,11 @@ void wl1271_tx_work(struct work_struct *work) ...@@ -759,7 +784,11 @@ void wl1271_tx_work(struct work_struct *work)
if (ret < 0) if (ret < 0)
goto out; goto out;
wl1271_tx_work_locked(wl); ret = wlcore_tx_work_locked(wl);
if (ret < 0) {
wl12xx_queue_recovery_work(wl);
goto out;
}
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out: out:
...@@ -881,22 +910,28 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -881,22 +910,28 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
} }
/* Called upon reception of a TX complete interrupt */ /* Called upon reception of a TX complete interrupt */
void wl1271_tx_complete(struct wl1271 *wl) int wlcore_tx_complete(struct wl1271 *wl)
{ {
struct wl1271_acx_mem_map *memmap = struct wl1271_acx_mem_map *memmap =
(struct wl1271_acx_mem_map *)wl->target_mem_map; (struct wl1271_acx_mem_map *)wl->target_mem_map;
u32 count, fw_counter; u32 count, fw_counter;
u32 i; u32 i;
int ret;
/* read the tx results from the chipset */ /* read the tx results from the chipset */
wl1271_read(wl, le32_to_cpu(memmap->tx_result), ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false); wl->tx_res_if, sizeof(*wl->tx_res_if), false);
if (ret < 0)
goto out;
fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
/* write host counter to chipset (to ack) */ /* write host counter to chipset (to ack) */
wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if, offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter), fw_counter); tx_result_host_counter), fw_counter);
if (ret < 0)
goto out;
count = fw_counter - wl->tx_results_count; count = fw_counter - wl->tx_results_count;
wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
...@@ -916,8 +951,11 @@ void wl1271_tx_complete(struct wl1271 *wl) ...@@ -916,8 +951,11 @@ void wl1271_tx_complete(struct wl1271 *wl)
wl->tx_results_count++; wl->tx_results_count++;
} }
out:
return ret;
} }
EXPORT_SYMBOL(wl1271_tx_complete); EXPORT_SYMBOL(wlcore_tx_complete);
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
{ {
......
...@@ -234,8 +234,8 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl) ...@@ -234,8 +234,8 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
} }
void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl); int wlcore_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl); int wlcore_tx_complete(struct wl1271 *wl);
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl12xx_tx_reset(struct wl1271 *wl); void wl12xx_tx_reset(struct wl1271 *wl);
void wl1271_tx_flush(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl);
......
...@@ -41,9 +41,9 @@ struct wlcore_ops { ...@@ -41,9 +41,9 @@ struct wlcore_ops {
int (*identify_fw)(struct wl1271 *wl); int (*identify_fw)(struct wl1271 *wl);
int (*boot)(struct wl1271 *wl); int (*boot)(struct wl1271 *wl);
int (*plt_init)(struct wl1271 *wl); int (*plt_init)(struct wl1271 *wl);
void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len); void *buf, size_t len);
void (*ack_event)(struct wl1271 *wl); int (*ack_event)(struct wl1271 *wl);
u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks); u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks);
void (*set_tx_desc_blocks)(struct wl1271 *wl, void (*set_tx_desc_blocks)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc, struct wl1271_tx_hw_descr *desc,
...@@ -53,17 +53,17 @@ struct wlcore_ops { ...@@ -53,17 +53,17 @@ struct wlcore_ops {
struct sk_buff *skb); struct sk_buff *skb);
enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl, enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl,
u32 rx_desc); u32 rx_desc);
void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len); int (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len);
u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data, u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data,
u32 data_len); u32 data_len);
void (*tx_delayed_compl)(struct wl1271 *wl); int (*tx_delayed_compl)(struct wl1271 *wl);
void (*tx_immediate_compl)(struct wl1271 *wl); void (*tx_immediate_compl)(struct wl1271 *wl);
int (*hw_init)(struct wl1271 *wl); int (*hw_init)(struct wl1271 *wl);
int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif); int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl, u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,
struct wl12xx_vif *wlvif); struct wl12xx_vif *wlvif);
s8 (*get_pg_ver)(struct wl1271 *wl); int (*get_pg_ver)(struct wl1271 *wl, s8 *ver);
void (*get_mac)(struct wl1271 *wl); int (*get_mac)(struct wl1271 *wl);
void (*set_tx_desc_csum)(struct wl1271 *wl, void (*set_tx_desc_csum)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc, struct wl1271_tx_hw_descr *desc,
struct sk_buff *skb); struct sk_buff *skb);
......
...@@ -209,10 +209,10 @@ struct wl1271_scan { ...@@ -209,10 +209,10 @@ struct wl1271_scan {
}; };
struct wl1271_if_operations { struct wl1271_if_operations {
void (*read)(struct device *child, int addr, void *buf, size_t len, int __must_check (*read)(struct device *child, int addr, void *buf,
bool fixed); size_t len, bool fixed);
void (*write)(struct device *child, int addr, void *buf, size_t len, int __must_check (*write)(struct device *child, int addr, void *buf,
bool fixed); size_t len, bool fixed);
void (*reset)(struct device *child); void (*reset)(struct device *child);
void (*init)(struct device *child); void (*init)(struct device *child);
int (*power)(struct device *child, bool enable); int (*power)(struct device *child, bool enable);
...@@ -247,6 +247,7 @@ enum wl12xx_flags { ...@@ -247,6 +247,7 @@ enum wl12xx_flags {
WL1271_FLAG_RECOVERY_IN_PROGRESS, WL1271_FLAG_RECOVERY_IN_PROGRESS,
WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
WL1271_FLAG_INTENDED_FW_RECOVERY, WL1271_FLAG_INTENDED_FW_RECOVERY,
WL1271_FLAG_SDIO_FAILED,
}; };
enum wl12xx_vif_flags { enum wl12xx_vif_flags {
......
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