Commit 460cd058 authored by David Brownell's avatar David Brownell Committed by Pierre Ossman

mmc_spi: Fix mmc-over-spi regression

Patch 49dce689 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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 1fa8dd14
...@@ -1165,6 +1165,23 @@ mmc_spi_detect_irq(int irq, void *mmc) ...@@ -1165,6 +1165,23 @@ mmc_spi_detect_irq(int irq, void *mmc)
return IRQ_HANDLED; 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) static int mmc_spi_probe(struct spi_device *spi)
{ {
void *ones; void *ones;
...@@ -1188,33 +1205,30 @@ static int mmc_spi_probe(struct spi_device *spi) ...@@ -1188,33 +1205,30 @@ static int mmc_spi_probe(struct spi_device *spi)
return status; return status;
} }
/* We can use the bus safely iff nobody else will interfere with /* We can use the bus safely iff nobody else will interfere with us.
* us. That is, either we have the experimental exclusive access * Most commands consist of one SPI message to issue a command, then
* primitives ... or else there's nobody to share it with. * 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) { 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 cc.n = 0;
* can't proceed. cc.bus = spi->dev.bus;
*/ status = device_for_each_child(spi->dev.parent, &cc,
spin_lock(&parent->klist_children.k_lock); maybe_count_child);
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);
if (status < 0) { if (status < 0) {
dev_err(&spi->dev, "can't share SPI bus\n"); dev_err(&spi->dev, "can't share SPI bus\n");
return status; return status;
} }
/* REVISIT we can't guarantee another device won't dev_warn(&spi->dev, "ASSUMING SPI bus stays unshared!\n");
* be added later. It's uncommon though ... for now,
* work as if this is safe.
*/
dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n");
} }
/* We need a supply of ones to transmit. This is the only time /* We need a supply of ones to transmit. This is the only time
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment