diff options
author | Russell King - ARM Linux <linux@arm.linux.org.uk> | 2011-01-03 17:43:15 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-01-04 22:16:13 -0500 |
commit | 542361f8e385355c68e263eba49d4306739b9220 (patch) | |
tree | 64d465d026c348f4b5d945cb53aaaf12fb8338a3 /drivers/dma/amba-pl08x.c | |
parent | 5f638b4f313e345bf02700910e581bccf71212f5 (diff) |
ARM: PL08x: don't manipulate txd->srcbus or txd->dstbus during LLI fill
Don't alter any txd->srcbus or txd->dstbus values while building the
LLI list. This allows us to see the original dma_addr_t values passed
in via the prep_memcpy() method.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/amba-pl08x.c')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 159 |
1 files changed, 83 insertions, 76 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index be7fa174d6c0..39970c5038d6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c | |||
@@ -481,38 +481,45 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, | |||
481 | return retbits; | 481 | return retbits; |
482 | } | 482 | } |
483 | 483 | ||
484 | struct pl08x_lli_build_data { | ||
485 | struct pl08x_txd *txd; | ||
486 | struct pl08x_driver_data *pl08x; | ||
487 | struct pl08x_bus_data srcbus; | ||
488 | struct pl08x_bus_data dstbus; | ||
489 | size_t remainder; | ||
490 | }; | ||
491 | |||
484 | /* | 492 | /* |
485 | * Autoselect a master bus to use for the transfer | 493 | * Autoselect a master bus to use for the transfer |
486 | * this prefers the destination bus if both available | 494 | * this prefers the destination bus if both available |
487 | * if fixed address on one bus the other will be chosen | 495 | * if fixed address on one bus the other will be chosen |
488 | */ | 496 | */ |
489 | static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, | 497 | static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, |
490 | struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus, | 498 | struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) |
491 | struct pl08x_bus_data **sbus, u32 cctl) | ||
492 | { | 499 | { |
493 | if (!(cctl & PL080_CONTROL_DST_INCR)) { | 500 | if (!(cctl & PL080_CONTROL_DST_INCR)) { |
494 | *mbus = src_bus; | 501 | *mbus = &bd->srcbus; |
495 | *sbus = dst_bus; | 502 | *sbus = &bd->dstbus; |
496 | } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { | 503 | } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { |
497 | *mbus = dst_bus; | 504 | *mbus = &bd->dstbus; |
498 | *sbus = src_bus; | 505 | *sbus = &bd->srcbus; |
499 | } else { | 506 | } else { |
500 | if (dst_bus->buswidth == 4) { | 507 | if (bd->dstbus.buswidth == 4) { |
501 | *mbus = dst_bus; | 508 | *mbus = &bd->dstbus; |
502 | *sbus = src_bus; | 509 | *sbus = &bd->srcbus; |
503 | } else if (src_bus->buswidth == 4) { | 510 | } else if (bd->srcbus.buswidth == 4) { |
504 | *mbus = src_bus; | 511 | *mbus = &bd->srcbus; |
505 | *sbus = dst_bus; | 512 | *sbus = &bd->dstbus; |
506 | } else if (dst_bus->buswidth == 2) { | 513 | } else if (bd->dstbus.buswidth == 2) { |
507 | *mbus = dst_bus; | 514 | *mbus = &bd->dstbus; |
508 | *sbus = src_bus; | 515 | *sbus = &bd->srcbus; |
509 | } else if (src_bus->buswidth == 2) { | 516 | } else if (bd->srcbus.buswidth == 2) { |
510 | *mbus = src_bus; | 517 | *mbus = &bd->srcbus; |
511 | *sbus = dst_bus; | 518 | *sbus = &bd->dstbus; |
512 | } else { | 519 | } else { |
513 | /* src_bus->buswidth == 1 */ | 520 | /* bd->srcbus.buswidth == 1 */ |
514 | *mbus = dst_bus; | 521 | *mbus = &bd->dstbus; |
515 | *sbus = src_bus; | 522 | *sbus = &bd->srcbus; |
516 | } | 523 | } |
517 | } | 524 | } |
518 | } | 525 | } |
@@ -521,29 +528,29 @@ static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, | |||
521 | * Fills in one LLI for a certain transfer descriptor | 528 | * Fills in one LLI for a certain transfer descriptor |
522 | * and advance the counter | 529 | * and advance the counter |
523 | */ | 530 | */ |
524 | static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, | 531 | static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, |
525 | struct pl08x_txd *txd, int num_llis, int len, u32 cctl, u32 *remainder) | 532 | int num_llis, int len, u32 cctl) |
526 | { | 533 | { |
527 | struct pl08x_lli *llis_va = txd->llis_va; | 534 | struct pl08x_lli *llis_va = bd->txd->llis_va; |
528 | dma_addr_t llis_bus = txd->llis_bus; | 535 | dma_addr_t llis_bus = bd->txd->llis_bus; |
529 | 536 | ||
530 | BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); | 537 | BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); |
531 | 538 | ||
532 | llis_va[num_llis].cctl = cctl; | 539 | llis_va[num_llis].cctl = cctl; |
533 | llis_va[num_llis].src = txd->srcbus.addr; | 540 | llis_va[num_llis].src = bd->srcbus.addr; |
534 | llis_va[num_llis].dst = txd->dstbus.addr; | 541 | llis_va[num_llis].dst = bd->dstbus.addr; |
535 | llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); | 542 | llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); |
536 | if (pl08x->lli_buses & PL08X_AHB2) | 543 | if (bd->pl08x->lli_buses & PL08X_AHB2) |
537 | llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; | 544 | llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; |
538 | 545 | ||
539 | if (cctl & PL080_CONTROL_SRC_INCR) | 546 | if (cctl & PL080_CONTROL_SRC_INCR) |
540 | txd->srcbus.addr += len; | 547 | bd->srcbus.addr += len; |
541 | if (cctl & PL080_CONTROL_DST_INCR) | 548 | if (cctl & PL080_CONTROL_DST_INCR) |
542 | txd->dstbus.addr += len; | 549 | bd->dstbus.addr += len; |
543 | 550 | ||
544 | BUG_ON(*remainder < len); | 551 | BUG_ON(bd->remainder < len); |
545 | 552 | ||
546 | *remainder -= len; | 553 | bd->remainder -= len; |
547 | } | 554 | } |
548 | 555 | ||
549 | /* | 556 | /* |
@@ -567,7 +574,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
567 | struct pl08x_txd *txd) | 574 | struct pl08x_txd *txd) |
568 | { | 575 | { |
569 | struct pl08x_bus_data *mbus, *sbus; | 576 | struct pl08x_bus_data *mbus, *sbus; |
570 | size_t remainder; | 577 | struct pl08x_lli_build_data bd; |
571 | int num_llis = 0; | 578 | int num_llis = 0; |
572 | u32 cctl; | 579 | u32 cctl; |
573 | size_t max_bytes_per_lli; | 580 | size_t max_bytes_per_lli; |
@@ -586,38 +593,43 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
586 | /* Get the default CCTL */ | 593 | /* Get the default CCTL */ |
587 | cctl = txd->cctl; | 594 | cctl = txd->cctl; |
588 | 595 | ||
596 | bd.txd = txd; | ||
597 | bd.pl08x = pl08x; | ||
598 | bd.srcbus.addr = txd->srcbus.addr; | ||
599 | bd.dstbus.addr = txd->dstbus.addr; | ||
600 | |||
589 | /* Find maximum width of the source bus */ | 601 | /* Find maximum width of the source bus */ |
590 | txd->srcbus.maxwidth = | 602 | bd.srcbus.maxwidth = |
591 | pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >> | 603 | pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >> |
592 | PL080_CONTROL_SWIDTH_SHIFT); | 604 | PL080_CONTROL_SWIDTH_SHIFT); |
593 | 605 | ||
594 | /* Find maximum width of the destination bus */ | 606 | /* Find maximum width of the destination bus */ |
595 | txd->dstbus.maxwidth = | 607 | bd.dstbus.maxwidth = |
596 | pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >> | 608 | pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >> |
597 | PL080_CONTROL_DWIDTH_SHIFT); | 609 | PL080_CONTROL_DWIDTH_SHIFT); |
598 | 610 | ||
599 | /* Set up the bus widths to the maximum */ | 611 | /* Set up the bus widths to the maximum */ |
600 | txd->srcbus.buswidth = txd->srcbus.maxwidth; | 612 | bd.srcbus.buswidth = bd.srcbus.maxwidth; |
601 | txd->dstbus.buswidth = txd->dstbus.maxwidth; | 613 | bd.dstbus.buswidth = bd.dstbus.maxwidth; |
602 | dev_vdbg(&pl08x->adev->dev, | 614 | dev_vdbg(&pl08x->adev->dev, |
603 | "%s source bus is %d bytes wide, dest bus is %d bytes wide\n", | 615 | "%s source bus is %d bytes wide, dest bus is %d bytes wide\n", |
604 | __func__, txd->srcbus.buswidth, txd->dstbus.buswidth); | 616 | __func__, bd.srcbus.buswidth, bd.dstbus.buswidth); |
605 | 617 | ||
606 | 618 | ||
607 | /* | 619 | /* |
608 | * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) | 620 | * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) |
609 | */ | 621 | */ |
610 | max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) * | 622 | max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * |
611 | PL080_CONTROL_TRANSFER_SIZE_MASK; | 623 | PL080_CONTROL_TRANSFER_SIZE_MASK; |
612 | dev_vdbg(&pl08x->adev->dev, | 624 | dev_vdbg(&pl08x->adev->dev, |
613 | "%s max bytes per lli = %zu\n", | 625 | "%s max bytes per lli = %zu\n", |
614 | __func__, max_bytes_per_lli); | 626 | __func__, max_bytes_per_lli); |
615 | 627 | ||
616 | /* We need to count this down to zero */ | 628 | /* We need to count this down to zero */ |
617 | remainder = txd->len; | 629 | bd.remainder = txd->len; |
618 | dev_vdbg(&pl08x->adev->dev, | 630 | dev_vdbg(&pl08x->adev->dev, |
619 | "%s remainder = %zu\n", | 631 | "%s remainder = %zu\n", |
620 | __func__, remainder); | 632 | __func__, bd.remainder); |
621 | 633 | ||
622 | /* | 634 | /* |
623 | * Choose bus to align to | 635 | * Choose bus to align to |
@@ -625,22 +637,20 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
625 | * - if fixed address on one bus chooses other | 637 | * - if fixed address on one bus chooses other |
626 | * - modifies cctl to choose an appropriate master | 638 | * - modifies cctl to choose an appropriate master |
627 | */ | 639 | */ |
628 | pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus, | 640 | pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); |
629 | &mbus, &sbus, cctl); | ||
630 | 641 | ||
631 | if (txd->len < mbus->buswidth) { | 642 | if (txd->len < mbus->buswidth) { |
632 | /* | 643 | /* |
633 | * Less than a bus width available | 644 | * Less than a bus width available |
634 | * - send as single bytes | 645 | * - send as single bytes |
635 | */ | 646 | */ |
636 | while (remainder) { | 647 | while (bd.remainder) { |
637 | dev_vdbg(&pl08x->adev->dev, | 648 | dev_vdbg(&pl08x->adev->dev, |
638 | "%s single byte LLIs for a transfer of " | 649 | "%s single byte LLIs for a transfer of " |
639 | "less than a bus width (remain 0x%08x)\n", | 650 | "less than a bus width (remain 0x%08x)\n", |
640 | __func__, remainder); | 651 | __func__, bd.remainder); |
641 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); | 652 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); |
642 | pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, | 653 | pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); |
643 | cctl, &remainder); | ||
644 | total_bytes++; | 654 | total_bytes++; |
645 | } | 655 | } |
646 | } else { | 656 | } else { |
@@ -652,10 +662,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
652 | dev_vdbg(&pl08x->adev->dev, | 662 | dev_vdbg(&pl08x->adev->dev, |
653 | "%s adjustment lli for less than bus width " | 663 | "%s adjustment lli for less than bus width " |
654 | "(remain 0x%08x)\n", | 664 | "(remain 0x%08x)\n", |
655 | __func__, remainder); | 665 | __func__, bd.remainder); |
656 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); | 666 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); |
657 | pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, | 667 | pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); |
658 | cctl, &remainder); | ||
659 | total_bytes++; | 668 | total_bytes++; |
660 | } | 669 | } |
661 | 670 | ||
@@ -675,14 +684,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
675 | * Make largest possible LLIs until less than one bus | 684 | * Make largest possible LLIs until less than one bus |
676 | * width left | 685 | * width left |
677 | */ | 686 | */ |
678 | while (remainder > (mbus->buswidth - 1)) { | 687 | while (bd.remainder > (mbus->buswidth - 1)) { |
679 | size_t lli_len, target_len, tsize, odd_bytes; | 688 | size_t lli_len, target_len, tsize, odd_bytes; |
680 | 689 | ||
681 | /* | 690 | /* |
682 | * If enough left try to send max possible, | 691 | * If enough left try to send max possible, |
683 | * otherwise try to send the remainder | 692 | * otherwise try to send the remainder |
684 | */ | 693 | */ |
685 | target_len = min(remainder, max_bytes_per_lli); | 694 | target_len = min(bd.remainder, max_bytes_per_lli); |
686 | 695 | ||
687 | /* | 696 | /* |
688 | * Set bus lengths for incrementing buses to the | 697 | * Set bus lengths for incrementing buses to the |
@@ -690,24 +699,24 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
690 | * limiting on the target length calculated above. | 699 | * limiting on the target length calculated above. |
691 | */ | 700 | */ |
692 | if (cctl & PL080_CONTROL_SRC_INCR) | 701 | if (cctl & PL080_CONTROL_SRC_INCR) |
693 | txd->srcbus.fill_bytes = | 702 | bd.srcbus.fill_bytes = |
694 | pl08x_pre_boundary(txd->srcbus.addr, | 703 | pl08x_pre_boundary(bd.srcbus.addr, |
695 | target_len); | 704 | target_len); |
696 | else | 705 | else |
697 | txd->srcbus.fill_bytes = target_len; | 706 | bd.srcbus.fill_bytes = target_len; |
698 | 707 | ||
699 | if (cctl & PL080_CONTROL_DST_INCR) | 708 | if (cctl & PL080_CONTROL_DST_INCR) |
700 | txd->dstbus.fill_bytes = | 709 | bd.dstbus.fill_bytes = |
701 | pl08x_pre_boundary(txd->dstbus.addr, | 710 | pl08x_pre_boundary(bd.dstbus.addr, |
702 | target_len); | 711 | target_len); |
703 | else | 712 | else |
704 | txd->dstbus.fill_bytes = target_len; | 713 | bd.dstbus.fill_bytes = target_len; |
705 | 714 | ||
706 | /* Find the nearest */ | 715 | /* Find the nearest */ |
707 | lli_len = min(txd->srcbus.fill_bytes, | 716 | lli_len = min(bd.srcbus.fill_bytes, |
708 | txd->dstbus.fill_bytes); | 717 | bd.dstbus.fill_bytes); |
709 | 718 | ||
710 | BUG_ON(lli_len > remainder); | 719 | BUG_ON(lli_len > bd.remainder); |
711 | 720 | ||
712 | if (lli_len <= 0) { | 721 | if (lli_len <= 0) { |
713 | dev_err(&pl08x->adev->dev, | 722 | dev_err(&pl08x->adev->dev, |
@@ -764,15 +773,15 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
764 | } | 773 | } |
765 | 774 | ||
766 | cctl = pl08x_cctl_bits(cctl, | 775 | cctl = pl08x_cctl_bits(cctl, |
767 | txd->srcbus.buswidth, | 776 | bd.srcbus.buswidth, |
768 | txd->dstbus.buswidth, | 777 | bd.dstbus.buswidth, |
769 | tsize); | 778 | tsize); |
770 | 779 | ||
771 | dev_vdbg(&pl08x->adev->dev, | 780 | dev_vdbg(&pl08x->adev->dev, |
772 | "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", | 781 | "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", |
773 | __func__, lli_len, remainder); | 782 | __func__, lli_len, bd.remainder); |
774 | pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, | 783 | pl08x_fill_lli_for_desc(&bd, num_llis++, |
775 | lli_len, cctl, &remainder); | 784 | lli_len, cctl); |
776 | total_bytes += lli_len; | 785 | total_bytes += lli_len; |
777 | } | 786 | } |
778 | 787 | ||
@@ -784,14 +793,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
784 | */ | 793 | */ |
785 | int j; | 794 | int j; |
786 | for (j = 0; (j < mbus->buswidth) | 795 | for (j = 0; (j < mbus->buswidth) |
787 | && (remainder); j++) { | 796 | && (bd.remainder); j++) { |
788 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); | 797 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); |
789 | dev_vdbg(&pl08x->adev->dev, | 798 | dev_vdbg(&pl08x->adev->dev, |
790 | "%s align with boundary, single byte (remain 0x%08zx)\n", | 799 | "%s align with boundary, single byte (remain 0x%08zx)\n", |
791 | __func__, remainder); | 800 | __func__, bd.remainder); |
792 | pl08x_fill_lli_for_desc(pl08x, txd, | 801 | pl08x_fill_lli_for_desc(&bd, |
793 | num_llis++, 1, cctl, | 802 | num_llis++, 1, cctl); |
794 | &remainder); | ||
795 | total_bytes++; | 803 | total_bytes++; |
796 | } | 804 | } |
797 | } | 805 | } |
@@ -800,13 +808,12 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, | |||
800 | /* | 808 | /* |
801 | * Send any odd bytes | 809 | * Send any odd bytes |
802 | */ | 810 | */ |
803 | while (remainder) { | 811 | while (bd.remainder) { |
804 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); | 812 | cctl = pl08x_cctl_bits(cctl, 1, 1, 1); |
805 | dev_vdbg(&pl08x->adev->dev, | 813 | dev_vdbg(&pl08x->adev->dev, |
806 | "%s align with boundary, single odd byte (remain %zu)\n", | 814 | "%s align with boundary, single odd byte (remain %zu)\n", |
807 | __func__, remainder); | 815 | __func__, bd.remainder); |
808 | pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, | 816 | pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); |
809 | cctl, &remainder); | ||
810 | total_bytes++; | 817 | total_bytes++; |
811 | } | 818 | } |
812 | } | 819 | } |