Commit 5c57a901 authored by Ido Yariv's avatar Ido Yariv Committed by Luciano Coelho

wl1271: Handle large SPI transfers

The HW supports up to 4095 bytes transfers via SPI. The SPI read & write
operations do not handle larger transfers, causing the HW to stall in such
cases.

Fix this by fragmenting large transfers into smaller chunks, and
transferring each one separately.
Signed-off-by: default avatarIdo Yariv <ido@wizery.com>
Tested-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
parent 65836112
...@@ -63,6 +63,11 @@ ...@@ -63,6 +63,11 @@
((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 #define HW_ACCESS_WSPI_INIT_CMD_MASK 0
/* HW limitation: maximum possible chunk size is 4095 bytes */
#define WSPI_MAX_CHUNK_SIZE 4092
#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
static inline struct spi_device *wl_to_spi(struct wl1271 *wl) static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
{ {
return wl->if_priv; return wl->if_priv;
...@@ -202,17 +207,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl) ...@@ -202,17 +207,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl)
static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed) size_t len, bool fixed)
{ {
struct spi_transfer t[3]; struct spi_transfer t[2];
struct spi_message m; struct spi_message m;
u32 *busy_buf; u32 *busy_buf;
u32 *cmd; u32 *cmd;
u32 chunk_len;
while (len > 0) {
chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
cmd = &wl->buffer_cmd; cmd = &wl->buffer_cmd;
busy_buf = wl->buffer_busyword; busy_buf = wl->buffer_busyword;
*cmd = 0; *cmd = 0;
*cmd |= WSPI_CMD_READ; *cmd |= WSPI_CMD_READ;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR; *cmd |= addr & WSPI_CMD_BYTE_ADDR;
if (fixed) if (fixed)
...@@ -236,7 +246,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, ...@@ -236,7 +246,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
wl1271_spi_read_busy(wl)) { wl1271_spi_read_busy(wl)) {
memset(buf, 0, len); memset(buf, 0, chunk_len);
return; return;
} }
...@@ -244,48 +254,70 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, ...@@ -244,48 +254,70 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
memset(t, 0, sizeof(t)); memset(t, 0, sizeof(t));
t[0].rx_buf = buf; t[0].rx_buf = buf;
t[0].len = len; t[0].len = chunk_len;
t[0].cs_change = true; t[0].cs_change = true;
spi_message_add_tail(&t[0], &m); spi_message_add_tail(&t[0], &m);
spi_sync(wl_to_spi(wl), &m); spi_sync(wl_to_spi(wl), &m);
wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
if (!fixed)
addr += chunk_len;
buf += chunk_len;
len -= chunk_len;
}
} }
static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed) size_t len, bool fixed)
{ {
struct spi_transfer t[2]; struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
struct spi_message m; struct spi_message m;
u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
u32 *cmd; u32 *cmd;
u32 chunk_len;
int i;
cmd = &wl->buffer_cmd; WARN_ON(len > WL1271_AGGR_BUFFER_SIZE);
spi_message_init(&m);
memset(t, 0, sizeof(t));
cmd = &commands[0];
i = 0;
while (len > 0) {
chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
*cmd = 0; *cmd = 0;
*cmd |= WSPI_CMD_WRITE; *cmd |= WSPI_CMD_WRITE;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR; *cmd |= addr & WSPI_CMD_BYTE_ADDR;
if (fixed) if (fixed)
*cmd |= WSPI_CMD_FIXED; *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m); t[i].tx_buf = cmd;
memset(t, 0, sizeof(t)); t[i].len = sizeof(*cmd);
spi_message_add_tail(&t[i++], &m);
t[0].tx_buf = cmd; t[i].tx_buf = buf;
t[0].len = sizeof(*cmd); t[i].len = chunk_len;
spi_message_add_tail(&t[0], &m); spi_message_add_tail(&t[i++], &m);
t[1].tx_buf = buf; wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
t[1].len = len; wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
spi_message_add_tail(&t[1], &m);
spi_sync(wl_to_spi(wl), &m); if (!fixed)
addr += chunk_len;
buf += chunk_len;
len -= chunk_len;
cmd++;
}
wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); spi_sync(wl_to_spi(wl), &m);
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
} }
static irqreturn_t wl1271_irq(int irq, void *cookie) static irqreturn_t wl1271_irq(int irq, void *cookie)
......
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