diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 149 |
1 files changed, 133 insertions, 16 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 32a205e0b063..3f8e69c29146 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | |||
@@ -22,9 +22,11 @@ | |||
22 | #include <linux/pci_ids.h> | 22 | #include <linux/pci_ids.h> |
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/completion.h> | 24 | #include <linux/completion.h> |
25 | #include <linux/scatterlist.h> | ||
25 | #include <linux/mmc/sdio.h> | 26 | #include <linux/mmc/sdio.h> |
26 | #include <linux/mmc/sdio_func.h> | 27 | #include <linux/mmc/sdio_func.h> |
27 | #include <linux/mmc/card.h> | 28 | #include <linux/mmc/card.h> |
29 | #include <linux/mmc/host.h> | ||
28 | #include <linux/platform_data/brcmfmac-sdio.h> | 30 | #include <linux/platform_data/brcmfmac-sdio.h> |
29 | 31 | ||
30 | #include <defs.h> | 32 | #include <defs.h> |
@@ -316,34 +318,138 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, | |||
316 | * caller has already been padded and aligned. | 318 | * caller has already been padded and aligned. |
317 | */ | 319 | */ |
318 | static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, | 320 | static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, |
319 | bool write, u32 addr, struct sk_buff *pkt) | 321 | bool write, u32 addr, struct sk_buff_head *pktlist) |
320 | { | 322 | { |
321 | uint len; | 323 | unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset; |
324 | unsigned int max_blks, max_req_sz; | ||
325 | unsigned short max_seg_sz, seg_sz; | ||
326 | unsigned char *pkt_data; | ||
327 | struct sk_buff *pkt_next = NULL; | ||
328 | struct mmc_request mmc_req; | ||
329 | struct mmc_command mmc_cmd; | ||
330 | struct mmc_data mmc_dat; | ||
331 | struct sg_table st; | ||
332 | struct scatterlist *sgl; | ||
333 | struct mmc_host *host; | ||
334 | int ret = 0; | ||
335 | |||
336 | if (!pktlist->qlen) | ||
337 | return -EINVAL; | ||
322 | 338 | ||
323 | brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); | 339 | brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); |
324 | if (brcmf_pm_resume_error(sdiodev)) | 340 | if (brcmf_pm_resume_error(sdiodev)) |
325 | return -EIO; | 341 | return -EIO; |
326 | 342 | ||
327 | /* Single skb use the standard mmc interface */ | 343 | /* Single skb use the standard mmc interface */ |
328 | if (!pkt->next) { | 344 | if (pktlist->qlen == 1) { |
329 | len = pkt->len + 3; | 345 | pkt_next = pktlist->next; |
330 | len &= (uint)~3; | 346 | req_sz = pkt_next->len + 3; |
347 | req_sz &= (uint)~3; | ||
331 | 348 | ||
332 | if (write) | 349 | if (write) |
333 | return sdio_memcpy_toio(sdiodev->func[fn], addr, | 350 | return sdio_memcpy_toio(sdiodev->func[fn], addr, |
334 | ((u8 *)(pkt->data)), len); | 351 | ((u8 *)(pkt_next->data)), |
352 | req_sz); | ||
335 | else if (fn == 1) | 353 | else if (fn == 1) |
336 | return sdio_memcpy_fromio(sdiodev->func[fn], | 354 | return sdio_memcpy_fromio(sdiodev->func[fn], |
337 | ((u8 *)(pkt->data)), addr, | 355 | ((u8 *)(pkt_next->data)), |
338 | len); | 356 | addr, req_sz); |
339 | else | 357 | else |
340 | /* function 2 read is FIFO operation */ | 358 | /* function 2 read is FIFO operation */ |
341 | return sdio_readsb(sdiodev->func[fn], | 359 | return sdio_readsb(sdiodev->func[fn], |
342 | ((u8 *)(pkt->data)), addr, len); | 360 | ((u8 *)(pkt_next->data)), addr, |
361 | req_sz); | ||
343 | } | 362 | } |
344 | 363 | ||
345 | brcmf_err("skb chain is not supported yet.\n"); | 364 | host = sdiodev->func[fn]->card->host; |
346 | return -EOPNOTSUPP; | 365 | func_blk_sz = sdiodev->func[fn]->cur_blksize; |
366 | /* Blocks per command is limited by host count, host transfer | ||
367 | * size and the maximum for IO_RW_EXTENDED of 511 blocks. | ||
368 | */ | ||
369 | max_blks = min_t(unsigned int, host->max_blk_count, 511u); | ||
370 | max_req_sz = min_t(unsigned int, host->max_req_size, | ||
371 | max_blks * func_blk_sz); | ||
372 | max_seg_sz = min_t(unsigned short, host->max_segs, SG_MAX_SINGLE_ALLOC); | ||
373 | max_seg_sz = min_t(unsigned short, max_seg_sz, pktlist->qlen); | ||
374 | seg_sz = pktlist->qlen; | ||
375 | pkt_offset = 0; | ||
376 | pkt_next = pktlist->next; | ||
377 | |||
378 | if (sg_alloc_table(&st, max_seg_sz, GFP_KERNEL)) | ||
379 | return -ENOMEM; | ||
380 | |||
381 | while (seg_sz) { | ||
382 | req_sz = 0; | ||
383 | sg_cnt = 0; | ||
384 | memset(&mmc_req, 0, sizeof(struct mmc_request)); | ||
385 | memset(&mmc_cmd, 0, sizeof(struct mmc_command)); | ||
386 | memset(&mmc_dat, 0, sizeof(struct mmc_data)); | ||
387 | sgl = st.sgl; | ||
388 | /* prep sg table */ | ||
389 | while (pkt_next != (struct sk_buff *)pktlist) { | ||
390 | pkt_data = pkt_next->data + pkt_offset; | ||
391 | sg_data_sz = pkt_next->len - pkt_offset; | ||
392 | if (sg_data_sz > host->max_seg_size) | ||
393 | sg_data_sz = host->max_seg_size; | ||
394 | if (sg_data_sz > max_req_sz - req_sz) | ||
395 | sg_data_sz = max_req_sz - req_sz; | ||
396 | |||
397 | sg_set_buf(sgl, pkt_data, sg_data_sz); | ||
398 | |||
399 | sg_cnt++; | ||
400 | sgl = sg_next(sgl); | ||
401 | req_sz += sg_data_sz; | ||
402 | pkt_offset += sg_data_sz; | ||
403 | if (pkt_offset == pkt_next->len) { | ||
404 | pkt_offset = 0; | ||
405 | pkt_next = pkt_next->next; | ||
406 | } | ||
407 | |||
408 | if (req_sz >= max_req_sz || sg_cnt >= max_seg_sz) | ||
409 | break; | ||
410 | } | ||
411 | seg_sz -= sg_cnt; | ||
412 | |||
413 | if (req_sz % func_blk_sz != 0) { | ||
414 | brcmf_err("sg request length %u is not %u aligned\n", | ||
415 | req_sz, func_blk_sz); | ||
416 | sg_free_table(&st); | ||
417 | return -ENOTBLK; | ||
418 | } | ||
419 | mmc_dat.sg = st.sgl; | ||
420 | mmc_dat.sg_len = sg_cnt; | ||
421 | mmc_dat.blksz = func_blk_sz; | ||
422 | mmc_dat.blocks = req_sz / func_blk_sz; | ||
423 | mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; | ||
424 | mmc_cmd.opcode = SD_IO_RW_EXTENDED; | ||
425 | mmc_cmd.arg = write ? 1<<31 : 0; /* write flag */ | ||
426 | mmc_cmd.arg |= (fn & 0x7) << 28; /* SDIO func num */ | ||
427 | mmc_cmd.arg |= 1<<27; /* block mode */ | ||
428 | /* incrementing addr for function 1 */ | ||
429 | mmc_cmd.arg |= (fn == 1) ? 1<<26 : 0; | ||
430 | mmc_cmd.arg |= (addr & 0x1FFFF) << 9; /* address */ | ||
431 | mmc_cmd.arg |= mmc_dat.blocks & 0x1FF; /* block count */ | ||
432 | mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; | ||
433 | mmc_req.cmd = &mmc_cmd; | ||
434 | mmc_req.data = &mmc_dat; | ||
435 | if (fn == 1) | ||
436 | addr += req_sz; | ||
437 | |||
438 | mmc_set_data_timeout(&mmc_dat, sdiodev->func[fn]->card); | ||
439 | mmc_wait_for_req(host, &mmc_req); | ||
440 | |||
441 | ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error; | ||
442 | if (ret != 0) { | ||
443 | brcmf_err("CMD53 sg block %s failed %d\n", | ||
444 | write ? "write" : "read", ret); | ||
445 | ret = -EIO; | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | sg_free_table(&st); | ||
451 | |||
452 | return ret; | ||
347 | } | 453 | } |
348 | 454 | ||
349 | static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn, | 455 | static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn, |
@@ -400,6 +506,7 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
400 | { | 506 | { |
401 | uint width; | 507 | uint width; |
402 | int err = 0; | 508 | int err = 0; |
509 | struct sk_buff_head pkt_list; | ||
403 | 510 | ||
404 | brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", | 511 | brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", |
405 | fn, addr, pkt->len); | 512 | fn, addr, pkt->len); |
@@ -409,7 +516,10 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
409 | if (err) | 516 | if (err) |
410 | goto done; | 517 | goto done; |
411 | 518 | ||
412 | err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pkt); | 519 | skb_queue_head_init(&pkt_list); |
520 | skb_queue_tail(&pkt_list, pkt); | ||
521 | err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, &pkt_list); | ||
522 | skb_dequeue_tail(&pkt_list); | ||
413 | 523 | ||
414 | done: | 524 | done: |
415 | return err; | 525 | return err; |
@@ -431,8 +541,7 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
431 | goto done; | 541 | goto done; |
432 | 542 | ||
433 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; | 543 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; |
434 | err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr, | 544 | err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pktq); |
435 | pktq); | ||
436 | 545 | ||
437 | done: | 546 | done: |
438 | return err; | 547 | return err; |
@@ -467,6 +576,7 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
467 | uint width; | 576 | uint width; |
468 | uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; | 577 | uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; |
469 | int err = 0; | 578 | int err = 0; |
579 | struct sk_buff_head pkt_list; | ||
470 | 580 | ||
471 | brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", | 581 | brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", |
472 | fn, addr, pkt->len); | 582 | fn, addr, pkt->len); |
@@ -489,7 +599,10 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
489 | if (width == 4) | 599 | if (width == 4) |
490 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; | 600 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; |
491 | 601 | ||
492 | err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, pkt); | 602 | skb_queue_head_init(&pkt_list); |
603 | skb_queue_tail(&pkt_list, pkt); | ||
604 | err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, &pkt_list); | ||
605 | skb_dequeue_tail(&pkt_list); | ||
493 | 606 | ||
494 | done: | 607 | done: |
495 | return err; | 608 | return err; |
@@ -503,6 +616,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address, | |||
503 | struct sk_buff *pkt; | 616 | struct sk_buff *pkt; |
504 | u32 sdaddr; | 617 | u32 sdaddr; |
505 | uint dsize; | 618 | uint dsize; |
619 | struct sk_buff_head pkt_list; | ||
506 | 620 | ||
507 | dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size); | 621 | dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size); |
508 | pkt = dev_alloc_skb(dsize); | 622 | pkt = dev_alloc_skb(dsize); |
@@ -511,6 +625,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address, | |||
511 | return -EIO; | 625 | return -EIO; |
512 | } | 626 | } |
513 | pkt->priority = 0; | 627 | pkt->priority = 0; |
628 | skb_queue_head_init(&pkt_list); | ||
514 | 629 | ||
515 | /* Determine initial transfer parameters */ | 630 | /* Determine initial transfer parameters */ |
516 | sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; | 631 | sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; |
@@ -538,8 +653,10 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address, | |||
538 | skb_put(pkt, dsize); | 653 | skb_put(pkt, dsize); |
539 | if (write) | 654 | if (write) |
540 | memcpy(pkt->data, data, dsize); | 655 | memcpy(pkt->data, data, dsize); |
656 | skb_queue_tail(&pkt_list, pkt); | ||
541 | bcmerror = brcmf_sdio_buffrw(sdiodev, SDIO_FUNC_1, write, | 657 | bcmerror = brcmf_sdio_buffrw(sdiodev, SDIO_FUNC_1, write, |
542 | sdaddr, pkt); | 658 | sdaddr, &pkt_list); |
659 | skb_dequeue_tail(&pkt_list); | ||
543 | if (bcmerror) { | 660 | if (bcmerror) { |
544 | brcmf_err("membytes transfer failed\n"); | 661 | brcmf_err("membytes transfer failed\n"); |
545 | break; | 662 | break; |