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

Reply via email to