On Wed, Jan 15, 2014 at 03:41:07PM +0100, Martin Pieuchot wrote:
> On 15/01/14(Wed) 15:27, Stefan Sperling wrote:
> > On Wed, Jan 15, 2014 at 10:11:27AM +0100, Martin Pieuchot wrote:
> > > On 14/01/14(Tue) 16:21, Sunny Raspet wrote:
> > > > Hello!
> > > > 
> > > > Running 5.4-RELEASE/macppc on a Mac PowerBook G4, attempting to
> > > > interact with the built-in bwi(4) card results in badness.
> > > 
> > > Sadly this is a know issue on most of the macppc machine having a
> > > bwi(4).  If somebody has more inputs I'm also interested ;) 
> > > 
> > > M.
> > 
> > It seems the bwi driver lacks support for PIO mode which the
> > linux b43 driver falls back to in case of DMA errors such as
> > this one.
> > 
> > Two related linux commits:
> > https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=9e3bd9190800e8209b4a3e1d724c35f0738dcad2
> > https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5100d5ac81b9330dc57e35adbe50923ba6107b8f
> > I'm not sure why the latter commit talks about PCMCIA but it mentions
> > the powerbook G4.
> 
> That might help but that's just the top of the iceberg.  At some point
> this driver worked with my iBook G4 (I remember using it a lot in 4.7).
> 
> Now and for quite some time it produces the same intr error.  Same
> problem with my PowerBook G4 12''.  However it works well on my
> PowerBook 15'' ...

With tcpdump I noticed that the chip would sometimes receive one or two frames
before the error occured. Also, in my case, the chip is using 30 bits of bus 
space
(sc->sc_bus_space == BWI_BUS_SPACE_30BIT).

Dumping the RX descriptor ring shows that RX works for descriptors
which use a physical addresses which fits into 30 bits, like in this
case (showing allocations for the first 4 descriptors):
 
Jun 13 15:11:32 fintan /bsd: bwi_setup_desc32: paddr=0xfe5000, addr=0x40fe5000, 
addr_hi=0x0, addr_lo=0xfe5000 ctrl=0x7e2, buf_len=2018
Jun 13 15:11:32 fintan /bsd: bwi_setup_desc32: paddr=0xfe5800, addr=0x40fe5800, 
addr_hi=0x0, addr_lo=0xfe5800 ctrl=0x7e2, buf_len=2018
Jun 13 15:11:32 fintan /bsd: bwi_setup_desc32: paddr=0x4f43e000, 
addr=0x4f43e000, addr_hi=0x1, addr_lo=0xf43e000 ctrl=0x107e2, buf_len=2018
Jun 13 15:11:32 fintan /bsd: bwi_setup_desc32: paddr=0x4f43e800, 
addr=0x4f43e800, addr_hi=0x1, addr_lo=0xf43e800 ctrl=0x107e2, buf_len=2018

In the capture below there is a valid frame in the second buffer when the RX 
interrupt
occurs (ieee80211_dump_pkt() is very useful). The first element of the RX ring 
has
already been replaced with a fresh one (which is using an address above 30 bit).

Jun 13 15:11:32 fintan /bsd: bwi_rxeof
Jun 13 15:11:32 fintan /bsd: bwi_setup_desc32: paddr=0x4cda2000, 
addr=0x4cda2000, addr_hi=0x1, addr_lo=0xcda2000 ctrl=0x107e2, buf_len=2018
Jun 13 15:11:32 fintan /bsd: bwi0: intr fatal TX/RX (0) error 0x00011000
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: rd->rdata_txrx_ctrl = 200
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: rd->rdata_paddr = f80000
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: desc[0]->ctrl = 107e2, 
desc[0]->addr = 4cda2000
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: rb=0xe013018c 
rb->rb_paddr=4cda2000 rb->rb_mbuf = 0x4cda4100
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_buflen=0
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_pad1[0]=
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_pad1[1]=
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_rssi=
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_sq=0
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_phyinfo=0
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_flags3=0
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_flags2=0
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_tsf=0
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: desc[1]->ctrl = 7e2, 
desc[1]->addr = 40fe5800
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: rb=0xe0130198 
rb->rb_paddr=fe5800 rb->rb_mbuf = 0xfe6b00
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_buflen=241
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_pad1[0]=
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_pad1[1]=
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_rssi=\^]
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_sq=8192
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_phyinfo=-1055
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_flags3=1800
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_flags2=0
Jun 13 15:11:32 fintan /bsd: bwi_dump_rx_ring32: hdr->rxh_tsf=46ae
Jun 13 15:11:32 fintan /bsd: NODS 
88:25:2c:dc:cd:3e->ff:ff:ff:ff:ff:ff(88:25:2c:dc:cd:3e) beacon 0M +0
Jun 13 15:11:32 fintan /bsd:  8000 0000 ffff ffff ffff 8825 2cdc cd3e 8825 2cdc 
cd3e 60ff 83e1 0fc1 7600 0000 6400 1104 000b 574c 414e 2d44 4343 4438 3401 0882 
848b 9624 3048 6c03 0101 0504 0001 0100 2a01 002f 0100 3014 0100 000f ac04 0100 
000f ac04 0100 000f ac02 0000 3204 0c12 1860 2d1a 6c18 1fff ff00 0000 0000 0000 
0000 0000 0000 0000 0000 0000 0000 3d16 0108 0400 0000 0000 0000 0000 0000 0000 
0000 0000 0000 4a0e 1400 0a00 2c01 c800 1400 0500 1900 7f01 01dd 0900 1018 0204 
f005 0000 dd18 0050 f202 0101 0000 03a4 0000 27a4 0000 4243 5e00 6232 2f00 dd13 
0050 f204 104a 0001 1010 4400 0102 103c 0001 0340 c12b eecb baf1 b85a d8

Furthermore, RX interrupt status has the "descriptor protocol error" bit set,
which (for the TX path) is documented as "Indicates the Descriptor Ring Address
could not be accessed" at http://bcm-specs.sipsolutions.net/DMA#General

So the chip freaks out and switches into interrupt storm mode. And the driver
is stupid enough to do a printf() on each interrupt when this happens so
the machine is live locked.

And, tada, removing the 1GB of extra RAM from my powerbook G4, leaving 512MB,
makes the device work.

I think we'll need a bounce buffer here, like was done for bce(4).

Linux b43legacy retries allocations if it gets a physical address which
this chip cannot handle...

/* Check if a DMA mapping address is invalid. */
static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
                                         dma_addr_t addr,
                                         size_t buffersize,
                                         bool dma_to_device)
{
        if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
                return 1;

        switch (ring->type) {
        case B43legacy_DMA_30BIT:
                if ((u64)addr + buffersize > (1ULL << 30))
                        goto address_error;
                break;
        case B43legacy_DMA_32BIT:
                if ((u64)addr + buffersize > (1ULL << 32))
                        goto address_error;
                break;
        }

        /* The address is OK. */                  
        return 0;                                 
                                                  
address_error:                           
        /* We can't support this address. Unmap it again. */
        unmap_descbuffer(ring, addr, buffersize, dma_to_device);

        return 1;
}

Reply via email to