mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ARM: Add fixed PCI i/o mapping
This adds a fixed virtual mapping for PCI i/o addresses. The mapping is located at the last 2MB of vmalloc region (0xfee00000-0xff000000). 2MB is used to align with PMD size, but IO_SPACE_LIMIT is 1MB. The space is reserved after .map_io and can be mapped at any time later with pci_ioremap_io. Platforms which need early i/o mapping (e.g. for vga console) can call pci_map_io_early in their .map_io function. This has changed completely from the 1st implementation which only supported creating the static mapping at .map_io. Signed-off-by: Rob Herring <rob.herring@calxeda.com> Cc: Russell King <linux@arm.linux.org.uk> Acked-by: Nicolas Pitre <nico@linaro.org>
This commit is contained in:
		
							parent
							
								
									701eb2647d
								
							
						
					
					
						commit
						c279443709
					
				
					 7 changed files with 99 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -51,6 +51,9 @@ ffc00000	ffefffff	DMA memory mapping region.  Memory returned
 | 
			
		|||
ff000000	ffbfffff	Reserved for future expansion of DMA
 | 
			
		||||
				mapping region.
 | 
			
		||||
 | 
			
		||||
fee00000	feffffff	Mapping of PCI I/O space. This is a static
 | 
			
		||||
				mapping within the vmalloc space.
 | 
			
		||||
 | 
			
		||||
VMALLOC_START	VMALLOC_END-1	vmalloc() / ioremap() space.
 | 
			
		||||
				Memory returned by vmalloc/ioremap will
 | 
			
		||||
				be dynamically placed in this region.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,11 +113,19 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
 | 
			
		|||
#define __iowmb()		do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* PCI fixed i/o mapping */
 | 
			
		||||
#define PCI_IO_VIRT_BASE	0xfee00000
 | 
			
		||||
 | 
			
		||||
extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Now, pick up the machine-defined IO definitions
 | 
			
		||||
 */
 | 
			
		||||
#ifdef CONFIG_NEED_MACH_IO_H
 | 
			
		||||
#include <mach/io.h>
 | 
			
		||||
#elif defined(CONFIG_PCI)
 | 
			
		||||
#define IO_SPACE_LIMIT	((resource_size_t)0xfffff)
 | 
			
		||||
#define __io(a)		__typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
 | 
			
		||||
#else
 | 
			
		||||
#define __io(a)		__typesafe_io((a) & IO_SPACE_LIMIT)
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,9 @@
 | 
			
		|||
 *
 | 
			
		||||
 *  Page table mapping constructs and function prototypes
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __ASM_MACH_MAP_H
 | 
			
		||||
#define __ASM_MACH_MAP_H
 | 
			
		||||
 | 
			
		||||
#include <asm/io.h>
 | 
			
		||||
 | 
			
		||||
struct map_desc {
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +37,8 @@ struct map_desc {
 | 
			
		|||
 | 
			
		||||
#ifdef CONFIG_MMU
 | 
			
		||||
extern void iotable_init(struct map_desc *, int);
 | 
			
		||||
extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
 | 
			
		||||
				  void *caller);
 | 
			
		||||
 | 
			
		||||
struct mem_type;
 | 
			
		||||
extern const struct mem_type *get_mem_type(unsigned int type);
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +49,7 @@ extern int ioremap_page(unsigned long virt, unsigned long phys,
 | 
			
		|||
			const struct mem_type *mtype);
 | 
			
		||||
#else
 | 
			
		||||
#define iotable_init(map,num)	do { } while (0)
 | 
			
		||||
#define vm_reserve_area_early(a,s,c)	do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
#ifndef __ASM_MACH_PCI_H
 | 
			
		||||
#define __ASM_MACH_PCI_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct pci_sys_data;
 | 
			
		||||
struct pci_ops;
 | 
			
		||||
struct pci_bus;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +55,15 @@ struct pci_sys_data {
 | 
			
		|||
 */
 | 
			
		||||
void pci_common_init(struct hw_pci *);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Setup early fixed I/O mapping.
 | 
			
		||||
 */
 | 
			
		||||
#if defined(CONFIG_PCI)
 | 
			
		||||
extern void pci_map_io_early(unsigned long pfn);
 | 
			
		||||
#else
 | 
			
