Skip to content

Commit

Permalink
[ARM] 3705/1: add supersection support to ioremap()
Browse files Browse the repository at this point in the history
Patch from Lennert Buytenhek

Analogous to the previous patch that allows ioremap() to use section
mappings, this patch allows ioremap() to use supersection mappings.
Original patch by Deepak Saxena.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Lennert Buytenhek authored and Russell King committed Jul 1, 2006
1 parent ae95bfb commit a069c89
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 5 deletions.
66 changes: 63 additions & 3 deletions arch/arm/mm/ioremap.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
#include <asm/sizes.h>

/*
* Used by ioremap() and iounmap() code to mark section-mapped I/O regions
* in vm_struct->flags field.
* Used by ioremap() and iounmap() code to mark (super)section-mapped
* I/O regions in vm_struct->flags field.
*/
#define VM_ARM_SECTION_MAPPING 0x80000000

Expand Down Expand Up @@ -233,6 +233,54 @@ remap_area_sections(unsigned long virt, unsigned long pfn,

return 0;
}

static int
remap_area_supersections(unsigned long virt, unsigned long pfn,
unsigned long size, unsigned long flags)
{
unsigned long prot, addr = virt, end = virt + size;
pgd_t *pgd;

/*
* Remove and free any PTE-based mapping, and
* sync the current kernel mapping.
*/
unmap_area_sections(virt, size);

prot = PMD_TYPE_SECT | PMD_SECT_SUPER | PMD_SECT_AP_WRITE |
PMD_DOMAIN(DOMAIN_IO) |
(flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE));

/*
* ARMv6 and above need XN set to prevent speculative prefetches
* hitting IO.
*/
if (cpu_architecture() >= CPU_ARCH_ARMv6)
prot |= PMD_SECT_XN;

pgd = pgd_offset_k(virt);
do {
unsigned long super_pmd_val, i;

super_pmd_val = __pfn_to_phys(pfn) | prot;
super_pmd_val |= ((pfn >> (32 - PAGE_SHIFT)) & 0xf) << 20;

for (i = 0; i < 8; i++) {
pmd_t *pmd = pmd_offset(pgd, addr);

pmd[0] = __pmd(super_pmd_val);
pmd[1] = __pmd(super_pmd_val);
flush_pmd_entry(pmd);

addr += PGDIR_SIZE;
pgd++;
}

pfn += SUPERSECTION_SIZE >> PAGE_SHIFT;
} while (addr < end);

return 0;
}
#endif


Expand All @@ -255,14 +303,26 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
int err;
unsigned long addr;
struct vm_struct * area;
unsigned int cr = get_cr();

/*
* High mappings must be supersection aligned
*/
if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
return NULL;

area = get_vm_area(size, VM_IOREMAP);
if (!area)
return NULL;
addr = (unsigned long)area->addr;

#ifndef CONFIG_SMP
if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
if ((((cpu_architecture() >= CPU_ARCH_ARMv6) && (cr & CR_XP)) ||
cpu_is_xsc3()) &&
!((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
err = remap_area_supersections(addr, pfn, size, flags);
} else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
err = remap_area_sections(addr, pfn, size, flags);
} else
Expand Down
4 changes: 2 additions & 2 deletions include/asm-arm/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@
#define XIP_VIRT_ADDR(physaddr) (MODULE_START + ((physaddr) & 0x000fffff))

/*
* Allow 2MB-aligned ioremap pages
* Allow 16MB-aligned ioremap pages
*/
#define IOREMAP_MAX_ORDER 21
#define IOREMAP_MAX_ORDER 24

#else /* CONFIG_MMU */

Expand Down

0 comments on commit a069c89

Please sign in to comment.