[PATCH v4 13/13] mmc: tmio: add barriers to IO operations
Guennadi Liakhovetski
g.liakhovetski at gmx.de
Tue Feb 19 04:20:26 EST 2013
On Mon, 18 Feb 2013, Arnd Bergmann wrote:
> On Monday 18 February 2013, Guennadi Liakhovetski wrote:
> > > Also, should the barrier not be after the MMIO read, rather than before it?
> > > Typically the barrier should ensure that any read from memory after an
> > > MMIO read reflects the memory contents after any DMA is complete that
> > > the MMIO read has already claimed to be done.
> >
> > Errors, that I've been observing were happening with no DMA, in pure PIO
> > mode.
> >
> > Unfortunately, I don't have a good explanation, why the barriers have to
> > be there, where I put them. At some point during my testing, I had
> > printk()s in the code and SDIO worked. Then the classical - remove
> > printk()s - stops working. Delays didn't halp, but barriers did. The
> > motivation to put a write barrier before a (repeated) read was to wait for
> > completion of any write operations before starting a read. And indeed,
> > normal write operations, like writew() / iowrite16() have a write barrier
> > before the write. So, isn't it possible, that the last write hasn't
> > completed yet, while we begin with reading? But reads / writes should,
> > probably, anyway be serialised on the bus...
>
> What kind of bus is this?
Sorry, I'm not sure how best to describe it, and I don't have sufficient
information myself. In any case on a block-diagram of sh73a0 SDHI devices
aren't directly connected to a common super-highway bus, instead they are
on a bus-splitter. One more thing I forgot to mention - this error has
been observed on SMP.
> All buses I have looked at do serialize reads
> and writes to the same address at the minimum, and all sane buses
> serialize them when they happen to the same device, but it's harder
> to do when you need to serialize e.g. a read with a previous write
> to another device or another bus connected to the same device.
>
> Let me try to say what I understand from reading the code: These
> accessors are only used on one function, and there is no DMA
> involved here. The function does (simplified):
>
> void tmio_mmc_pio_irq(struct page *, void __iomem *io, size_t count, bool read)
> {
> void *virt;
>
> /* called from interrupt handler, but let's disable interrupts some more ;) */
> local_irq_disable();
>
> /* if highmem, map the page */
> virt = kmap_atomic(page);
> if (read) {
> wmb();
> readsw(io, virt, count);
> } else {
> writesw(io, virt, count);
> rmb();
> }
>
> kunmap_atomic(virt);
> }
>
> I don't think there is any other I/O involved, so the barriers are probably
> needed to synchronize with whoever is accessing the page on the other
> side of the kmap/kunmap. Did the bug happen on highmem?
No, don't think highmem was involved.
> The barriers here should probably be outside of the I/O accessors
> and in the tmio_mmc_pio_irq() function, but I still can't explain
> why they are needed here.
>
> > It's also possible, that these errors are related to runtime
> > power-management, which would involve IO to other SoC peripherals. But
> > they all should also contain barriers, so, this doesn't explain it
> > immediately either.
>
> Maybe the runtime-pm code uses __raw_writel or writel_relaxed where it
> should be using writel?
I checked clock code under drivers/sh/clk, I don't see any relevant
__raw_* operations there. One I do see, however, GIC code does use
*_relaxed() accessors, but under raw spinlocks... Do those provide
sufficient barriers?
Thanks
Guennadi
> Or maybe there some effect with disabling the caches and not flushing
> them properly in advance here?
>
> In any case, I would expect a much more specific changeset text for a
> patch like this.
>
> Arnd
>
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
More information about the devicetree-discuss
mailing list