Skip to content

Commit

Permalink
ARM: Add fixed PCI i/o mapping
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Rob Herring committed Jul 25, 2012
1 parent 701eb26 commit c279443
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 11 deletions.
3 changes: 3 additions & 0 deletions Documentation/arm/memory.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions arch/arm/include/asm/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions arch/arm/include/asm/mach/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
Expand All @@ -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
10 changes: 10 additions & 0 deletions arch/arm/include/asm/mach/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#ifndef __ASM_MACH_PCI_H
#define __ASM_MACH_PCI_H


struct pci_sys_data;
struct pci_ops;
struct pci_bus;
Expand Down Expand Up @@ -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
*/
Expand Down
13 changes: 13 additions & 0 deletions arch/arm/kernel/bios32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
14 changes: 14 additions & 0 deletions arch/arm/mm/ioremap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
54 changes: 43 additions & 11 deletions arch/arm/mm/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/pci.h>

#include "mm.h"

Expand Down Expand Up @@ -216,7 +217,7 @@ static struct mem_type mem_types[] = {
.prot_l1 = PMD_TYPE_TABLE,
.prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB,
.domain = DOMAIN_IO,
},
},
[MT_DEVICE_WC] = { /* ioremap_wc */
.prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC,
.prot_l1 = PMD_TYPE_TABLE,
Expand Down Expand Up @@ -783,14 +784,27 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
create_mapping(md);
vm->addr = (void *)(md->virtual & PAGE_MASK);
vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
vm->phys_addr = __pfn_to_phys(md->pfn);
vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
vm->phys_addr = __pfn_to_phys(md->pfn);
vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
vm->flags |= VM_ARM_MTYPE(md->type);
vm->caller = iotable_init;
vm_area_add_early(vm++);
}
}

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

/*
Expand All @@ -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)
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit c279443

Please sign in to comment.