From: Thomas Koeller on
Hi,

I am writing a driver that loads a firmware blob into its device. The driver
calls request_firmware() and gets a struct firmware * that contains a
data buffer pointer in its 'data' member. The buffer is then passed to a
SPI driver to send it to the device.

The SPI driver uses DMA and, in preparation for that, eventually calls
dma_cache_maint() (contained in arch/arm/mm/dma-mapping.c). At this
point, the whole thing goes bad because there is a check:

BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(start + size - 1));

and the address obtained via request_firmware() fails this check.

The request_firmware() function creates the data buffer by allocating a
number of single pages in a loop, places them in an array, and finally
creates a kernel mapping by calling vmap(). The vmap() result is the
buffer address passed to the DMA.

I do not understand the purpose of the failing check. The virt_addr_valid()
macro checks whether its argument is below high_memory. But why would the
virtual address of a DMA data buffer matter at all? After all, the pages
are resident, so I cannot see any problem here. Can anybody explain?

Thomas
From: Russell King - ARM Linux on
On Thu, Mar 04, 2010 at 10:11:08PM +0100, Thomas Koeller wrote:
> I do not understand the purpose of the failing check. The virt_addr_valid()
> macro checks whether its argument is below high_memory. But why would the
> virtual address of a DMA data buffer matter at all? After all, the pages
> are resident, so I cannot see any problem here. Can anybody explain?

Cache maintainence is done using virtual addresses for L1, and
physical addresses for L2. There's the need for virtual addresses
to be translatable to physical addresses, which is only true for
the kernel direct mapped region (pages between PAGE_OFFSET and
high_memory).
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Thomas Koeller on
Am Donnerstag, 4. M�rz 2010 22:36:34 schrieb Russell King - ARM Linux:
> Cache maintainence is done using virtual addresses for L1, and
> physical addresses for L2. There's the need for virtual addresses
> to be translatable to physical addresses, which is only true for
> the kernel direct mapped region (pages between PAGE_OFFSET and
> high_memory).

Isn't the mapping created by vmap() sufficient for the virt/phys
translation? In which way is this case different from a buffer
passed in from user space, where the constituent pages are not
in the directly mapped kernel region either?

tk

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Russell King - ARM Linux on
On Sat, Mar 06, 2010 at 02:07:12PM +0100, Thomas Koeller wrote:
> Am Donnerstag, 4. M�rz 2010 22:36:34 schrieb Russell King - ARM Linux:
> > Cache maintainence is done using virtual addresses for L1, and
> > physical addresses for L2. There's the need for virtual addresses
> > to be translatable to physical addresses, which is only true for
> > the kernel direct mapped region (pages between PAGE_OFFSET and
> > high_memory).
>
> Isn't the mapping created by vmap() sufficient for the virt/phys
> translation? In which way is this case different from a buffer
> passed in from user space, where the constituent pages are not
> in the directly mapped kernel region either?

No different.

The requirement is that dma_map_single() is passed a virtual address
in the kernel direct-mapped memory region, which is translatable using
virt_to_phys() and friends.

Anything which requires a page table lookup to obtain the physical
address is just not acceptable - that requires taking locks and other
messy things, plus is grossly inefficient.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Lin Mac on
2010/3/7 Russell King - ARM Linux <linux(a)arm.linux.org.uk>:
> On Sat, Mar 06, 2010 at 02:07:12PM +0100, Thomas Koeller wrote:
>> Am Donnerstag, 4. M�rz 2010 22:36:34 schrieb Russell King - ARM Linux:
>> > Cache maintainence is done using virtual addresses for L1, and
>> > physical addresses for L2. �There's the need for virtual addresses
>> > to be translatable to physical addresses, which is only true for
>> > the kernel direct mapped region (pages between PAGE_OFFSET and
>> > high_memory).
>>
>> Isn't the mapping created by vmap() sufficient for the virt/phys
>> translation? In which way is this case different from a buffer
>> passed in from user space, where the constituent pages are not
>> in the directly mapped kernel region either?
>
> No different.
>
> The requirement is that dma_map_single() is passed a virtual address
> in the kernel direct-mapped memory region, which is translatable using
> virt_to_phys() and friends.
I had encounter a similiar problem and I simply allocated a new
buffer, copy the data, then DMA. It seems slow and stupid.

I'm wondering wether could I translate the vmap virt to phys(don't
know how to yet), then use phys_to_virt to get the virt in
direct-mapped memory region?

Is there other possible ways?

> Anything which requires a page table lookup to obtain the physical
> address is just not acceptable - that requires taking locks and other
> messy things, plus is grossly inefficient.

Best Regards,
Mac Lin
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/