aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorIdo Yariv <ido@wizery.com>2010-09-30 07:28:26 -0400
committerLuciano Coelho <luciano.coelho@nokia.com>2010-10-05 09:27:24 -0400
commit5c57a901dc96fc81d0041282269b43542f170d2a (patch)
tree7ee87d336cf3b85b6429cba098329ac784e96092 /drivers/net
parent65836112fc24bdf009554481b36b6ba0a690b855 (diff)
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: Ido Yariv <ido@wizery.com> Tested-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c140
1 files changed, 86 insertions, 54 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 75cbf36146e2..ef801680773f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -63,6 +63,11 @@
63 ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) 63 ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
64#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 64#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
65 65
66/* HW limitation: maximum possible chunk size is 4095 bytes */
67#define WSPI_MAX_CHUNK_SIZE 4092
68
69#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
70
66static inline struct spi_device *wl_to_spi(struct wl1271 *wl) 71static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
67{ 72{
68 return wl->if_priv; 73 return wl->if_priv;
@@ -202,90 +207,117 @@ static int wl1271_spi_read_busy(struct wl1271 *wl)
202static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, 207static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
203 size_t len, bool fixed) 208 size_t len, bool fixed)
204{ 209{
205 struct spi_transfer t[3]; 210 struct spi_transfer t[2];
206 struct spi_message m; 211 struct spi_message m;
207 u32 *busy_buf; 212 u32 *busy_buf;
208 u32 *cmd; 213 u32 *cmd;
214 u32 chunk_len;
209 215
210 cmd = &wl->buffer_cmd; 216 while (len > 0) {
211 busy_buf = wl->buffer_busyword; 217 chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
212 218
213 *cmd = 0; 219 cmd = &wl->buffer_cmd;
214 *cmd |= WSPI_CMD_READ; 220 busy_buf = wl->buffer_busyword;
215 *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
216 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
217 221
218 if (fixed) 222 *cmd = 0;
219 *cmd |= WSPI_CMD_FIXED; 223 *cmd |= WSPI_CMD_READ;
224 *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
225 WSPI_CMD_BYTE_LENGTH;
226 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
220 227
221 spi_message_init(&m); 228 if (fixed)
222 memset(t, 0, sizeof(t)); 229 *cmd |= WSPI_CMD_FIXED;
223 230
224 t[0].tx_buf = cmd; 231 spi_message_init(&m);
225 t[0].len = 4; 232 memset(t, 0, sizeof(t));
226 t[0].cs_change = true;
227 spi_message_add_tail(&t[0], &m);
228 233
229 /* Busy and non busy words read */ 234 t[0].tx_buf = cmd;
230 t[1].rx_buf = busy_buf; 235 t[0].len = 4;
231 t[1].len = WL1271_BUSY_WORD_LEN; 236 t[0].cs_change = true;
232 t[1].cs_change = true; 237 spi_message_add_tail(&t[0], &m);
233 spi_message_add_tail(&t[1], &m);
234 238
235 spi_sync(wl_to_spi(wl), &m); 239 /* Busy and non busy words read */
240 t[1].rx_buf = busy_buf;
241 t[1].len = WL1271_BUSY_WORD_LEN;
242 t[1].cs_change = true;
243 spi_message_add_tail(&t[1], &m);
236 244
237 if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && 245 spi_sync(wl_to_spi(wl), &m);
238 wl1271_spi_read_busy(wl)) {
239 memset(buf, 0, len);
240 return;
241 }
242 246
243 spi_message_init(&m); 247 if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
244 memset(t, 0, sizeof(t)); 248 wl1271_spi_read_busy(wl)) {
249 memset(buf, 0, chunk_len);
250 return;
251 }
245 252
246 t[0].rx_buf = buf; 253 spi_message_init(&m);
247 t[0].len = len; 254 memset(t, 0, sizeof(t));
248 t[0].cs_change = true;
249 spi_message_add_tail(&t[0], &m);
250 255
251 spi_sync(wl_to_spi(wl), &m); 256 t[0].rx_buf = buf;
257 t[0].len = chunk_len;
258 t[0].cs_change = true;
259 spi_message_add_tail(&t[0], &m);
260
261 spi_sync(wl_to_spi(wl), &m);
252 262
253 wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); 263 wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
254 wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); 264 wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
265
266 if (!fixed)
267 addr += chunk_len;
268 buf += chunk_len;
269 len -= chunk_len;
270 }
255} 271}
256 272
257static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, 273static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
258 size_t len, bool fixed) 274 size_t len, bool fixed)
259{ 275{
260 struct spi_transfer t[2]; 276 struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
261 struct spi_message m; 277 struct spi_message m;
278 u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
262 u32 *cmd; 279 u32 *cmd;
280 u32 chunk_len;
281 int i;
263 282
264 cmd = &wl->buffer_cmd; 283 WARN_ON(len > WL1271_AGGR_BUFFER_SIZE);
265
266 *cmd = 0;
267 *cmd |= WSPI_CMD_WRITE;
268 *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
269 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
270
271 if (fixed)
272 *cmd |= WSPI_CMD_FIXED;
273 284
274 spi_message_init(&m); 285 spi_message_init(&m);
275 memset(t, 0, sizeof(t)); 286 memset(t, 0, sizeof(t));
276 287
277 t[0].tx_buf = cmd; 288 cmd = &commands[0];
278 t[0].len = sizeof(*cmd); 289 i = 0;
279 spi_message_add_tail(&t[0], &m); 290 while (len > 0) {
291 chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
280 292
281 t[1].tx_buf = buf; 293 *cmd = 0;
282 t[1].len = len; 294 *cmd |= WSPI_CMD_WRITE;
283 spi_message_add_tail(&t[1], &m); 295 *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
296 WSPI_CMD_BYTE_LENGTH;
297 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
284 298
285 spi_sync(wl_to_spi(wl), &m); 299 if (fixed)
300 *cmd |= WSPI_CMD_FIXED;
301
302 t[i].tx_buf = cmd;
303 t[i].len = sizeof(*cmd);
304 spi_message_add_tail(&t[i++], &m);
305
306 t[i].tx_buf = buf;
307 t[i].len = chunk_len;
308 spi_message_add_tail(&t[i++], &m);
286 309
287 wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); 310 wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
288 wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); 311 wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
312
313 if (!fixed)
314 addr += chunk_len;
315 buf += chunk_len;
316 len -= chunk_len;
317 cmd++;
318 }
319
320 spi_sync(wl_to_spi(wl), &m);
289} 321}
290 322
291static irqreturn_t wl1271_irq(int irq, void *cookie) 323static irqreturn_t wl1271_irq(int irq, void *cookie)