Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b7cd62e authored by Deepak Saxena's avatar Deepak Saxena Committed by Russell King
Browse files

[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: default avatarDeepak Saxena <dsaxena@plexity.net>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 9769c246
Loading
Loading
Loading
Loading
+47 −13
Original line number Diff line number Diff line
@@ -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,14 +550,23 @@ 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)) {
		/*
		 * 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) {
			alloc_init_supersection(virt, virt + off, prot_sect);