Ethernet deadlocks and forking the kernel
kernel ?? Comments Wed 16 July 2014 Chris PerivolaropoulosThis is a bit specific but it is something I encountered more than once and spent a couple of hours trying to fix. So here is the problem. I have a xilinx zynq zc702 board and I load a slightly customized 3.8 linux kernel on it. I boot it and it freezes at
loop: module loaded
xqspips e000d000.spi: master is unqueued, this is deprecated
Now now you probably want to know what boot arguments I was using and what kind of modifications I have made to the kernel and the exact release but it doesn't really matter. The problem was the xqspips driver and not the fact that something is deprecated -who knows what this message means exactly-.
Let me walk you through around the problem what happens in drivers/spi/spi-xilinx-qps.c when a spi transfer commences.
xqspips_start_transferruns- At some poiunt it writes to
XQSPIPS_IEN_OFFSETregister to raise an interrupt that will call asynchronouslyxqspips_irq xqspips_start_transferinits some other stuff and then waits forxqspips_irqto set a completion structure.
Now xqspips_irq is passed a xqspips structure that contains
information about how much data we want to transmit and how much data
we expect to receive.
- First it checks with the status register to see if there is some space in the transfer buffer or that there is something useful in the receive buffer.
- While the receive buffer is not empty try to read data from it
decrementing
struct xqspips->bytes_to_receivecorrectly. - If there is stuff to transfer, transfer it
- If
struct xqspips->bytes_to_receiveis not yet zero reissue an interrupt in a slightly different way than before and finalize. - If
struct xqspips->bytes_to_receiveis zero complete the completion struct thatxqspips_start_transferis waiting for and finalize.
The above is a rough descriuption of the situation. Now I don't know
if it is a hardware problem or a driver bug but there are two problems
here. One is that xqspi->bytes_to_receive is 1 while the status
register claims there is no data in the buffer. And also setting the
IEN register doesn't raise an interrupt. Thus irq callback fails to
read the data isntructed by xqspi->bytes_to_receive and proceeds
finish confident that an interrupt was raised to take care of the
situation.
The hard part of this was finding all the above out. Then it was
trivial to just tell xqspips_irq to not only check the status
register to decide whether it should read or not, but also check with
the xqspi struct. Essentially changing
/* Read out the data from the RX FIFO */
while (xqspips_read(xqspi->regs + XQSPIPS_STATUS_OFFSET) &
XQSPIPS_IXR_RXNEMTY_MASK) {
into
/* Read out the data from the RX FIFO */
while ((xqspips_read(xqspi->regs + XQSPIPS_STATUS_OFFSET) &
XQSPIPS_IXR_RXNEMTY_MASK) ||
xqspi->bytes_to_receive) {
did the trick.
Tags: kernel drivers irq linux