[#5551] SPI message lost when bus locked

Document created by Aaronwu Employee on Sep 4, 2013
Version 1Show Document
  • View in full screen mode

[#5551] SPI message lost when bus locked

Submitted By: Andrew Fomushkin

Open Date

2009-09-23 09:57:32     Close Date

2009-11-06 02:36:12

Priority:

Medium     Assignee:

Yi Li

Status:

Closed     Fixed In Release:

N/A

Found In Release:

2009R1-RC6     Release:

2009R1

Category:

Drivers     Board:

N/A

Processor:

ALL     Silicon Revision:

Is this bug repeatable?:

Yes     Resolution:

Fixed

Uboot version or rev.:

    Toolchain version or rev.:

2009R1_RC10

App binary format:

N/A     

Summary: SPI message lost when bus locked

Details:

 

When SPI bus locked (by mmc_spi for example) and someone wants to transfer SPI message on this bus system deadlocked.

 

Look at:

drivers/spi/spi_bfin5xx.c

bfin_spi_pump_messages()

 

original:

/* Someone has locked the bus */

if (drv_data->locked && next_cs != locked_cs) {

    list_for_each_entry(msg, &drv_data->queue, queue) {

        chip = spi_get_ctldata(next_msg->spi);

        next_cs = next_msg->spi->chip_select ?

            next_msg->spi->chip_select : chip->cs_gpio;

        if (next_cs == locked_cs) {

            next_msg = msg;

            break;

        }

    }

    /* Do nothing even if there are messages for other devices */

    if (next_cs != locked_cs) {

        drv_data->busy = 0;

        spin_unlock_irqrestore(&drv_data->lock, flags);

        return;

    }

}

 

I suggest:

/* Someone has locked the bus */

if (drv_data->locked && next_cs != locked_cs) {

    list_for_each_entry(msg, &drv_data->queue, queue) {

        chip = spi_get_ctldata(msg->spi);

        next_cs = msg->spi->chip_select ?

            msg->spi->chip_select : chip->cs_gpio;

        if (next_cs == locked_cs) {

            next_msg = msg;

            break;

        }

    }

    /* Do nothing even if there are messages for other devices */

    if (next_cs != locked_cs) {

        drv_data->busy = 0;

        spin_unlock_irqrestore(&drv_data->lock, flags);

        return;

    }

}

 

 

Follow-ups

 

--- Andrew Fomushkin                                         2009-09-26 01:07:38

I explain.

 

#ifdef CONFIG_SPI_BFIN_LOCK

        /* Extract head of queue */

    next_msg = list_entry(drv_data->queue.next,

        struct spi_message, queue);

 

    if (drv_data->locked) {

        locked_cs = drv_data->locked;

        chip = spi_get_ctldata(next_msg->spi);

        next_cs = next_msg->spi->chip_select ? next_msg->spi->chip_select

:

            chip->cs_gpio;

    }

 

    /* Someone has locked the bus */

    if (drv_data->locked && next_cs != locked_cs) {

        list_for_each_entry(msg, &drv_data->queue, queue) {

            chip = spi_get_ctldata(next_msg->spi);

            next_cs = next_msg->spi->chip_select ?

                next_msg->spi->chip_select : chip->cs_gpio;

            if (next_cs == locked_cs) {

                next_msg = msg;

                break;

            }

        }

        /* Do nothing even if there are messages for other devices */

        if (next_cs != locked_cs) {

            drv_data->busy = 0;

            spin_unlock_irqrestore(&drv_data->lock, flags);

            return;

        }

    }

    drv_data->cur_msg = next_msg;

#else

    /* Extract head of queue */

    drv_data->cur_msg = list_entry(drv_data->queue.next,

        struct spi_message, queue);

#endif

 

When SPI bus is locked and we search for a new message to send. We search

message that belongs to SPI slave that locked bus. If next message in queue

pointed by next_msg is not belong to SPI slave that locked bus we walk through

queue to find message that belongs to that slave, this is done by that cycle:

 

list_for_each_entry(msg, &drv_data->queue, queue) {

                    ^^^

    chip = spi_get_ctldata(next_msg->spi);

                               ^^^^^^^^

    next_cs = next_msg->spi->chip_select ?

                  ^^^^^^^^

        next_msg->spi->chip_select : chip->cs_gpio;

                ^^^^^^^^

    if (next_cs == locked_cs) {

        next_msg = msg;

        break;

    }

}

Cycle iterator is msg but we check next_msg that don't chahges and is pointed

to message that dont satisfy our conditions and driver do nothing because he not

found SPI message that he may to send, and he wait when new message from SPI

slave that locked bus appears or bus would be unlocked.

 

In practise I have SD card connected to SPI bus on BF537 and AD1937 that

connected to same bus (access to registers). When I do heavy read/write from/to

SD card like that:

dd if=/mnt/test1 of=/dev/null

and in a same time try to access to AD1939 bus is locked forever.

 

--- Yi Li                                                    2009-09-28 04:12:46

Thanks Andrew. I've made a stupid mistake.

I will check in your patch.

-Yi

 

--- Yi Li                                                    2009-09-28 04:26:27

Fixed on trunk and branch.

 

--- Yi Li                                                    2009-11-06 02:36:12

close it since it has been fixed.

 

 

 

    Files

    Changes

    Commits

    Dependencies

    Duplicates

    Associations

    Tags

 

File Name     File Type     File Size     Posted By

No Files Were Found

Attachments

    Outcomes