• E
    spi/mmc_spi: SPI bus locking API, using mutex · cf32b71e
    Ernst Schwab 提交于
    SPI bus locking API to allow exclusive access to the SPI bus, especially, but
    not limited to, for the mmc_spi driver.
    
    Coded according to an outline from Grant Likely; here is his
    specification (accidentally swapped function names corrected):
    
    It requires 3 things to be added to struct spi_master.
    - 1 Mutex
    - 1 spin lock
    - 1 flag.
    
    The mutex protects spi_sync, and provides sleeping "for free"
    The spinlock protects the atomic spi_async call.
    The flag is set when the lock is obtained, and checked while holding
    the spinlock in spi_async().  If the flag is checked, then spi_async()
    must fail immediately.
    
    The current runtime API looks like this:
    spi_async(struct spi_device*, struct spi_message*);
    spi_sync(struct spi_device*, struct spi_message*);
    
    The API needs to be extended to this:
    spi_async(struct spi_device*, struct spi_message*)
    spi_sync(struct spi_device*, struct spi_message*)
    spi_bus_lock(struct spi_master*)  /* although struct spi_device* might
    be easier */
    spi_bus_unlock(struct spi_master*)
    spi_async_locked(struct spi_device*, struct spi_message*)
    spi_sync_locked(struct spi_device*, struct spi_message*)
    
    Drivers can only call the last two if they already hold the spi_master_lock().
    
    spi_bus_lock() obtains the mutex, obtains the spin lock, sets the
    flag, and releases the spin lock before returning.  It doesn't even
    need to sleep while waiting for "in-flight" spi_transactions to
    complete because its purpose is to guarantee no additional
    transactions are added.  It does not guarantee that the bus is idle.
    
    spi_bus_unlock() clears the flag and releases the mutex, which will
    wake up any waiters.
    
    The difference between spi_async() and spi_async_locked() is that the
    locked version bypasses the check of the lock flag.  Both versions
    need to obtain the spinlock.
    
    The difference between spi_sync() and spi_sync_locked() is that
    spi_sync() must hold the mutex while enqueuing a new transfer.
    spi_sync_locked() doesn't because the mutex is already held.  Note
    however that spi_sync must *not* continue to hold the mutex while
    waiting for the transfer to complete, otherwise only one transfer
    could be queued up at a time!
    
    Almost no code needs to be written.  The current spi_async() and
    spi_sync() can probably be renamed to __spi_async() and __spi_sync()
    so that spi_async(), spi_sync(), spi_async_locked() and
    spi_sync_locked() can just become wrappers around the common code.
    
    spi_sync() is protected by a mutex because it can sleep
    spi_async() needs to be protected with a flag and a spinlock because
    it can be called atomically and must not sleep
    Signed-off-by: NErnst Schwab <eschwab@online.de>
    [grant.likely@secretlab.ca: use spin_lock_irqsave()]
    Signed-off-by: NGrant Likely <grant.likely@secretlab.ca>
    Tested-by: NMatt Fleming <matt@console-pimps.org>
    Tested-by: NAntonio Ospite <ospite@studenti.unina.it>
    cf32b71e
spi.h 28.4 KB