summaryrefslogtreecommitdiff
path: root/arch/arm/mm/mm-armv.c
diff options
context:
space:
mode:
authorDeepak Saxena <dsaxena@plexity.net>2005-10-28 15:19:12 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-10-28 15:19:12 +0100
commit0b7cd62ecdc1f09b7df4608a3fee644b1c27985b (patch)
tree3769b043ea6b15ffe7b74a1a5d42903e08b126bc /arch/arm/mm/mm-armv.c
parent9769c2468d423a1562dd59a5db250bd0a5533ec9 (diff)
downloadlwn-0b7cd62ecdc1f09b7df4608a3fee644b1c27985b.tar.gz
lwn-0b7cd62ecdc1f09b7df4608a3fee644b1c27985b.zip
[ARM] 3017/1: Add support for 36-bit addresses to create_mapping()
Patch from Deepak Saxena This patch adds support for 36-bit static mapped I/O. While there are no platforms in the tree ATM that use it, it has been tested tested on the IXP2350 NPU and I would like to get the support for that chipset upstream one piece at a time. There are also other Intel chipset ports in development that are waiting on this to go upstream. The patch replaces the print formats for physical addresses with %016llx which will create a bit extraneous output on 32-bit systems, but I think that is cleaner than having #ifdefs, specially since users will only see the output in error cases. Depends on 3016/1. Signed-off-by: Deepak Saxena <dsaxena@plexity.net> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm/mm-armv.c')
-rw-r--r--arch/arm/mm/mm-armv.c60
1 files changed, 47 insertions, 13 deletions
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 64db10e806b3..61bc2fa0511e 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -478,20 +478,20 @@ void __init create_mapping(struct map_desc *md)
unsigned long virt, length;
int prot_sect, prot_l1, domain;
pgprot_t prot_pte;
- long off;
+ unsigned long off = (u32)__pfn_to_phys(md->pfn);
if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
printk(KERN_WARNING "BUG: not creating mapping for "
- "0x%08lx at 0x%08lx in user region\n",
- __pfn_to_phys(md->pfn), md->virtual);
+ "0x%016llx at 0x%08lx in user region\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
return;
}
if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
- printk(KERN_WARNING "BUG: mapping for 0x%08lx at 0x%08lx "
+ printk(KERN_WARNING "BUG: mapping for 0x%016llx at 0x%08lx "
"overlaps vmalloc space\n",
- __pfn_to_phys(md->pfn), md->virtual);
+ __pfn_to_phys((u64)md->pfn), md->virtual);
}
domain = mem_types[md->type].domain;
@@ -499,8 +499,33 @@ void __init create_mapping(struct map_desc *md)
prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
+ /*
+ * Catch 36-bit addresses
+ */
+ if(md->pfn >= 0x100000) {
+ if(domain) {
+ printk(KERN_ERR "MM: invalid domain in supersection "
+ "mapping for 0x%016llx at 0x%08lx\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+ if((md->virtual | md->length | __pfn_to_phys(md->pfn))
+ & ~SUPERSECTION_MASK) {
+ printk(KERN_ERR "MM: cannot create mapping for "
+ "0x%016llx at 0x%08lx invalid alignment\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+
+ /*
+ * Shift bits [35:32] of address into bits [23:20] of PMD
+ * (See ARMv6 spec).
+ */
+ off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
+ }
+
virt = md->virtual;
- off = __pfn_to_phys(md->pfn) - virt;
+ off -= virt;
length = md->length;
if (mem_types[md->type].prot_l1 == 0 &&
@@ -525,13 +550,22 @@ void __init create_mapping(struct map_desc *md)
* of the actual domain assignments in use.
*/
if (cpu_architecture() >= CPU_ARCH_ARMv6 && domain == 0) {
- /* Align to supersection boundary */
- while ((virt & ~SUPERSECTION_MASK || (virt + off) &
- ~SUPERSECTION_MASK) && length >= (PGDIR_SIZE / 2)) {
- alloc_init_section(virt, virt + off, prot_sect);
-
- virt += (PGDIR_SIZE / 2);
- length -= (PGDIR_SIZE / 2);
+ /*
+ * Align to supersection boundary if !high pages.
+ * High pages have already been checked for proper
+ * alignment above and they will fail the SUPSERSECTION_MASK
+ * check because of the way the address is encoded into
+ * offset.
+ */
+ if (md->pfn <= 0x100000) {
+ while ((virt & ~SUPERSECTION_MASK ||
+ (virt + off) & ~SUPERSECTION_MASK) &&
+ length >= (PGDIR_SIZE / 2)) {
+ alloc_init_section(virt, virt + off, prot_sect);
+
+ virt += (PGDIR_SIZE / 2);
+ length -= (PGDIR_SIZE / 2);
+ }
}
while (length >= SUPERSECTION_SIZE) {