• Andy Chiu's avatar
    net: axienet: Use iowrite64 to write all 64b descriptor pointers · b690f8df
    Andy Chiu authored
    According to commit f735c40e ("net: axienet: Autodetect 64-bit DMA
    capability") and AXI-DMA spec (pg021), on 64-bit capable dma, only
    writing MSB part of tail descriptor pointer causes DMA engine to start
    fetching descriptors. However, we found that it is true only if dma is in
    idle state. In other words, dma would use a tailp even if it only has LSB
    updated, when the dma is running.
    
    The non-atomicity of this behavior could be problematic if enough
    delay were introduced in between the 2 writes. For example, if an
    interrupt comes right after the LSB write and the cpu spends long
    enough time in the handler for the dma to get back into idle state by
    completing descriptors, then the seconcd write to MSB would treat dma
    to start fetching descriptors again. Since the descriptor next to the
    one pointed by current tail pointer is not filled by the kernel yet,
    fetching a null descriptor here causes a dma internal error and halt
    the dma engine down.
    
    We suggest that the dma engine should start process a 64-bit MMIO write
    to the descriptor pointer only if ONE 32-bit part of it is written on all
    states. Or we should restrict the use of 64-bit addressable dma on 32-bit
    platforms, since those devices have no instruction to guarantee the write
    to LSB and MSB part of tail pointer occurs atomically to the dma.
    
    initial condition:
    curp =  x-3;
    tailp = x-2;
    LSB = x;
    MSB = 0;
    
    cpu:                       |dma:
     iowrite32(LSB, tailp)     |  completes #(x-3) desc, curp = x-3
     ...                       |  tailp updated
     => irq                    |  completes #(x-2) desc, curp = x-2
        ...                    |  completes #(x-1) desc, curp = x-1
        ...                    |  ...
        ...                    |  completes #x desc, curp = tailp = x
     <= irqreturn              |  reaches tailp == curp = x, idle
     iowrite32(MSB, tailp + 4) |  ...
                               |  tailp updated, starts fetching...
                               |  fetches #(x + 1) desc, sees cntrl = 0
                               |  post Tx error, halt
    Signed-off-by: default avatarAndy Chiu <andy.chiu@sifive.com>
    Reported-by: default avatarMax Hsu <max.hsu@sifive.com>
    Reviewed-by: default avatarGreentime Hu <greentime.hu@sifive.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    b690f8df
xilinx_axienet.h 23.4 KB