mmc_spi: Fix mmc-over-spi regression
Patch 49dce689ad
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>
This commit is contained in:
parent
1fa8dd146f
commit
460cd0589d
1 changed files with 33 additions and 19 deletions
|
@ -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)
|
||||||
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue