Title: [7401] trunk/drivers: revise spi_lock_bus(), spi_unlock_bus() based on feedback from LKML.
- Revision
- 7401
- Author
- adamliyi
- Date
- 2009-09-22 03:42:35 -0400 (Tue, 22 Sep 2009)
Log Message
revise spi_lock_bus(), spi_unlock_bus() based on feedback from LKML.
- spi_lock_bus(), spi_unlock_bus() return -ENOSYS if not implemented
- spi_unlocK_bus() returns -ENOLCK if the caller did not call spi_lock_bus() before
- add check in mmc_spi driver. If a system has more than one spi device registered and the system has no spi_lock_bus(), mmc_spi cannot be used.
Modified Paths
Diff
Modified: trunk/drivers/mmc/host/mmc_spi.c (7400 => 7401)
--- trunk/drivers/mmc/host/mmc_spi.c 2009-09-22 04:55:28 UTC (rev 7400)
+++ trunk/drivers/mmc/host/mmc_spi.c 2009-09-22 07:42:35 UTC (rev 7401)
@@ -1084,7 +1084,11 @@
#endif
/* issue command; then optionally data and stop */
- spi_lock_bus(host->spi);
+ status = spi_lock_bus(host->spi);
+ if (status == -ENOLCK) {
+ dev_err(&host->spi->dev, "failed to lock spi bus\n");
+ return;
+ }
status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
if (status == 0 && mrq->data) {
mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
@@ -1093,7 +1097,11 @@
else
mmc_cs_off(host);
}
- spi_unlock_bus(host->spi);
+ status = spi_unlock_bus(host->spi);
+ if (status == -ENOLCK) {
+ dev_err(&host->spi->dev, "failed to unlock spi bus\n");
+ return;
+ }
mmc_request_done(host->mmc, mrq);
}
@@ -1338,6 +1346,41 @@
return status;
}
+ /* We can use the bus safely if nobody else will interfere with us.
+ * Most commands consist of one SPI message to issue a command, then
+ * several more to collect its response, then possibly more for data
+ * transfer. Clocking access to other devices during that period will
+ * corrupt the command execution.
+ *
+ * spi_lock_bus() is used to guarantee exclusive access to spi bus. For
+ * system without spi_lock_bus(), if mmc_spi is the only registered spi
+ * device, we use spi bus based on the unsafe assumption that no other
+ * spi devices will be added later.
+ */
+
+ if (spi->master->num_chipselect > 1) {
+ struct count_children cc;
+
+ /* Test if spi master implementes spi_lock_bus() */
+ status = spi_lock_bus(spi);
+ spi_unlock_bus(spi);
+ if (status == -ENOSYS) {
+ /* No. Am I the only spi device registered? */
+ cc.n = 0;
+ cc.bus = spi->dev.bus;
+ status = device_for_each_child(spi->dev.parent, &cc,
+ maybe_count_child);
+ if (status < 0) {
+ dev_err(&spi->dev, "can't share SPI bus\n");
+ return status;
+ }
+ /* REVISIT we can't guarantee another device
+ * won't be added later... */
+ dev_warn(&spi->dev,
+ "ASSUMING SPI bus stays unshared!\n");
+ }
+ }
+
/* We need a supply of ones to transmit. This is the only time
* the CPU touches these, so cache coherency isn't a concern.
*
Modified: trunk/drivers/spi/spi.c (7400 => 7401)
--- trunk/drivers/spi/spi.c 2009-09-22 04:55:28 UTC (rev 7400)
+++ trunk/drivers/spi/spi.c 2009-09-22 07:42:35 UTC (rev 7401)
@@ -666,14 +666,16 @@
* So this call may be used in irq and other contexts which can't sleep,
* as well as from task contexts which can sleep.
*
- * It returns zero on success, else a negative error code.
+ * It returns zero on success, else a negative error code:
+ * -ENOSYS: spi master driver does not implement this function
+ * -ENOLCK: cannot lock the bus
*/
int spi_lock_bus(struct spi_device *spi)
{
if (spi->master->lock_bus)
return spi->master->lock_bus(spi);
else
- return 0;
+ return -ENOSYS;
}
EXPORT_SYMBOL_GPL(spi_lock_bus);
@@ -687,16 +689,18 @@
* can be transferred.
*
* If the caller did not call spi_lock_bus() before, spi_unlock_bus()
- * should have no effect.
+ * will return -ENOLCK.
*
- * It returns zero on success, else a negative error code.
+ * It returns zero on success, else a negative error code:
+ * -ENOSYS: spi master driver does not implement this function
+ * -ENOLCK: cannot unlock the bus
*/
int spi_unlock_bus(struct spi_device *spi)
{
if (spi->master->unlock_bus)
return spi->master->unlock_bus(spi);
else
- return 0;
+ return -ENOSYS;
}
EXPORT_SYMBOL_GPL(spi_unlock_bus);
Modified: trunk/drivers/spi/spi_bfin5xx.c (7400 => 7401)
--- trunk/drivers/spi/spi_bfin5xx.c 2009-09-22 04:55:28 UTC (rev 7400)
+++ trunk/drivers/spi/spi_bfin5xx.c 2009-09-22 07:42:35 UTC (rev 7401)
@@ -1118,33 +1118,42 @@
*/
static int bfin_spi_lock_bus(struct spi_device *spi)
{
+ int ret = -ENOSYS;
#ifdef CONFIG_SPI_BFIN_LOCK
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
struct chip_data *chip = spi_get_ctldata(spi);
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
- if (drv_data->locked) {
- spin_unlock_irqrestore(&drv_data->lock, flags);
- return -ENOLCK;
- }
- drv_data->locked = spi->chip_select ? spi->chip_select : chip->cs_gpio;
+ if (!drv_data->locked) {
+ drv_data->locked = spi->chip_select ?
+ spi->chip_select : chip->cs_gpio;
+ ret = 0;
+ } else
+ ret = -ENOLCK;
spin_unlock_irqrestore(&drv_data->lock, flags);
#endif
- return 0;
+ return ret;
}
static int bfin_spi_unlock_bus(struct spi_device *spi)
{
+ int ret = -ENOSYS;
#ifdef CONFIG_SPI_BFIN_LOCK
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct chip_data *chip = spi_get_ctldata(spi);
unsigned long flags;
+ int cs = spi->chip_select ? spi->chip_select : chip->cs_gpio;
spin_lock_irqsave(&drv_data->lock, flags);
- drv_data->locked = 0;
+ if (cs == drv_data->locked) {
+ drv_data->locked = 0;
+ ret = 0;
+ } else
+ ret = -ENOLCK;
spin_unlock_irqrestore(&drv_data->lock, flags);
#endif
- return 0;
+ return ret;
}
/*
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits