Re: Creating 16 MB super-sections for MMIO

From: Mason
Date: Wed Dec 03 2014 - 04:52:47 EST

[Top-posting to address topicality]

Is LKML more appropriate a list to discuss MMU setup?
(I've been studying arch-specific code in arch/arm/mm)


On 02/12/2014 11:42, Mason wrote:

[Branched from "Code generation involving __raw_readl and __raw_writel" thread]

On 27/11/2014 14:12, Arnd Bergmann wrote:

On Thursday 27 November 2014 14:01:41 Mason wrote:

I'm asking because I have an idea in mind: on the bus, the first
16 MB contains only memory-mapped registers, so I've been thinking
I can map this region at init, and keep it for the lifetime of the
system. It would use only one entry in the TLB, since the CPU
supports 16 MB super-sections.

I could even lock that entry in the TLB so that these accesses
are guaranteed to never TLB-miss, right?

The map_io callback will set up a mapping like that, and when
a driver calls ioremap on the same physical address, you will
get the correct pointer using that TLB, you just don't communicate
the address through a pointer any more.

[NOTE: Initially, the focus of this message was on TLB lockdown,
but then it changed to creating super-sections]

According to the ARM architecture manual:

The architecture has a concept of an entry locked down in the TLB.
The method by which lockdown is achieved is IMPLEMENTATION DEFINED,
and an implementation might not support lockdown.

Does Linux support locking down an entry in the TLB?
Where are CPU-specific implementations stored in the source tree?
(I'm using a Cortex A9.)

I glanced at


but nothing jumped out at me.

arch/arm/mach-tegra/cortex-a9.S (an obsolete file?) did mention
lockdown (albeit in a comment only).

[some time passes]

After giving the issue more thought, I think trying to lock the TLB entry
might be a case of premature optimization. However, it seems worthwhile to
make sure that Linux correctly sets up the 16 MB mapping, using a single
TLB entry (instead of 16 section entries).

I traced create_mapping -> alloc_init_pud -> alloc_init_pmd -> __map_init_section

(I think I'm in the right place...)
However, I was expecting PMD_SECT_SUPER somewhere in there, yet I don't
see any, so I'm not confident about a super-section being created.

The only two relevant functions appear to be


The first is only called in this case:
* Catch 36-bit addresses
if (md->pfn >= 0x100000) {
create_36bit_mapping(md, type);

Since I want to map PA 0, I could lie and pretend it is PA 2^32,
pray for a wrap-around back to 0, and get the super-section mapping.
That sounds like an ugly hack...

The other function is only called in this case:
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
if (DOMAIN_IO == 0 &&
(((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
cpu_is_xsc3()) && pfn >= 0x100000 &&
!((paddr | size | addr) & ~SUPERSECTION_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
err = remap_area_supersections(addr, pfn, size, type);
} else if (!((paddr | size | addr) & ~PMD_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
err = remap_area_sections(addr, pfn, size, type);
} else

But we do define CONFIG_SMP (dual core CPU).
So no super-sections for me, IIUC?


To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at
Please read the FAQ at