mmc_spi: Fix mmc-over-spi regression
authorDavid Brownell <david-b@pacbell.net>
Sat, 27 Oct 2007 12:47:20 +0000 (14:47 +0200)
committerPierre Ossman <drzeus@drzeus.cx>
Sat, 27 Oct 2007 12:47:20 +0000 (14:47 +0200)
Patch 49dce689ad4ef0fd1f970ef762168e4bd46f69a3 changed the sysfs data
structures for SPI in a way which broke the MMC-over-SPI host driver.

This patch fixes that regression by changing the scheme used to keep
from knowingly trying to use a shared bus segment, and updates the
adjacent comments slightly to better explain the issue.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
drivers/mmc/host/mmc_spi.c

index 12c2d80..a646921 100644 (file)
@@ -1165,6 +1165,23 @@ mmc_spi_detect_irq(int irq, void *mmc)
        return IRQ_HANDLED;
 }
 
+struct count_children {
+       unsigned        n;
+       struct bus_type *bus;
+};
+
+static int maybe_count_child(struct device *dev, void *c)
+{
+       struct count_children *ccp = c;
+
+       if (dev->bus == ccp->bus) {
+               if (ccp->n)
+                       return -EBUSY;
+               ccp->n++;
+       }
+       return 0;
+}
+
 static int mmc_spi_probe(struct spi_device *spi)
 {
        void                    *ones;
@@ -1188,33 +1205,30 @@ static int mmc_spi_probe(struct spi_device *spi)
                return status;
        }
 
-       /* We can use the bus safely iff nobody else will interfere with
-        * us.  That is, either we have the experimental exclusive access
-        * primitives ... or else there's nobody to share it with.
+       /* We can use the bus safely iff 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.
+        *
+        * Until we have software primitives which guarantee non-interference,
+        * we'll aim for a hardware-level guarantee.
+        *
+        * REVISIT we can't guarantee another device won't be added later...
         */
        if (spi->master->num_chipselect > 1) {
-               struct device   *parent = spi->dev.parent;
+               struct count_children cc;
 
-               /* If there are multiple devices on this bus, we
-                * can't proceed.
-                */
-               spin_lock(&parent->klist_children.k_lock);
-               if (parent->klist_children.k_list.next
-                               != parent->klist_children.k_list.prev)
-                       status = -EMLINK;
-               else
-                       status = 0;
-               spin_unlock(&parent->klist_children.k_lock);
+               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.  It's uncommon though ... for now,
-                * work as if this is safe.
-                */
-               dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n");
+               dev_warn(&spi->dev, "ASSUMING SPI bus stays unshared!\n");
        }
 
        /* We need a supply of ones to transmit.  This is the only time