]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/host/mmc_spi.c
ipmi: don't grab locks in run-to-completion mode
[linux-2.6-omap-h63xx.git] / drivers / mmc / host / mmc_spi.c
index 7ae18eaed6c5d869d3e7d89bffd484bbe9798147..365024b83d3da9df9b6e4f7a9d4cf6d216ba523d 100644 (file)
@@ -176,8 +176,6 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
                                DMA_FROM_DEVICE);
 
        status = spi_sync(host->spi, &host->readback);
-       if (status == 0)
-               status = host->readback.status;
 
        if (host->dma_dev)
                dma_sync_single_for_cpu(host->dma_dev,
@@ -480,8 +478,6 @@ mmc_spi_command_send(struct mmc_spi_host *host,
                                DMA_BIDIRECTIONAL);
        }
        status = spi_sync(host->spi, &host->m);
-       if (status == 0)
-               status = host->m.status;
 
        if (host->dma_dev)
                dma_sync_single_for_cpu(host->dma_dev,
@@ -624,8 +620,6 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
                                DMA_BIDIRECTIONAL);
 
        status = spi_sync(spi, &host->m);
-       if (status == 0)
-               status = host->m.status;
 
        if (status != 0) {
                dev_dbg(&spi->dev, "write error (%d)\n", status);
@@ -726,8 +720,6 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
                }
 
                status = spi_sync(spi, &host->m);
-               if (status == 0)
-                       status = host->m.status;
 
                if (host->dma_dev) {
                        dma_sync_single_for_cpu(host->dma_dev,
@@ -813,7 +805,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                                        && dir == DMA_FROM_DEVICE)
                                dir = DMA_BIDIRECTIONAL;
 
-                       dma_addr = dma_map_page(dma_dev, sg->page, 0,
+                       dma_addr = dma_map_page(dma_dev, sg_page(sg), 0,
                                                PAGE_SIZE, dir);
                        if (direction == DMA_TO_DEVICE)
                                t->tx_dma = dma_addr + sg->offset;
@@ -822,7 +814,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                }
 
                /* allow pio too; we don't allow highmem */
-               kmap_addr = kmap(sg->page);
+               kmap_addr = kmap(sg_page(sg));
                if (direction == DMA_TO_DEVICE)
                        t->tx_buf = kmap_addr + sg->offset;
                else
@@ -855,8 +847,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
 
                /* discard mappings */
                if (direction == DMA_FROM_DEVICE)
-                       flush_kernel_dcache_page(sg->page);
-               kunmap(sg->page);
+                       flush_kernel_dcache_page(sg_page(sg));
+               kunmap(sg_page(sg));
                if (dma_dev)
                        dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
 
@@ -905,8 +897,6 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                                        DMA_BIDIRECTIONAL);
 
                tmp = spi_sync(spi, &host->m);
-               if (tmp == 0)
-                       tmp = host->m.status;
 
                if (host->dma_dev)
                        dma_sync_single_for_cpu(host->dma_dev,
@@ -1165,6 +1155,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 +1195,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