		||||
static inline void pci_map_io_early(unsigned long pfn) {}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PCI controllers
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@
 | 
			
		|||
#include <linux/io.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach-types.h>
 | 
			
		||||
#include <asm/mach/map.h>
 | 
			
		||||
#include <asm/mach/pci.h>
 | 
			
		||||
 | 
			
		||||
static int debug_pci;
 | 
			
		||||
| 
						 | 
				
			
			@ -627,3 +628,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 | 
			
		|||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init pci_map_io_early(unsigned long pfn)
 | 
			
		||||
{
 | 
			
		||||
	struct map_desc pci_io_desc = {
 | 
			
		||||
		.virtual	= PCI_IO_VIRT_BASE,
 | 
			
		||||
		.type		= MT_DEVICE,
 | 
			
		||||
		.length		= SZ_64K,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	pci_io_desc.pfn = pfn;
 | 
			
		||||
	iotable_init(&pci_io_desc, 1);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@
 | 
			
		|||
#include <asm/system_info.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/mach/map.h>
 | 
			
		||||
#include <asm/mach/pci.h>
 | 
			
		||||
#include "mm.h"
 | 
			
		||||
 | 
			
		||||
int ioremap_page(unsigned long virt, unsigned long phys,
 | 
			
		||||
| 
						 | 
				
			
			@ -383,3 +384,16 @@ void __arm_iounmap(volatile void __iomem *io_addr)
 | 
			
		|||
	arch_iounmap(io_addr);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__arm_iounmap);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PCI
 | 
			
		||||
int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
 | 
			
		||||
{
 | 
			
		||||
	BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT);
 | 
			
		||||
 | 
			
		||||
	return ioremap_page_range(PCI_IO_VIRT_BASE + offset,
 | 
			
		||||
				  PCI_IO_VIRT_BASE + offset + SZ_64K,
 | 
			
		||||
				  phys_addr,
 | 
			
		||||
				  __pgprot(get_mem_type(MT_DEVICE)->prot_pte));
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(pci_ioremap_io);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@
 | 
			
		|||
 | 
			
		||||
#include <asm/mach/arch.h>
 | 
			
		||||
#include <asm/mach/map.h>
 | 
			
		||||
#include <asm/mach/pci.h>
 | 
			
		||||
 | 
			
		||||
#include "mm.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -791,6 +792,19 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __init vm_reserve_area_early(unsigned long addr, unsigned long size,
 | 
			
		||||
				  void *caller)
 | 
			
		||||
{
 | 
			
		||||
	struct vm_struct *vm;
 | 
			
		||||
 | 
			
		||||
	vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
 | 
			
		||||
	vm->addr = (void *)addr;
 | 
			
		||||
	vm->size = size;
 | 
			
		||||
	vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
 | 
			
		||||
	vm->caller = caller;
 | 
			
		||||
	vm_area_add_early(vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_ARM_LPAE
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -808,14 +822,7 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
 | 
			
		|||
 | 
			
		||||
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);
 | 
			
		||||
	vm_reserve_area_early(addr, SECTION_SIZE, pmd_empty_section_gap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __init fill_pmd_gaps(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -864,6 +871,28 @@ static void __init fill_pmd_gaps(void)
 | 
			
		|||
#define fill_pmd_gaps() do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_PCI) && !defined(CONFIG_NEED_MACH_IO_H)
 | 
			
		||||
static void __init pci_reserve_io(void)
 | 
			
		||||
{
 | 
			
		||||
	struct vm_struct *vm;
 | 
			
		||||
	unsigned long addr;
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
		addr &= ~(SZ_2M - 1);
 | 
			
		||||
		if (addr == PCI_IO_VIRT_BASE)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	vm_reserve_area_early(PCI_IO_VIRT_BASE, SZ_2M, pci_reserve_io);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define pci_reserve_io() do { } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void * __initdata vmalloc_min =
 | 
			
		||||
	(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1147,6 +1176,9 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
 | 
			
		|||
		mdesc->map_io();
 | 
			
		||||
	fill_pmd_gaps();
 | 
			
		||||
 | 
			
		||||
	/* Reserve fixed i/o space in VMALLOC region */
 | 
			
		||||
	pci_reserve_io();
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Finally flush the caches and tlb to ensure that we're in a
 | 
			
		||||
	 * consistent state wrt the writebuffer.  This also ensures that
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue