diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2011-08-14 14:16:37 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-24 14:41:41 -0400 |
commit | 0cc9772a6bd8002aaf7583194098e92481d9c7f1 (patch) | |
tree | 4eb6f9e26ec65218aaed7b868f3235cd20c6c724 | |
parent | 04023afcce2eaff4f66d19ca21b106512fffabe7 (diff) |
b43: fix DMA on some bugged hardware
Some hardware with 64-bit DMA uses lower address word for setting
routing (translation) bit. Add workaround for such boards.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 113 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.h | 6 |
3 files changed, 84 insertions, 36 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f4e9d8b7d9f8..9e5974bf2655 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -594,6 +594,7 @@ struct b43_dma { | |||
594 | struct b43_dmaring *rx_ring; | 594 | struct b43_dmaring *rx_ring; |
595 | 595 | ||
596 | u32 translation; /* Routing bits */ | 596 | u32 translation; /* Routing bits */ |
597 | bool translation_in_low; /* Should translation bit go into low addr? */ | ||
597 | bool parity; /* Check for parity */ | 598 | bool parity; /* Check for parity */ |
598 | }; | 599 | }; |
599 | 600 | ||
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index d0d9aee44a59..e76b40ddbc48 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -47,6 +47,38 @@ | |||
47 | * into separate slots. */ | 47 | * into separate slots. */ |
48 | #define TX_SLOTS_PER_FRAME 2 | 48 | #define TX_SLOTS_PER_FRAME 2 |
49 | 49 | ||
50 | static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr, | ||
51 | enum b43_addrtype addrtype) | ||
52 | { | ||
53 | u32 uninitialized_var(addr); | ||
54 | |||
55 | switch (addrtype) { | ||
56 | case B43_DMA_ADDR_LOW: | ||
57 | addr = lower_32_bits(dmaaddr); | ||
58 | if (dma->translation_in_low) { | ||
59 | addr &= ~SSB_DMA_TRANSLATION_MASK; | ||
60 | addr |= dma->translation; | ||
61 | } | ||
62 | break; | ||
63 | case B43_DMA_ADDR_HIGH: | ||
64 | addr = upper_32_bits(dmaaddr); | ||
65 | if (!dma->translation_in_low) { | ||
66 | addr &= ~SSB_DMA_TRANSLATION_MASK; | ||
67 | addr |= dma->translation; | ||
68 | } | ||
69 | break; | ||
70 | case B43_DMA_ADDR_EXT: | ||
71 | if (dma->translation_in_low) | ||
72 | addr = lower_32_bits(dmaaddr); | ||
73 | else | ||
74 | addr = upper_32_bits(dmaaddr); | ||
75 | addr &= SSB_DMA_TRANSLATION_MASK; | ||
76 | addr >>= SSB_DMA_TRANSLATION_SHIFT; | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | return addr; | ||
81 | } | ||
50 | 82 | ||
51 | /* 32bit DMA ops. */ | 83 | /* 32bit DMA ops. */ |
52 | static | 84 | static |
@@ -77,10 +109,9 @@ static void op32_fill_descriptor(struct b43_dmaring *ring, | |||
77 | slot = (int)(&(desc->dma32) - descbase); | 109 | slot = (int)(&(desc->dma32) - descbase); |
78 | B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); | 110 | B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); |
79 | 111 | ||
80 | addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK); | 112 | addr = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW); |
81 | addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK) | 113 | addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT); |
82 | >> SSB_DMA_TRANSLATION_SHIFT; | 114 | |
83 | addr |= ring->dev->dma.translation; | ||
84 | ctl = bufsize & B43_DMA32_DCTL_BYTECNT; | 115 | ctl = bufsize & B43_DMA32_DCTL_BYTECNT; |
85 | if (slot == ring->nr_slots - 1) | 116 | if (slot == ring->nr_slots - 1) |
86 | ctl |= B43_DMA32_DCTL_DTABLEEND; | 117 | ctl |= B43_DMA32_DCTL_DTABLEEND; |
@@ -170,11 +201,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring, | |||
170 | slot = (int)(&(desc->dma64) - descbase); | 201 | slot = (int)(&(desc->dma64) - descbase); |
171 | B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); | 202 | B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); |
172 | 203 | ||
173 | addrlo = (u32) (dmaaddr & 0xFFFFFFFF); | 204 | addrlo = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW); |
174 | addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); | 205 | addrhi = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_HIGH); |
175 | addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) | 206 | addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT); |
176 | >> SSB_DMA_TRANSLATION_SHIFT; | 207 | |
177 | addrhi |= ring->dev->dma.translation; | ||
178 | if (slot == ring->nr_slots - 1) | 208 | if (slot == ring->nr_slots - 1) |
179 | ctl0 |= B43_DMA64_DCTL0_DTABLEEND; | 209 | ctl0 |= B43_DMA64_DCTL0_DTABLEEND; |
180 | if (start) | 210 | if (start) |
@@ -658,41 +688,37 @@ static int dmacontroller_setup(struct b43_dmaring *ring) | |||
658 | int err = 0; | 688 | int err = 0; |
659 | u32 value; | 689 | u32 value; |
660 | u32 addrext; | 690 | u32 addrext; |
661 | u32 trans = ring->dev->dma.translation; | ||
662 | bool parity = ring->dev->dma.parity; | 691 | bool parity = ring->dev->dma.parity; |
692 | u32 addrlo; | ||
693 | u32 addrhi; | ||
663 | 694 | ||
664 | if (ring->tx) { | 695 | if (ring->tx) { |
665 | if (ring->type == B43_DMA_64BIT) { | 696 | if (ring->type == B43_DMA_64BIT) { |
666 | u64 ringbase = (u64) (ring->dmabase); | 697 | u64 ringbase = (u64) (ring->dmabase); |
698 | addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); | ||
699 | addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); | ||
700 | addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH); | ||
667 | 701 | ||
668 | addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) | ||
669 | >> SSB_DMA_TRANSLATION_SHIFT; | ||
670 | value = B43_DMA64_TXENABLE; | 702 | value = B43_DMA64_TXENABLE; |
671 | value |= (addrext << B43_DMA64_TXADDREXT_SHIFT) | 703 | value |= (addrext << B43_DMA64_TXADDREXT_SHIFT) |
672 | & B43_DMA64_TXADDREXT_MASK; | 704 | & B43_DMA64_TXADDREXT_MASK; |
673 | if (!parity) | 705 | if (!parity) |
674 | value |= B43_DMA64_TXPARITYDISABLE; | 706 | value |= B43_DMA64_TXPARITYDISABLE; |
675 | b43_dma_write(ring, B43_DMA64_TXCTL, value); | 707 | b43_dma_write(ring, B43_DMA64_TXCTL, value); |
676 | b43_dma_write(ring, B43_DMA64_TXRINGLO, | 708 | b43_dma_write(ring, B43_DMA64_TXRINGLO, addrlo); |
677 | (ringbase & 0xFFFFFFFF)); | 709 | b43_dma_write(ring, B43_DMA64_TXRINGHI, addrhi); |
678 | b43_dma_write(ring, B43_DMA64_TXRINGHI, | ||
679 | ((ringbase >> 32) & | ||
680 | ~SSB_DMA_TRANSLATION_MASK) | ||
681 | | trans); | ||
682 | } else { | 710 | } else { |
683 | u32 ringbase = (u32) (ring->dmabase); | 711 | u32 ringbase = (u32) (ring->dmabase); |
712 | addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); | ||
713 | addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); | ||
684 | 714 | ||
685 | addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) | ||
686 | >> SSB_DMA_TRANSLATION_SHIFT; | ||
687 | value = B43_DMA32_TXENABLE; | 715 | value = B43_DMA32_TXENABLE; |
688 | value |= (addrext << B43_DMA32_TXADDREXT_SHIFT) | 716 | value |= (addrext << B43_DMA32_TXADDREXT_SHIFT) |
689 | & B43_DMA32_TXADDREXT_MASK; | 717 | & B43_DMA32_TXADDREXT_MASK; |
690 | if (!parity) | 718 | if (!parity) |
691 | value |= B43_DMA32_TXPARITYDISABLE; | 719 | value |= B43_DMA32_TXPARITYDISABLE; |
692 | b43_dma_write(ring, B43_DMA32_TXCTL, value); | 720 | b43_dma_write(ring, B43_DMA32_TXCTL, value); |
693 | b43_dma_write(ring, B43_DMA32_TXRING, | 721 | b43_dma_write(ring, B43_DMA32_TXRING, addrlo); |
694 | (ringbase & ~SSB_DMA_TRANSLATION_MASK) | ||
695 | | trans); | ||
696 | } | 722 | } |
697 | } else { | 723 | } else { |
698 | err = alloc_initial_descbuffers(ring); | 724 | err = alloc_initial_descbuffers(ring); |
@@ -700,9 +726,10 @@ static int dmacontroller_setup(struct b43_dmaring *ring) | |||
700 | goto out; | 726 | goto out; |
701 | if (ring->type == B43_DMA_64BIT) { | 727 | if (ring->type == B43_DMA_64BIT) { |
702 | u64 ringbase = (u64) (ring->dmabase); | 728 | u64 ringbase = (u64) (ring->dmabase); |
729 | addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); | ||
730 | addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); | ||
731 | addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH); | ||
703 | 732 | ||
704 | addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) | ||
705 | >> SSB_DMA_TRANSLATION_SHIFT; | ||
706 | value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT); | 733 | value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT); |
707 | value |= B43_DMA64_RXENABLE; | 734 | value |= B43_DMA64_RXENABLE; |
708 | value |= (addrext << B43_DMA64_RXADDREXT_SHIFT) | 735 | value |= (addrext << B43_DMA64_RXADDREXT_SHIFT) |
@@ -710,19 +737,15 @@ static int dmacontroller_setup(struct b43_dmaring *ring) | |||
710 | if (!parity) | 737 | if (!parity) |
711 | value |= B43_DMA64_RXPARITYDISABLE; | 738 | value |= B43_DMA64_RXPARITYDISABLE; |
712 | b43_dma_write(ring, B43_DMA64_RXCTL, value); | 739 | b43_dma_write(ring, B43_DMA64_RXCTL, value); |
713 | b43_dma_write(ring, B43_DMA64_RXRINGLO, | 740 | b43_dma_write(ring, B43_DMA64_RXRINGLO, addrlo); |
714 | (ringbase & 0xFFFFFFFF)); | 741 | b43_dma_write(ring, B43_DMA64_RXRINGHI, addrhi); |
715 | b43_dma_write(ring, B43_DMA64_RXRINGHI, | ||
716 | ((ringbase >> 32) & | ||
717 | ~SSB_DMA_TRANSLATION_MASK) | ||
718 | | trans); | ||
719 | b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots * | 742 | b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots * |
720 | sizeof(struct b43_dmadesc64)); | 743 | sizeof(struct b43_dmadesc64)); |
721 | } else { | 744 | } else { |
722 | u32 ringbase = (u32) (ring->dmabase); | 745 | u32 ringbase = (u32) (ring->dmabase); |
746 | addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); | ||
747 | addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); | ||
723 | 748 | ||
724 | addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) | ||
725 | >> SSB_DMA_TRANSLATION_SHIFT; | ||
726 | value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT); | 749 | value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT); |
727 | value |= B43_DMA32_RXENABLE; | 750 | value |= B43_DMA32_RXENABLE; |
728 | value |= (addrext << B43_DMA32_RXADDREXT_SHIFT) | 751 | value |= (addrext << B43_DMA32_RXADDREXT_SHIFT) |
@@ -730,9 +753,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring) | |||
730 | if (!parity) | 753 | if (!parity) |
731 | value |= B43_DMA32_RXPARITYDISABLE; | 754 | value |= B43_DMA32_RXPARITYDISABLE; |
732 | b43_dma_write(ring, B43_DMA32_RXCTL, value); | 755 | b43_dma_write(ring, B43_DMA32_RXCTL, value); |
733 | b43_dma_write(ring, B43_DMA32_RXRING, | 756 | b43_dma_write(ring, B43_DMA32_RXRING, addrlo); |
734 | (ringbase & ~SSB_DMA_TRANSLATION_MASK) | ||
735 | | trans); | ||
736 | b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots * | 757 | b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots * |
737 | sizeof(struct b43_dmadesc32)); | 758 | sizeof(struct b43_dmadesc32)); |
738 | } | 759 | } |
@@ -1061,6 +1082,25 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) | |||
1061 | return 0; | 1082 | return 0; |
1062 | } | 1083 | } |
1063 | 1084 | ||
1085 | /* Some hardware with 64-bit DMA seems to be bugged and looks for translation | ||
1086 | * bit in low address word instead of high one. | ||
1087 | */ | ||
1088 | static bool b43_dma_translation_in_low_word(struct b43_wldev *dev, | ||
1089 | enum b43_dmatype type) | ||
1090 | { | ||
1091 | if (type != B43_DMA_64BIT) | ||
1092 | return 1; | ||
1093 | |||
1094 | #ifdef CONFIG_B43_SSB | ||
1095 | if (dev->dev->bus_type == B43_BUS_SSB && | ||
1096 | dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && | ||
1097 | !(dev->dev->sdev->bus->host_pci->is_pcie && | ||
1098 | ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)) | ||
1099 | return 1; | ||
1100 | #endif | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1064 | int b43_dma_init(struct b43_wldev *dev) | 1104 | int b43_dma_init(struct b43_wldev *dev) |
1065 | { | 1105 | { |
1066 | struct b43_dma *dma = &dev->dma; | 1106 | struct b43_dma *dma = &dev->dma; |
@@ -1086,6 +1126,7 @@ int b43_dma_init(struct b43_wldev *dev) | |||
1086 | break; | 1126 | break; |
1087 | #endif | 1127 | #endif |
1088 | } | 1128 | } |
1129 | dma->translation_in_low = b43_dma_translation_in_low_word(dev, type); | ||
1089 | 1130 | ||
1090 | dma->parity = true; | 1131 | dma->parity = true; |
1091 | #ifdef CONFIG_B43_BCMA | 1132 | #ifdef CONFIG_B43_BCMA |
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 546d19cbf5d5..7e20b04fa51a 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h | |||
@@ -215,6 +215,12 @@ enum b43_dmatype { | |||
215 | B43_DMA_64BIT = 64, | 215 | B43_DMA_64BIT = 64, |
216 | }; | 216 | }; |
217 | 217 | ||
218 | enum b43_addrtype { | ||
219 | B43_DMA_ADDR_LOW, | ||
220 | B43_DMA_ADDR_HIGH, | ||
221 | B43_DMA_ADDR_EXT, | ||
222 | }; | ||
223 | |||
218 | struct b43_dmaring { | 224 | struct b43_dmaring { |
219 | /* Lowlevel DMA ops. */ | 225 | /* Lowlevel DMA ops. */ |
220 | const struct b43_dma_ops *ops; | 226 | const struct b43_dma_ops *ops; |