[PATCH 2/2] b43: fix DMA on some bugged hardware

Rafał Miłecki zajec5 at gmail.com
Wed Aug 10 13:10:03 EDT 2011


W dniu 10 sierpnia 2011 18:55 użytkownik Michael Büsch <m at bues.ch> napisał:
> On Wed, 10 Aug 2011 18:45:57 +0200
> Rafał Miłecki <zajec5 at gmail.com> wrote:
>
>> W dniu 10 sierpnia 2011 18:33 użytkownik Michael Büsch <m at bues.ch> napisał:
>> > On Wed, 10 Aug 2011 18:11:28 +0200
>> >> diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
>> >> index 0953ce1..9a2b678 100644
>> >> --- a/drivers/net/wireless/b43/dma.c
>> >> +++ b/drivers/net/wireless/b43/dma.c
>> >> @@ -174,7 +174,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
>> >>       addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
>> >>       addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
>> >>           >> SSB_DMA_TRANSLATION_SHIFT;
>> >> -     addrhi |= ring->dev->dma.translation;
>> >> +     if (ring->dev->dma.translation_in_low)
>> >> +             addrlo |= ring->dev->dma.translation;
>> >> +     else
>> >> +             addrhi |= ring->dev->dma.translation;
>> >>       if (slot == ring->nr_slots - 1)
>> >>               ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
>> >>       if (start)
>> >> @@ -656,10 +659,12 @@ static int alloc_initial_descbuffers(struct b43_dmaring *ring)
>> >>  static int dmacontroller_setup(struct b43_dmaring *ring)
>> >>  {
>> >>       int err = 0;
>> >> +     int tmp;
>> >>       u32 value;
>> >>       u32 addrext;
>> >>       u32 trans = ring->dev->dma.translation;
>> >>       bool parity = ring->dev->dma.parity;
>> >> +     u32 addrs[2];
>> >>
>> >>       if (ring->tx) {
>> >>               if (ring->type == B43_DMA_64BIT) {
>> >> @@ -673,12 +678,14 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
>> >>                       if (!parity)
>> >>                               value |= B43_DMA64_TXPARITYDISABLE;
>> >>                       b43_dma_write(ring, B43_DMA64_TXCTL, value);
>> >> -                     b43_dma_write(ring, B43_DMA64_TXRINGLO,
>> >> -                                   (ringbase & 0xFFFFFFFF));
>> >> -                     b43_dma_write(ring, B43_DMA64_TXRINGHI,
>> >> -                                   ((ringbase >> 32) &
>> >> -                                    ~SSB_DMA_TRANSLATION_MASK)
>> >> -                                   | trans);
>> >> +
>> >> +                     addrs[0] = ringbase & 0xFFFFFFFF;
>> >> +                     addrs[1] = ringbase >> 32;
>> >> +                     tmp = ring->dev->dma.translation_in_low ? 0 : 1;
>> >> +                     addrs[tmp] &= ~SSB_DMA_TRANSLATION_MASK;
>> >> +                     addrs[tmp] |= trans;
>> >> +                     b43_dma_write(ring, B43_DMA64_TXRINGLO, addrs[0]);
>> >> +                     b43_dma_write(ring, B43_DMA64_TXRINGHI, addrs[1]);
>> >>               } else {
>> >>                       u32 ringbase = (u32) (ring->dmabase);
>> >>
>> >> @@ -710,12 +717,15 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
>> >>                       if (!parity)
>> >>                               value |= B43_DMA64_RXPARITYDISABLE;
>> >>                       b43_dma_write(ring, B43_DMA64_RXCTL, value);
>> >> -                     b43_dma_write(ring, B43_DMA64_RXRINGLO,
>> >> -                                   (ringbase & 0xFFFFFFFF));
>> >> -                     b43_dma_write(ring, B43_DMA64_RXRINGHI,
>> >> -                                   ((ringbase >> 32) &
>> >> -                                    ~SSB_DMA_TRANSLATION_MASK)
>> >> -                                   | trans);
>> >> +
>> >> +                     addrs[0] = ringbase & 0xFFFFFFFF;
>> >> +                     addrs[1] = ringbase >> 32;
>> >> +                     tmp = ring->dev->dma.translation_in_low ? 0 : 1;
>> >> +                     addrs[tmp] &= ~SSB_DMA_TRANSLATION_MASK;
>> >> +                     addrs[tmp] |= trans;
>> >> +                     b43_dma_write(ring, B43_DMA64_RXRINGLO, addrs[0]);
>> >> +                     b43_dma_write(ring, B43_DMA64_RXRINGHI, addrs[1]);
>> >> +
>> >>                       b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
>> >>                                     sizeof(struct b43_dmadesc64));
>> >>               } else {
>> >> @@ -1052,6 +1062,21 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
>> >>       return 0;
>> >>  }
>> >
>> >
>> > This doesn't look correct to me for several reasons:
>> >
>> > In the fill-op the address is not masked correctly with the translation mask.
>> > In both the fill-op and both ring setups, the actual address extension bits
>> > are always taken from the address's high word. I guess the extension should
>> > be the low word bits for devices where we use the low word. That's the only
>> > thing that would make sense. But hey, it's not that we have sane hardware here.
>> > So this has to be checked.
>>
>> Ouch, yeah, you should be right (according to common sense of design).
>>
>> Unfortunately, on my machine, kernel provides low addresses for DMA purposes:
>> 0x1f310000
>> 0x1f318000
>> 0x1f31c000
>>
>> Can I ask/hack kernel to offer b43 addresses starting with 0x4... or
>> 0x8... (or 0xc...)?
>
> I'm not sure I understand..
> Are you actually saying that those shiny new devices are total crap
> in that their 64bit DMA engine can only do real-life-30bit, because they
> completely fucked up the extension bits?
> Did you try to fix the extension according to my suggestion? Does that
> break stuff?

Sorry, I was thinking about some additional tests without really
sharing my thoughts.

kernel offers me addresses like:
0x000000001f310000
0x000000001f318000
0x000000001f31c000

However I wanted to hack kernel to receive something conflicting with:
#define SSB_DMA_TRANSLATION_MASK	0xC0000000

For example I wanted to receive from kernel address like:
0x000000005f318000
or
0x000000009f318000


However that are just some additional tests. It sounds pretty obvious
that we should take addrext from the "correct" part of ringbase (AKA
ring->dmabase).

-- 
Rafał



More information about the b43-dev mailing list