Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 311544
b: refs/heads/master
c: 19b52ab
h: refs/heads/master
v: v3
  • Loading branch information
Nicolas Pitre authored and Russell King committed Jul 1, 2012
1 parent 12ccbd6 commit fc4a05d
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9973290ce20ace7cac8ad06f753468c0b826fd0f
refs/heads/master: 19b52abe3c5d759661500a1dc810924369b2ad46
74 changes: 74 additions & 0 deletions trunk/arch/arm/mm/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,79 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
}
}

#ifndef CONFIG_ARM_LPAE

/*
* The Linux PMD is made of two consecutive section entries covering 2MB
* (see definition in include/asm/pgtable-2level.h). However a call to
* create_mapping() may optimize static mappings by using individual
* 1MB section mappings. This leaves the actual PMD potentially half
* initialized if the top or bottom section entry isn't used, leaving it
* open to problems if a subsequent ioremap() or vmalloc() tries to use
* the virtual space left free by that unused section entry.
*
* Let's avoid the issue by inserting dummy vm entries covering the unused
* PMD halves once the static mappings are in place.
*/

static void __init pmd_empty_section_gap(unsigned long addr)
{
struct vm_struct *vm;

vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
vm->addr = (void *)addr;
vm->size = SECTION_SIZE;
vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
vm->caller = pmd_empty_section_gap;
vm_area_add_early(vm);
}

static void __init fill_pmd_gaps(void)
{
struct vm_struct *vm;
unsigned long addr, next = 0;
pmd_t *pmd;

/* we're still single threaded hence no lock needed here */
for (vm = vmlist; vm; vm = vm->next) {
if (!(vm->flags & VM_ARM_STATIC_MAPPING))
continue;
addr = (unsigned long)vm->addr;
if (addr < next)
continue;

/*
* Check if this vm starts on an odd section boundary.
* If so and the first section entry for this PMD is free
* then we block the corresponding virtual address.
*/
if ((addr & ~PMD_MASK) == SECTION_SIZE) {
pmd = pmd_off_k(addr);
if (pmd_none(*pmd))
pmd_empty_section_gap(addr & PMD_MASK);
}

/*
* Then check if this vm ends on an odd section boundary.
* If so and the second section entry for this PMD is empty
* then we block the corresponding virtual address.
*/
addr += vm->size;
if ((addr & ~PMD_MASK) == SECTION_SIZE) {
pmd = pmd_off_k(addr) + 1;
if (pmd_none(*pmd))
pmd_empty_section_gap(addr);
}

/* no need to look at any vm entry until we hit the next PMD */
next = (addr + PMD_SIZE - 1) & PMD_MASK;
}
}

#else
#define fill_pmd_gaps() do { } while (0)
#endif

static void * __initdata vmalloc_min =
(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);

Expand Down Expand Up @@ -1072,6 +1145,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
*/
if (mdesc->map_io)
mdesc->map_io();
fill_pmd_gaps();

/*
* Finally flush the caches and tlb to ensure that we're in a
Expand Down

0 comments on commit fc4a05d

Please sign in to comment.