diff options
Diffstat (limited to 'ANDROID_3.4.5/arch/ia64/mm')
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/Makefile | 11 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/contig.c | 356 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/discontig.c | 825 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/extable.c | 115 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/fault.c | 281 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/hugetlbpage.c | 207 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/init.c | 716 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/ioremap.c | 121 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/numa.c | 92 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/ia64/mm/tlb.c | 562 |
10 files changed, 0 insertions, 3286 deletions
diff --git a/ANDROID_3.4.5/arch/ia64/mm/Makefile b/ANDROID_3.4.5/arch/ia64/mm/Makefile deleted file mode 100644 index bb0a01a8..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the ia64-specific parts of the memory manager. -# - -obj-y := init.o fault.o tlb.o extable.o ioremap.o - -obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_NUMA) += numa.o -obj-$(CONFIG_DISCONTIGMEM) += discontig.o -obj-$(CONFIG_SPARSEMEM) += discontig.o -obj-$(CONFIG_FLATMEM) += contig.o diff --git a/ANDROID_3.4.5/arch/ia64/mm/contig.c b/ANDROID_3.4.5/arch/ia64/mm/contig.c deleted file mode 100644 index 1516d1dc..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/contig.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1998-2003 Hewlett-Packard Co - * David Mosberger-Tang <davidm@hpl.hp.com> - * Stephane Eranian <eranian@hpl.hp.com> - * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com> - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> - * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved. - * - * Routines used by ia64 machines with contiguous (or virtually contiguous) - * memory. - */ -#include <linux/bootmem.h> -#include <linux/efi.h> -#include <linux/memblock.h> -#include <linux/mm.h> -#include <linux/nmi.h> -#include <linux/swap.h> - -#include <asm/meminit.h> -#include <asm/pgalloc.h> -#include <asm/pgtable.h> -#include <asm/sections.h> -#include <asm/mca.h> - -#ifdef CONFIG_VIRTUAL_MEM_MAP -static unsigned long max_gap; -#endif - -/** - * show_mem - give short summary of memory stats - * - * Shows a simple page count of reserved and used pages in the system. - * For discontig machines, it does this on a per-pgdat basis. - */ -void show_mem(unsigned int filter) -{ - int i, total_reserved = 0; - int total_shared = 0, total_cached = 0; - unsigned long total_present = 0; - pg_data_t *pgdat; - - printk(KERN_INFO "Mem-info:\n"); - show_free_areas(filter); - printk(KERN_INFO "Node memory in pages:\n"); - for_each_online_pgdat(pgdat) { - unsigned long present; - unsigned long flags; - int shared = 0, cached = 0, reserved = 0; - int nid = pgdat->node_id; - - if (skip_free_areas_node(filter, nid)) - continue; - pgdat_resize_lock(pgdat, &flags); - present = pgdat->node_present_pages; - for(i = 0; i < pgdat->node_spanned_pages; i++) { - struct page *page; - if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) - touch_nmi_watchdog(); - if (pfn_valid(pgdat->node_start_pfn + i)) - page = pfn_to_page(pgdat->node_start_pfn + i); - else { -#ifdef CONFIG_VIRTUAL_MEM_MAP - if (max_gap < LARGE_GAP) - continue; -#endif - i = vmemmap_find_next_valid_pfn(nid, i) - 1; - continue; - } - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page)-1; - } - pgdat_resize_unlock(pgdat, &flags); - total_present += present; - total_reserved += reserved; - total_cached += cached; - total_shared += shared; - printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, " - "shrd: %10d, swpd: %10d\n", nid, - present, reserved, shared, cached); - } - printk(KERN_INFO "%ld pages of RAM\n", total_present); - printk(KERN_INFO "%d reserved pages\n", total_reserved); - printk(KERN_INFO "%d pages shared\n", total_shared); - printk(KERN_INFO "%d pages swap cached\n", total_cached); - printk(KERN_INFO "Total of %ld pages in page table cache\n", - quicklist_total_size()); - printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages()); -} - - -/* physical address where the bootmem map is located */ -unsigned long bootmap_start; - -/** - * find_bootmap_location - callback to find a memory area for the bootmap - * @start: start of region - * @end: end of region - * @arg: unused callback data - * - * Find a place to put the bootmap and return its starting address in - * bootmap_start. This address must be page-aligned. - */ -static int __init -find_bootmap_location (u64 start, u64 end, void *arg) -{ - u64 needed = *(unsigned long *)arg; - u64 range_start, range_end, free_start; - int i; - -#if IGNORE_PFN0 - if (start == PAGE_OFFSET) { - start += PAGE_SIZE; - if (start >= end) - return 0; - } -#endif - - free_start = PAGE_OFFSET; - - for (i = 0; i < num_rsvd_regions; i++) { - range_start = max(start, free_start); - range_end = min(end, rsvd_region[i].start & PAGE_MASK); - - free_start = PAGE_ALIGN(rsvd_region[i].end); - - if (range_end <= range_start) - continue; /* skip over empty range */ - - if (range_end - range_start >= needed) { - bootmap_start = __pa(range_start); - return -1; /* done */ - } - - /* nothing more available in this segment */ - if (range_end == end) - return 0; - } - return 0; -} - -#ifdef CONFIG_SMP -static void *cpu_data; -/** - * per_cpu_init - setup per-cpu variables - * - * Allocate and setup per-cpu data areas. - */ -void * __cpuinit -per_cpu_init (void) -{ - static bool first_time = true; - void *cpu0_data = __cpu0_per_cpu; - unsigned int cpu; - - if (!first_time) - goto skip; - first_time = false; - - /* - * get_free_pages() cannot be used before cpu_init() done. - * BSP allocates PERCPU_PAGE_SIZE bytes for all possible CPUs - * to avoid that AP calls get_zeroed_page(). - */ - for_each_possible_cpu(cpu) { - void *src = cpu == 0 ? cpu0_data : __phys_per_cpu_start; - - memcpy(cpu_data, src, __per_cpu_end - __per_cpu_start); - __per_cpu_offset[cpu] = (char *)cpu_data - __per_cpu_start; - per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; - - /* - * percpu area for cpu0 is moved from the __init area - * which is setup by head.S and used till this point. - * Update ar.k3. This move is ensures that percpu - * area for cpu0 is on the correct node and its - * virtual address isn't insanely far from other - * percpu areas which is important for congruent - * percpu allocator. - */ - if (cpu == 0) - ia64_set_kr(IA64_KR_PER_CPU_DATA, __pa(cpu_data) - - (unsigned long)__per_cpu_start); - - cpu_data += PERCPU_PAGE_SIZE; - } -skip: - return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; -} - -static inline void -alloc_per_cpu_data(void) -{ - cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * num_possible_cpus(), - PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); -} - -/** - * setup_per_cpu_areas - setup percpu areas - * - * Arch code has already allocated and initialized percpu areas. All - * this function has to do is to teach the determined layout to the - * dynamic percpu allocator, which happens to be more complex than - * creating whole new ones using helpers. - */ -void __init -setup_per_cpu_areas(void) -{ - struct pcpu_alloc_info *ai; - struct pcpu_group_info *gi; - unsigned int cpu; - ssize_t static_size, reserved_size, dyn_size; - int rc; - - ai = pcpu_alloc_alloc_info(1, num_possible_cpus()); - if (!ai) - panic("failed to allocate pcpu_alloc_info"); - gi = &ai->groups[0]; - - /* units are assigned consecutively to possible cpus */ - for_each_possible_cpu(cpu) - gi->cpu_map[gi->nr_units++] = cpu; - - /* set parameters */ - static_size = __per_cpu_end - __per_cpu_start; - reserved_size = PERCPU_MODULE_RESERVE; - dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size; - if (dyn_size < 0) - panic("percpu area overflow static=%zd reserved=%zd\n", - static_size, reserved_size); - - ai->static_size = static_size; - ai->reserved_size = reserved_size; - ai->dyn_size = dyn_size; - ai->unit_size = PERCPU_PAGE_SIZE; - ai->atom_size = PAGE_SIZE; - ai->alloc_size = PERCPU_PAGE_SIZE; - - rc = pcpu_setup_first_chunk(ai, __per_cpu_start + __per_cpu_offset[0]); - if (rc) - panic("failed to setup percpu area (err=%d)", rc); - - pcpu_free_alloc_info(ai); -} -#else -#define alloc_per_cpu_data() do { } while (0) -#endif /* CONFIG_SMP */ - -/** - * find_memory - setup memory map - * - * Walk the EFI memory map and find usable memory for the system, taking - * into account reserved areas. - */ -void __init -find_memory (void) -{ - unsigned long bootmap_size; - - reserve_memory(); - - /* first find highest page frame number */ - min_low_pfn = ~0UL; - max_low_pfn = 0; - efi_memmap_walk(find_max_min_low_pfn, NULL); - max_pfn = max_low_pfn; - /* how many bytes to cover all the pages */ - bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT; - - /* look for a location to hold the bootmap */ - bootmap_start = ~0UL; - efi_memmap_walk(find_bootmap_location, &bootmap_size); - if (bootmap_start == ~0UL) - panic("Cannot find %ld bytes for bootmap\n", bootmap_size); - - bootmap_size = init_bootmem_node(NODE_DATA(0), - (bootmap_start >> PAGE_SHIFT), 0, max_pfn); - - /* Free all available memory, then mark bootmem-map as being in use. */ - efi_memmap_walk(filter_rsvd_memory, free_bootmem); - reserve_bootmem(bootmap_start, bootmap_size, BOOTMEM_DEFAULT); - - find_initrd(); - - alloc_per_cpu_data(); -} - -static int count_pages(u64 start, u64 end, void *arg) -{ - unsigned long *count = arg; - - *count += (end - start) >> PAGE_SHIFT; - return 0; -} - -/* - * Set up the page tables. - */ - -void __init -paging_init (void) -{ - unsigned long max_dma; - unsigned long max_zone_pfns[MAX_NR_ZONES]; - - num_physpages = 0; - efi_memmap_walk(count_pages, &num_physpages); - - memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); -#ifdef CONFIG_ZONE_DMA - max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - max_zone_pfns[ZONE_DMA] = max_dma; -#endif - max_zone_pfns[ZONE_NORMAL] = max_low_pfn; - -#ifdef CONFIG_VIRTUAL_MEM_MAP - efi_memmap_walk(filter_memory, register_active_ranges); - efi_memmap_walk(find_largest_hole, (u64 *)&max_gap); - if (max_gap < LARGE_GAP) { - vmem_map = (struct page *) 0; - free_area_init_nodes(max_zone_pfns); - } else { - unsigned long map_size; - - /* allocate virtual_mem_map */ - - map_size = PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * - sizeof(struct page)); - VMALLOC_END -= map_size; - vmem_map = (struct page *) VMALLOC_END; - efi_memmap_walk(create_mem_map_page_table, NULL); - - /* - * alloc_node_mem_map makes an adjustment for mem_map - * which isn't compatible with vmem_map. - */ - NODE_DATA(0)->node_mem_map = vmem_map + - find_min_pfn_with_active_regions(); - free_area_init_nodes(max_zone_pfns); - - printk("Virtual mem_map starts at 0x%p\n", mem_map); - } -#else /* !CONFIG_VIRTUAL_MEM_MAP */ - memblock_add_node(0, PFN_PHYS(max_low_pfn), 0); - free_area_init_nodes(max_zone_pfns); -#endif /* !CONFIG_VIRTUAL_MEM_MAP */ - zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); -} diff --git a/ANDROID_3.4.5/arch/ia64/mm/discontig.c b/ANDROID_3.4.5/arch/ia64/mm/discontig.c deleted file mode 100644 index c641333c..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/discontig.c +++ /dev/null @@ -1,825 +0,0 @@ -/* - * Copyright (c) 2000, 2003 Silicon Graphics, Inc. All rights reserved. - * Copyright (c) 2001 Intel Corp. - * Copyright (c) 2001 Tony Luck <tony.luck@intel.com> - * Copyright (c) 2002 NEC Corp. - * Copyright (c) 2002 Kimio Suganuma <k-suganuma@da.jp.nec.com> - * Copyright (c) 2004 Silicon Graphics, Inc - * Russ Anderson <rja@sgi.com> - * Jesse Barnes <jbarnes@sgi.com> - * Jack Steiner <steiner@sgi.com> - */ - -/* - * Platform initialization for Discontig Memory - */ - -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/nmi.h> -#include <linux/swap.h> -#include <linux/bootmem.h> -#include <linux/acpi.h> -#include <linux/efi.h> -#include <linux/nodemask.h> -#include <linux/slab.h> -#include <asm/pgalloc.h> -#include <asm/tlb.h> -#include <asm/meminit.h> -#include <asm/numa.h> -#include <asm/sections.h> - -/* - * Track per-node information needed to setup the boot memory allocator, the - * per-node areas, and the real VM. - */ -struct early_node_data { - struct ia64_node_data *node_data; - unsigned long pernode_addr; - unsigned long pernode_size; - unsigned long num_physpages; -#ifdef CONFIG_ZONE_DMA - unsigned long num_dma_physpages; -#endif - unsigned long min_pfn; - unsigned long max_pfn; -}; - -static struct early_node_data mem_data[MAX_NUMNODES] __initdata; -static nodemask_t memory_less_mask __initdata; - -pg_data_t *pgdat_list[MAX_NUMNODES]; - -/* - * To prevent cache aliasing effects, align per-node structures so that they - * start at addresses that are strided by node number. - */ -#define MAX_NODE_ALIGN_OFFSET (32 * 1024 * 1024) -#define NODEDATA_ALIGN(addr, node) \ - ((((addr) + 1024*1024-1) & ~(1024*1024-1)) + \ - (((node)*PERCPU_PAGE_SIZE) & (MAX_NODE_ALIGN_OFFSET - 1))) - -/** - * build_node_maps - callback to setup bootmem structs for each node - * @start: physical start of range - * @len: length of range - * @node: node where this range resides - * - * We allocate a struct bootmem_data for each piece of memory that we wish to - * treat as a virtually contiguous block (i.e. each node). Each such block - * must start on an %IA64_GRANULE_SIZE boundary, so we round the address down - * if necessary. Any non-existent pages will simply be part of the virtual - * memmap. We also update min_low_pfn and max_low_pfn here as we receive - * memory ranges from the caller. - */ -static int __init build_node_maps(unsigned long start, unsigned long len, - int node) -{ - unsigned long spfn, epfn, end = start + len; - struct bootmem_data *bdp = &bootmem_node_data[node]; - - epfn = GRANULEROUNDUP(end) >> PAGE_SHIFT; - spfn = GRANULEROUNDDOWN(start) >> PAGE_SHIFT; - - if (!bdp->node_low_pfn) { - bdp->node_min_pfn = spfn; - bdp->node_low_pfn = epfn; - } else { - bdp->node_min_pfn = min(spfn, bdp->node_min_pfn); - bdp->node_low_pfn = max(epfn, bdp->node_low_pfn); - } - - return 0; -} - -/** - * early_nr_cpus_node - return number of cpus on a given node - * @node: node to check - * - * Count the number of cpus on @node. We can't use nr_cpus_node() yet because - * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been - * called yet. Note that node 0 will also count all non-existent cpus. - */ -static int __meminit early_nr_cpus_node(int node) -{ - int cpu, n = 0; - - for_each_possible_early_cpu(cpu) - if (node == node_cpuid[cpu].nid) - n++; - - return n; -} - -/** - * compute_pernodesize - compute size of pernode data - * @node: the node id. - */ -static unsigned long __meminit compute_pernodesize(int node) -{ - unsigned long pernodesize = 0, cpus; - - cpus = early_nr_cpus_node(node); - pernodesize += PERCPU_PAGE_SIZE * cpus; - pernodesize += node * L1_CACHE_BYTES; - pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t)); - pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); - pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t)); - pernodesize = PAGE_ALIGN(pernodesize); - return pernodesize; -} - -/** - * per_cpu_node_setup - setup per-cpu areas on each node - * @cpu_data: per-cpu area on this node - * @node: node to setup - * - * Copy the static per-cpu data into the region we just set aside and then - * setup __per_cpu_offset for each CPU on this node. Return a pointer to - * the end of the area. - */ -static void *per_cpu_node_setup(void *cpu_data, int node) -{ -#ifdef CONFIG_SMP - int cpu; - - for_each_possible_early_cpu(cpu) { - void *src = cpu == 0 ? __cpu0_per_cpu : __phys_per_cpu_start; - - if (node != node_cpuid[cpu].nid) - continue; - - memcpy(__va(cpu_data), src, __per_cpu_end - __per_cpu_start); - __per_cpu_offset[cpu] = (char *)__va(cpu_data) - - __per_cpu_start; - - /* - * percpu area for cpu0 is moved from the __init area - * which is setup by head.S and used till this point. - * Update ar.k3. This move is ensures that percpu - * area for cpu0 is on the correct node and its - * virtual address isn't insanely far from other - * percpu areas which is important for congruent - * percpu allocator. - */ - if (cpu == 0) - ia64_set_kr(IA64_KR_PER_CPU_DATA, - (unsigned long)cpu_data - - (unsigned long)__per_cpu_start); - - cpu_data += PERCPU_PAGE_SIZE; - } -#endif - return cpu_data; -} - -#ifdef CONFIG_SMP -/** - * setup_per_cpu_areas - setup percpu areas - * - * Arch code has already allocated and initialized percpu areas. All - * this function has to do is to teach the determined layout to the - * dynamic percpu allocator, which happens to be more complex than - * creating whole new ones using helpers. - */ -void __init setup_per_cpu_areas(void) -{ - struct pcpu_alloc_info *ai; - struct pcpu_group_info *uninitialized_var(gi); - unsigned int *cpu_map; - void *base; - unsigned long base_offset; - unsigned int cpu; - ssize_t static_size, reserved_size, dyn_size; - int node, prev_node, unit, nr_units, rc; - - ai = pcpu_alloc_alloc_info(MAX_NUMNODES, nr_cpu_ids); - if (!ai) - panic("failed to allocate pcpu_alloc_info"); - cpu_map = ai->groups[0].cpu_map; - - /* determine base */ - base = (void *)ULONG_MAX; - for_each_possible_cpu(cpu) - base = min(base, - (void *)(__per_cpu_offset[cpu] + __per_cpu_start)); - base_offset = (void *)__per_cpu_start - base; - - /* build cpu_map, units are grouped by node */ - unit = 0; - for_each_node(node) - for_each_possible_cpu(cpu) - if (node == node_cpuid[cpu].nid) - cpu_map[unit++] = cpu; - nr_units = unit; - - /* set basic parameters */ - static_size = __per_cpu_end - __per_cpu_start; - reserved_size = PERCPU_MODULE_RESERVE; - dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size; - if (dyn_size < 0) - panic("percpu area overflow static=%zd reserved=%zd\n", - static_size, reserved_size); - - ai->static_size = static_size; - ai->reserved_size = reserved_size; - ai->dyn_size = dyn_size; - ai->unit_size = PERCPU_PAGE_SIZE; - ai->atom_size = PAGE_SIZE; - ai->alloc_size = PERCPU_PAGE_SIZE; - - /* - * CPUs are put into groups according to node. Walk cpu_map - * and create new groups at node boundaries. - */ - prev_node = -1; - ai->nr_groups = 0; - for (unit = 0; unit < nr_units; unit++) { - cpu = cpu_map[unit]; - node = node_cpuid[cpu].nid; - - if (node == prev_node) { - gi->nr_units++; - continue; - } - prev_node = node; - - gi = &ai->groups[ai->nr_groups++]; - gi->nr_units = 1; - gi->base_offset = __per_cpu_offset[cpu] + base_offset; - gi->cpu_map = &cpu_map[unit]; - } - - rc = pcpu_setup_first_chunk(ai, base); - if (rc) - panic("failed to setup percpu area (err=%d)", rc); - - pcpu_free_alloc_info(ai); -} -#endif - -/** - * fill_pernode - initialize pernode data. - * @node: the node id. - * @pernode: physical address of pernode data - * @pernodesize: size of the pernode data - */ -static void __init fill_pernode(int node, unsigned long pernode, - unsigned long pernodesize) -{ - void *cpu_data; - int cpus = early_nr_cpus_node(node); - struct bootmem_data *bdp = &bootmem_node_data[node]; - - mem_data[node].pernode_addr = pernode; - mem_data[node].pernode_size = pernodesize; - memset(__va(pernode), 0, pernodesize); - - cpu_data = (void *)pernode; - pernode += PERCPU_PAGE_SIZE * cpus; - pernode += node * L1_CACHE_BYTES; - - pgdat_list[node] = __va(pernode); - pernode += L1_CACHE_ALIGN(sizeof(pg_data_t)); - - mem_data[node].node_data = __va(pernode); - pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); - - pgdat_list[node]->bdata = bdp; - pernode += L1_CACHE_ALIGN(sizeof(pg_data_t)); - - cpu_data = per_cpu_node_setup(cpu_data, node); - - return; -} - -/** - * find_pernode_space - allocate memory for memory map and per-node structures - * @start: physical start of range - * @len: length of range - * @node: node where this range resides - * - * This routine reserves space for the per-cpu data struct, the list of - * pg_data_ts and the per-node data struct. Each node will have something like - * the following in the first chunk of addr. space large enough to hold it. - * - * ________________________ - * | | - * |~~~~~~~~~~~~~~~~~~~~~~~~| <-- NODEDATA_ALIGN(start, node) for the first - * | PERCPU_PAGE_SIZE * | start and length big enough - * | cpus_on_this_node | Node 0 will also have entries for all non-existent cpus. - * |------------------------| - * | local pg_data_t * | - * |------------------------| - * | local ia64_node_data | - * |------------------------| - * | ??? | - * |________________________| - * - * Once this space has been set aside, the bootmem maps are initialized. We - * could probably move the allocation of the per-cpu and ia64_node_data space - * outside of this function and use alloc_bootmem_node(), but doing it here - * is straightforward and we get the alignments we want so... - */ -static int __init find_pernode_space(unsigned long start, unsigned long len, - int node) -{ - unsigned long spfn, epfn; - unsigned long pernodesize = 0, pernode, pages, mapsize; - struct bootmem_data *bdp = &bootmem_node_data[node]; - - spfn = start >> PAGE_SHIFT; - epfn = (start + len) >> PAGE_SHIFT; - - pages = bdp->node_low_pfn - bdp->node_min_pfn; - mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT; - - /* - * Make sure this memory falls within this node's usable memory - * since we may have thrown some away in build_maps(). - */ - if (spfn < bdp->node_min_pfn || epfn > bdp->node_low_pfn) - return 0; - - /* Don't setup this node's local space twice... */ - if (mem_data[node].pernode_addr) - return 0; - - /* - * Calculate total size needed, incl. what's necessary - * for good alignment and alias prevention. - */ - pernodesize = compute_pernodesize(node); - pernode = NODEDATA_ALIGN(start, node); - - /* Is this range big enough for what we want to store here? */ - if (start + len > (pernode + pernodesize + mapsize)) - fill_pernode(node, pernode, pernodesize); - - return 0; -} - -/** - * free_node_bootmem - free bootmem allocator memory for use - * @start: physical start of range - * @len: length of range - * @node: node where this range resides - * - * Simply calls the bootmem allocator to free the specified ranged from - * the given pg_data_t's bdata struct. After this function has been called - * for all the entries in the EFI memory map, the bootmem allocator will - * be ready to service allocation requests. - */ -static int __init free_node_bootmem(unsigned long start, unsigned long len, - int node) -{ - free_bootmem_node(pgdat_list[node], start, len); - - return 0; -} - -/** - * reserve_pernode_space - reserve memory for per-node space - * - * Reserve the space used by the bootmem maps & per-node space in the boot - * allocator so that when we actually create the real mem maps we don't - * use their memory. - */ -static void __init reserve_pernode_space(void) -{ - unsigned long base, size, pages; - struct bootmem_data *bdp; - int node; - - for_each_online_node(node) { - pg_data_t *pdp = pgdat_list[node]; - - if (node_isset(node, memory_less_mask)) - continue; - - bdp = pdp->bdata; - - /* First the bootmem_map itself */ - pages = bdp->node_low_pfn - bdp->node_min_pfn; - size = bootmem_bootmap_pages(pages) << PAGE_SHIFT; - base = __pa(bdp->node_bootmem_map); - reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT); - - /* Now the per-node space */ - size = mem_data[node].pernode_size; - base = __pa(mem_data[node].pernode_addr); - reserve_bootmem_node(pdp, base, size, BOOTMEM_DEFAULT); - } -} - -static void __meminit scatter_node_data(void) -{ - pg_data_t **dst; - int node; - - /* - * for_each_online_node() can't be used at here. - * node_online_map is not set for hot-added nodes at this time, - * because we are halfway through initialization of the new node's - * structures. If for_each_online_node() is used, a new node's - * pg_data_ptrs will be not initialized. Instead of using it, - * pgdat_list[] is checked. - */ - for_each_node(node) { - if (pgdat_list[node]) { - dst = LOCAL_DATA_ADDR(pgdat_list[node])->pg_data_ptrs; - memcpy(dst, pgdat_list, sizeof(pgdat_list)); - } - } -} - -/** - * initialize_pernode_data - fixup per-cpu & per-node pointers - * - * Each node's per-node area has a copy of the global pg_data_t list, so - * we copy that to each node here, as well as setting the per-cpu pointer - * to the local node data structure. The active_cpus field of the per-node - * structure gets setup by the platform_cpu_init() function later. - */ -static void __init initialize_pernode_data(void) -{ - int cpu, node; - - scatter_node_data(); - -#ifdef CONFIG_SMP - /* Set the node_data pointer for each per-cpu struct */ - for_each_possible_early_cpu(cpu) { - node = node_cpuid[cpu].nid; - per_cpu(ia64_cpu_info, cpu).node_data = - mem_data[node].node_data; - } -#else - { - struct cpuinfo_ia64 *cpu0_cpu_info; - cpu = 0; - node = node_cpuid[cpu].nid; - cpu0_cpu_info = (struct cpuinfo_ia64 *)(__phys_per_cpu_start + - ((char *)&ia64_cpu_info - __per_cpu_start)); - cpu0_cpu_info->node_data = mem_data[node].node_data; - } -#endif /* CONFIG_SMP */ -} - -/** - * memory_less_node_alloc - * attempt to allocate memory on the best NUMA slit - * node but fall back to any other node when __alloc_bootmem_node fails - * for best. - * @nid: node id - * @pernodesize: size of this node's pernode data - */ -static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize) -{ - void *ptr = NULL; - u8 best = 0xff; - int bestnode = -1, node, anynode = 0; - - for_each_online_node(node) { - if (node_isset(node, memory_less_mask)) - continue; - else if (node_distance(nid, node) < best) { - best = node_distance(nid, node); - bestnode = node; - } - anynode = node; - } - - if (bestnode == -1) - bestnode = anynode; - - ptr = __alloc_bootmem_node(pgdat_list[bestnode], pernodesize, - PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); - - return ptr; -} - -/** - * memory_less_nodes - allocate and initialize CPU only nodes pernode - * information. - */ -static void __init memory_less_nodes(void) -{ - unsigned long pernodesize; - void *pernode; - int node; - - for_each_node_mask(node, memory_less_mask) { - pernodesize = compute_pernodesize(node); - pernode = memory_less_node_alloc(node, pernodesize); - fill_pernode(node, __pa(pernode), pernodesize); - } - - return; -} - -/** - * find_memory - walk the EFI memory map and setup the bootmem allocator - * - * Called early in boot to setup the bootmem allocator, and to - * allocate the per-cpu and per-node structures. - */ -void __init find_memory(void) -{ - int node; - - reserve_memory(); - - if (num_online_nodes() == 0) { - printk(KERN_ERR "node info missing!\n"); - node_set_online(0); - } - - nodes_or(memory_less_mask, memory_less_mask, node_online_map); - min_low_pfn = -1; - max_low_pfn = 0; - - /* These actually end up getting called by call_pernode_memory() */ - efi_memmap_walk(filter_rsvd_memory, build_node_maps); - efi_memmap_walk(filter_rsvd_memory, find_pernode_space); - efi_memmap_walk(find_max_min_low_pfn, NULL); - - for_each_online_node(node) - if (bootmem_node_data[node].node_low_pfn) { - node_clear(node, memory_less_mask); - mem_data[node].min_pfn = ~0UL; - } - - efi_memmap_walk(filter_memory, register_active_ranges); - - /* - * Initialize the boot memory maps in reverse order since that's - * what the bootmem allocator expects - */ - for (node = MAX_NUMNODES - 1; node >= 0; node--) { - unsigned long pernode, pernodesize, map; - struct bootmem_data *bdp; - - if (!node_online(node)) - continue; - else if (node_isset(node, memory_less_mask)) - continue; - - bdp = &bootmem_node_data[node]; - pernode = mem_data[node].pernode_addr; - pernodesize = mem_data[node].pernode_size; - map = pernode + pernodesize; - - init_bootmem_node(pgdat_list[node], - map>>PAGE_SHIFT, - bdp->node_min_pfn, - bdp->node_low_pfn); - } - - efi_memmap_walk(filter_rsvd_memory, free_node_bootmem); - - reserve_pernode_space(); - memory_less_nodes(); - initialize_pernode_data(); - - max_pfn = max_low_pfn; - - find_initrd(); -} - -#ifdef CONFIG_SMP -/** - * per_cpu_init - setup per-cpu variables - * - * find_pernode_space() does most of this already, we just need to set - * local_per_cpu_offset - */ -void __cpuinit *per_cpu_init(void) -{ - int cpu; - static int first_time = 1; - - if (first_time) { - first_time = 0; - for_each_possible_early_cpu(cpu) - per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; - } - - return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; -} -#endif /* CONFIG_SMP */ - -/** - * show_mem - give short summary of memory stats - * - * Shows a simple page count of reserved and used pages in the system. - * For discontig machines, it does this on a per-pgdat basis. - */ -void show_mem(unsigned int filter) -{ - int i, total_reserved = 0; - int total_shared = 0, total_cached = 0; - unsigned long total_present = 0; - pg_data_t *pgdat; - - printk(KERN_INFO "Mem-info:\n"); - show_free_areas(filter); - printk(KERN_INFO "Node memory in pages:\n"); - for_each_online_pgdat(pgdat) { - unsigned long present; - unsigned long flags; - int shared = 0, cached = 0, reserved = 0; - int nid = pgdat->node_id; - - if (skip_free_areas_node(filter, nid)) - continue; - pgdat_resize_lock(pgdat, &flags); - present = pgdat->node_present_pages; - for(i = 0; i < pgdat->node_spanned_pages; i++) { - struct page *page; - if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) - touch_nmi_watchdog(); - if (pfn_valid(pgdat->node_start_pfn + i)) - page = pfn_to_page(pgdat->node_start_pfn + i); - else { - i = vmemmap_find_next_valid_pfn(nid, i) - 1; - continue; - } - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page)-1; - } - pgdat_resize_unlock(pgdat, &flags); - total_present += present; - total_reserved += reserved; - total_cached += cached; - total_shared += shared; - printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, " - "shrd: %10d, swpd: %10d\n", nid, - present, reserved, shared, cached); - } - printk(KERN_INFO "%ld pages of RAM\n", total_present); - printk(KERN_INFO "%d reserved pages\n", total_reserved); - printk(KERN_INFO "%d pages shared\n", total_shared); - printk(KERN_INFO "%d pages swap cached\n", total_cached); - printk(KERN_INFO "Total of %ld pages in page table cache\n", - quicklist_total_size()); - printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages()); -} - -/** - * call_pernode_memory - use SRAT to call callback functions with node info - * @start: physical start of range - * @len: length of range - * @arg: function to call for each range - * - * efi_memmap_walk() knows nothing about layout of memory across nodes. Find - * out to which node a block of memory belongs. Ignore memory that we cannot - * identify, and split blocks that run across multiple nodes. - * - * Take this opportunity to round the start address up and the end address - * down to page boundaries. - */ -void call_pernode_memory(unsigned long start, unsigned long len, void *arg) -{ - unsigned long rs, re, end = start + len; - void (*func)(unsigned long, unsigned long, int); - int i; - - start = PAGE_ALIGN(start); - end &= PAGE_MASK; - if (start >= end) - return; - - func = arg; - - if (!num_node_memblks) { - /* No SRAT table, so assume one node (node 0) */ - if (start < end) - (*func)(start, end - start, 0); - return; - } - - for (i = 0; i < num_node_memblks; i++) { - rs = max(start, node_memblk[i].start_paddr); - re = min(end, node_memblk[i].start_paddr + - node_memblk[i].size); - - if (rs < re) - (*func)(rs, re - rs, node_memblk[i].nid); - - if (re == end) - break; - } -} - -/** - * count_node_pages - callback to build per-node memory info structures - * @start: physical start of range - * @len: length of range - * @node: node where this range resides - * - * Each node has it's own number of physical pages, DMAable pages, start, and - * end page frame number. This routine will be called by call_pernode_memory() - * for each piece of usable memory and will setup these values for each node. - * Very similar to build_maps(). - */ -static __init int count_node_pages(unsigned long start, unsigned long len, int node) -{ - unsigned long end = start + len; - - mem_data[node].num_physpages += len >> PAGE_SHIFT; -#ifdef CONFIG_ZONE_DMA - if (start <= __pa(MAX_DMA_ADDRESS)) - mem_data[node].num_dma_physpages += - (min(end, __pa(MAX_DMA_ADDRESS)) - start) >>PAGE_SHIFT; -#endif - start = GRANULEROUNDDOWN(start); - end = GRANULEROUNDUP(end); - mem_data[node].max_pfn = max(mem_data[node].max_pfn, - end >> PAGE_SHIFT); - mem_data[node].min_pfn = min(mem_data[node].min_pfn, - start >> PAGE_SHIFT); - - return 0; -} - -/** - * paging_init - setup page tables - * - * paging_init() sets up the page tables for each node of the system and frees - * the bootmem allocator memory for general use. - */ -void __init paging_init(void) -{ - unsigned long max_dma; - unsigned long pfn_offset = 0; - unsigned long max_pfn = 0; - int node; - unsigned long max_zone_pfns[MAX_NR_ZONES]; - - max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - - efi_memmap_walk(filter_rsvd_memory, count_node_pages); - - sparse_memory_present_with_active_regions(MAX_NUMNODES); - sparse_init(); - -#ifdef CONFIG_VIRTUAL_MEM_MAP - VMALLOC_END -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * - sizeof(struct page)); - vmem_map = (struct page *) VMALLOC_END; - efi_memmap_walk(create_mem_map_page_table, NULL); - printk("Virtual mem_map starts at 0x%p\n", vmem_map); -#endif - - for_each_online_node(node) { - num_physpages += mem_data[node].num_physpages; - pfn_offset = mem_data[node].min_pfn; - -#ifdef CONFIG_VIRTUAL_MEM_MAP - NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset; -#endif - if (mem_data[node].max_pfn > max_pfn) - max_pfn = mem_data[node].max_pfn; - } - - memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); -#ifdef CONFIG_ZONE_DMA - max_zone_pfns[ZONE_DMA] = max_dma; -#endif - max_zone_pfns[ZONE_NORMAL] = max_pfn; - free_area_init_nodes(max_zone_pfns); - - zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); -} - -#ifdef CONFIG_MEMORY_HOTPLUG -pg_data_t *arch_alloc_nodedata(int nid) -{ - unsigned long size = compute_pernodesize(nid); - - return kzalloc(size, GFP_KERNEL); -} - -void arch_free_nodedata(pg_data_t *pgdat) -{ - kfree(pgdat); -} - -void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat) -{ - pgdat_list[update_node] = update_pgdat; - scatter_node_data(); -} -#endif - -#ifdef CONFIG_SPARSEMEM_VMEMMAP -int __meminit vmemmap_populate(struct page *start_page, - unsigned long size, int node) -{ - return vmemmap_populate_basepages(start_page, size, node); -} -#endif diff --git a/ANDROID_3.4.5/arch/ia64/mm/extable.c b/ANDROID_3.4.5/arch/ia64/mm/extable.c deleted file mode 100644 index c99a41e2..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/extable.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. - * - * Copyright (C) 1998, 1999, 2001-2002, 2004 Hewlett-Packard Co - * David Mosberger-Tang <davidm@hpl.hp.com> - */ - -#include <linux/sort.h> - -#include <asm/uaccess.h> -#include <linux/module.h> - -static int cmp_ex(const void *a, const void *b) -{ - const struct exception_table_entry *l = a, *r = b; - u64 lip = (u64) &l->addr + l->addr; - u64 rip = (u64) &r->addr + r->addr; - - /* avoid overflow */ - if (lip > rip) - return 1; - if (lip < rip) - return -1; - return 0; -} - -static void swap_ex(void *a, void *b, int size) -{ - struct exception_table_entry *l = a, *r = b, tmp; - u64 delta = (u64) r - (u64) l; - - tmp = *l; - l->addr = r->addr + delta; - l->cont = r->cont + delta; - r->addr = tmp.addr - delta; - r->cont = tmp.cont - delta; -} - -/* - * Sort the exception table. It's usually already sorted, but there - * may be unordered entries due to multiple text sections (such as the - * .init text section). Note that the exception-table-entries contain - * location-relative addresses, which requires a bit of care during - * sorting to avoid overflows in the offset members (e.g., it would - * not be safe to make a temporary copy of an exception-table entry on - * the stack, because the stack may be more than 2GB away from the - * exception-table). - */ -void sort_extable (struct exception_table_entry *start, - struct exception_table_entry *finish) -{ - sort(start, finish - start, sizeof(struct exception_table_entry), - cmp_ex, swap_ex); -} - -static inline unsigned long ex_to_addr(const struct exception_table_entry *x) -{ - return (unsigned long)&x->addr + x->addr; -} - -#ifdef CONFIG_MODULES -/* - * Any entry referring to the module init will be at the beginning or - * the end. - */ -void trim_init_extable(struct module *m) -{ - /*trim the beginning*/ - while (m->num_exentries && - within_module_init(ex_to_addr(&m->extable[0]), m)) { - m->extable++; - m->num_exentries--; - } - /*trim the end*/ - while (m->num_exentries && - within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]), - m)) - m->num_exentries--; -} -#endif /* CONFIG_MODULES */ - -const struct exception_table_entry * -search_extable (const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long ip) -{ - const struct exception_table_entry *mid; - unsigned long mid_ip; - long diff; - - while (first <= last) { - mid = &first[(last - first)/2]; - mid_ip = (u64) &mid->addr + mid->addr; - diff = mid_ip - ip; - if (diff == 0) - return mid; - else if (diff < 0) - first = mid + 1; - else - last = mid - 1; - } - return NULL; -} - -void -ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e) -{ - long fix = (u64) &e->cont + e->cont; - - regs->r8 = -EFAULT; - if (fix & 4) - regs->r9 = 0; - regs->cr_iip = fix & ~0xf; - ia64_psr(regs)->ri = fix & 0x3; /* set continuation slot number */ -} diff --git a/ANDROID_3.4.5/arch/ia64/mm/fault.c b/ANDROID_3.4.5/arch/ia64/mm/fault.c deleted file mode 100644 index 02d29c2a..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/fault.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * MMU fault handling support. - * - * Copyright (C) 1998-2002 Hewlett-Packard Co - * David Mosberger-Tang <davidm@hpl.hp.com> - */ -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/kprobes.h> -#include <linux/kdebug.h> -#include <linux/prefetch.h> - -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/uaccess.h> - -extern int die(char *, struct pt_regs *, long); - -#ifdef CONFIG_KPROBES -static inline int notify_page_fault(struct pt_regs *regs, int trap) -{ - int ret = 0; - - if (!user_mode(regs)) { - /* kprobe_running() needs smp_processor_id() */ - preempt_disable(); - if (kprobe_running() && kprobe_fault_handler(regs, trap)) - ret = 1; - preempt_enable(); - } - - return ret; -} -#else -static inline int notify_page_fault(struct pt_regs *regs, int trap) -{ - return 0; -} -#endif - -/* - * Return TRUE if ADDRESS points at a page in the kernel's mapped segment - * (inside region 5, on ia64) and that page is present. - */ -static int -mapped_kernel_page_is_present (unsigned long address) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *ptep, pte; - - pgd = pgd_offset_k(address); - if (pgd_none(*pgd) || pgd_bad(*pgd)) - return 0; - - pud = pud_offset(pgd, address); - if (pud_none(*pud) || pud_bad(*pud)) - return 0; - - pmd = pmd_offset(pud, address); - if (pmd_none(*pmd) || pmd_bad(*pmd)) - return 0; - - ptep = pte_offset_kernel(pmd, address); - if (!ptep) - return 0; - - pte = *ptep; - return pte_present(pte); -} - -void __kprobes -ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) -{ - int signal = SIGSEGV, code = SEGV_MAPERR; - struct vm_area_struct *vma, *prev_vma; - struct mm_struct *mm = current->mm; - struct siginfo si; - unsigned long mask; - int fault; - - /* mmap_sem is performance critical.... */ - prefetchw(&mm->mmap_sem); - - /* - * If we're in an interrupt or have no user context, we must not take the fault.. - */ - if (in_atomic() || !mm) - goto no_context; - -#ifdef CONFIG_VIRTUAL_MEM_MAP - /* - * If fault is in region 5 and we are in the kernel, we may already - * have the mmap_sem (pfn_valid macro is called during mmap). There - * is no vma for region 5 addr's anyway, so skip getting the semaphore - * and go directly to the exception handling code. - */ - - if ((REGION_NUMBER(address) == 5) && !user_mode(regs)) - goto bad_area_no_up; -#endif - - /* - * This is to handle the kprobes on user space access instructions - */ - if (notify_page_fault(regs, TRAP_BRKPT)) - return; - - down_read(&mm->mmap_sem); - - vma = find_vma_prev(mm, address, &prev_vma); - if (!vma && !prev_vma ) - goto bad_area; - - /* - * find_vma_prev() returns vma such that address < vma->vm_end or NULL - * - * May find no vma, but could be that the last vm area is the - * register backing store that needs to expand upwards, in - * this case vma will be null, but prev_vma will ne non-null - */ - if (( !vma && prev_vma ) || (address < vma->vm_start) ) - goto check_expansion; - - good_area: - code = SEGV_ACCERR; - - /* OK, we've got a good vm_area for this memory area. Check the access permissions: */ - -# define VM_READ_BIT 0 -# define VM_WRITE_BIT 1 -# define VM_EXEC_BIT 2 - -# if (((1 << VM_READ_BIT) != VM_READ || (1 << VM_WRITE_BIT) != VM_WRITE) \ - || (1 << VM_EXEC_BIT) != VM_EXEC) -# error File is out of sync with <linux/mm.h>. Please update. -# endif - - if (((isr >> IA64_ISR_R_BIT) & 1UL) && (!(vma->vm_flags & (VM_READ | VM_WRITE)))) - goto bad_area; - - mask = ( (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT) - | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT)); - - if ((vma->vm_flags & mask) != mask) - goto bad_area; - - /* - * If for any reason at all we couldn't handle the fault, make - * sure we exit gracefully rather than endlessly redo the - * fault. - */ - fault = handle_mm_fault(mm, vma, address, (mask & VM_WRITE) ? FAULT_FLAG_WRITE : 0); - if (unlikely(fault & VM_FAULT_ERROR)) { - /* - * We ran out of memory, or some other thing happened - * to us that made us unable to handle the page fault - * gracefully. - */ - if (fault & VM_FAULT_OOM) { - goto out_of_memory; - } else if (fault & VM_FAULT_SIGBUS) { - signal = SIGBUS; - goto bad_area; - } - BUG(); - } - if (fault & VM_FAULT_MAJOR) - current->maj_flt++; - else - current->min_flt++; - up_read(&mm->mmap_sem); - return; - - check_expansion: - if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) { - if (!vma) - goto bad_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start) - || REGION_OFFSET(address) >= RGN_MAP_LIMIT) - goto bad_area; - if (expand_stack(vma, address)) - goto bad_area; - } else { - vma = prev_vma; - if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start) - || REGION_OFFSET(address) >= RGN_MAP_LIMIT) - goto bad_area; - /* - * Since the register backing store is accessed sequentially, - * we disallow growing it by more than a page at a time. - */ - if (address > vma->vm_end + PAGE_SIZE - sizeof(long)) - goto bad_area; - if (expand_upwards(vma, address)) - goto bad_area; - } - goto good_area; - - bad_area: - up_read(&mm->mmap_sem); -#ifdef CONFIG_VIRTUAL_MEM_MAP - bad_area_no_up: -#endif - if ((isr & IA64_ISR_SP) - || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) - { - /* - * This fault was due to a speculative load or lfetch.fault, set the "ed" - * bit in the psr to ensure forward progress. (Target register will get a - * NaT for ld.s, lfetch will be canceled.) - */ - ia64_psr(regs)->ed = 1; - return; - } - if (user_mode(regs)) { - si.si_signo = signal; - si.si_errno = 0; - si.si_code = code; - si.si_addr = (void __user *) address; - si.si_isr = isr; - si.si_flags = __ISR_VALID; - force_sig_info(signal, &si, current); - return; - } - - no_context: - if ((isr & IA64_ISR_SP) - || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) - { - /* - * This fault was due to a speculative load or lfetch.fault, set the "ed" - * bit in the psr to ensure forward progress. (Target register will get a - * NaT for ld.s, lfetch will be canceled.) - */ - ia64_psr(regs)->ed = 1; - return; - } - - /* - * Since we have no vma's for region 5, we might get here even if the address is - * valid, due to the VHPT walker inserting a non present translation that becomes - * stale. If that happens, the non present fault handler already purged the stale - * translation, which fixed the problem. So, we check to see if the translation is - * valid, and return if it is. - */ - if (REGION_NUMBER(address) == 5 && mapped_kernel_page_is_present(address)) - return; - - if (ia64_done_with_exception(regs)) - return; - - /* - * Oops. The kernel tried to access some bad page. We'll have to terminate things - * with extreme prejudice. - */ - bust_spinlocks(1); - - if (address < PAGE_SIZE) - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address); - else - printk(KERN_ALERT "Unable to handle kernel paging request at " - "virtual address %016lx\n", address); - if (die("Oops", regs, isr)) - regs = NULL; - bust_spinlocks(0); - if (regs) - do_exit(SIGKILL); - return; - - out_of_memory: - up_read(&mm->mmap_sem); - if (!user_mode(regs)) - goto no_context; - pagefault_out_of_memory(); -} diff --git a/ANDROID_3.4.5/arch/ia64/mm/hugetlbpage.c b/ANDROID_3.4.5/arch/ia64/mm/hugetlbpage.c deleted file mode 100644 index 5ca674b7..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/hugetlbpage.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * IA-64 Huge TLB Page Support for Kernel. - * - * Copyright (C) 2002-2004 Rohit Seth <rohit.seth@intel.com> - * Copyright (C) 2003-2004 Ken Chen <kenneth.w.chen@intel.com> - * - * Sep, 2003: add numa support - * Feb, 2004: dynamic hugetlb page size via boot parameter - */ - -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/hugetlb.h> -#include <linux/pagemap.h> -#include <linux/module.h> -#include <linux/sysctl.h> -#include <linux/log2.h> -#include <asm/mman.h> -#include <asm/pgalloc.h> -#include <asm/tlb.h> -#include <asm/tlbflush.h> - -unsigned int hpage_shift = HPAGE_SHIFT_DEFAULT; -EXPORT_SYMBOL(hpage_shift); - -pte_t * -huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz) -{ - unsigned long taddr = htlbpage_to_page(addr); - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte = NULL; - - pgd = pgd_offset(mm, taddr); - pud = pud_alloc(mm, pgd, taddr); - if (pud) { - pmd = pmd_alloc(mm, pud, taddr); - if (pmd) - pte = pte_alloc_map(mm, NULL, pmd, taddr); - } - return pte; -} - -pte_t * -huge_pte_offset (struct mm_struct *mm, unsigned long addr) -{ - unsigned long taddr = htlbpage_to_page(addr); - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte = NULL; - - pgd = pgd_offset(mm, taddr); - if (pgd_present(*pgd)) { - pud = pud_offset(pgd, taddr); - if (pud_present(*pud)) { - pmd = pmd_offset(pud, taddr); - if (pmd_present(*pmd)) - pte = pte_offset_map(pmd, taddr); - } - } - - return pte; -} - -int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) -{ - return 0; -} - -#define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; } - -/* - * Don't actually need to do any preparation, but need to make sure - * the address is in the right region. - */ -int prepare_hugepage_range(struct file *file, - unsigned long addr, unsigned long len) -{ - if (len & ~HPAGE_MASK) - return -EINVAL; - if (addr & ~HPAGE_MASK) - return -EINVAL; - if (REGION_NUMBER(addr) != RGN_HPAGE) - return -EINVAL; - - return 0; -} - -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long addr, int write) -{ - struct page *page; - pte_t *ptep; - - if (REGION_NUMBER(addr) != RGN_HPAGE) - return ERR_PTR(-EINVAL); - - ptep = huge_pte_offset(mm, addr); - if (!ptep || pte_none(*ptep)) - return NULL; - page = pte_page(*ptep); - page += ((addr & ~HPAGE_MASK) >> PAGE_SHIFT); - return page; -} -int pmd_huge(pmd_t pmd) -{ - return 0; -} - -int pud_huge(pud_t pud) -{ - return 0; -} - -struct page * -follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write) -{ - return NULL; -} - -void hugetlb_free_pgd_range(struct mmu_gather *tlb, - unsigned long addr, unsigned long end, - unsigned long floor, unsigned long ceiling) -{ - /* - * This is called to free hugetlb page tables. - * - * The offset of these addresses from the base of the hugetlb - * region must be scaled down by HPAGE_SIZE/PAGE_SIZE so that - * the standard free_pgd_range will free the right page tables. - * - * If floor and ceiling are also in the hugetlb region, they - * must likewise be scaled down; but if outside, left unchanged. - */ - - addr = htlbpage_to_page(addr); - end = htlbpage_to_page(end); - if (REGION_NUMBER(floor) == RGN_HPAGE) - floor = htlbpage_to_page(floor); - if (REGION_NUMBER(ceiling) == RGN_HPAGE) - ceiling = htlbpage_to_page(ceiling); - - free_pgd_range(tlb, addr, end, floor, ceiling); -} - -unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct vm_area_struct *vmm; - - if (len > RGN_MAP_LIMIT) - return -ENOMEM; - if (len & ~HPAGE_MASK) - return -EINVAL; - - /* Handle MAP_FIXED */ - if (flags & MAP_FIXED) { - if (prepare_hugepage_range(file, addr, len)) - return -EINVAL; - return addr; - } - - /* This code assumes that RGN_HPAGE != 0. */ - if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1))) - addr = HPAGE_REGION_BASE; - else - addr = ALIGN(addr, HPAGE_SIZE); - for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { - /* At this point: (!vmm || addr < vmm->vm_end). */ - if (REGION_OFFSET(addr) + len > RGN_MAP_LIMIT) - return -ENOMEM; - if (!vmm || (addr + len) <= vmm->vm_start) - return addr; - addr = ALIGN(vmm->vm_end, HPAGE_SIZE); - } -} - -static int __init hugetlb_setup_sz(char *str) -{ - u64 tr_pages; - unsigned long long size; - - if (ia64_pal_vm_page_size(&tr_pages, NULL) != 0) - /* - * shouldn't happen, but just in case. - */ - tr_pages = 0x15557000UL; - - size = memparse(str, &str); - if (*str || !is_power_of_2(size) || !(tr_pages & size) || - size <= PAGE_SIZE || - size >= (1UL << PAGE_SHIFT << MAX_ORDER)) { - printk(KERN_WARNING "Invalid huge page size specified\n"); - return 1; - } - - hpage_shift = __ffs(size); - /* - * boot cpu already executed ia64_mmu_init, and has HPAGE_SHIFT_DEFAULT - * override here with new page shift. - */ - ia64_set_rr(HPAGE_REGION_BASE, hpage_shift << 2); - return 0; -} -early_param("hugepagesz", hugetlb_setup_sz); diff --git a/ANDROID_3.4.5/arch/ia64/mm/init.c b/ANDROID_3.4.5/arch/ia64/mm/init.c deleted file mode 100644 index 0eab4548..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/init.c +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Initialize MMU support. - * - * Copyright (C) 1998-2003 Hewlett-Packard Co - * David Mosberger-Tang <davidm@hpl.hp.com> - */ -#include <linux/kernel.h> -#include <linux/init.h> - -#include <linux/bootmem.h> -#include <linux/efi.h> -#include <linux/elf.h> -#include <linux/memblock.h> -#include <linux/mm.h> -#include <linux/mmzone.h> -#include <linux/module.h> -#include <linux/personality.h> -#include <linux/reboot.h> -#include <linux/slab.h> -#include <linux/swap.h> -#include <linux/proc_fs.h> -#include <linux/bitops.h> -#include <linux/kexec.h> - -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/machvec.h> -#include <asm/numa.h> -#include <asm/patch.h> -#include <asm/pgalloc.h> -#include <asm/sal.h> -#include <asm/sections.h> -#include <asm/tlb.h> -#include <asm/uaccess.h> -#include <asm/unistd.h> -#include <asm/mca.h> -#include <asm/paravirt.h> - -extern void ia64_tlb_init (void); - -unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; - -#ifdef CONFIG_VIRTUAL_MEM_MAP -unsigned long VMALLOC_END = VMALLOC_END_INIT; -EXPORT_SYMBOL(VMALLOC_END); -struct page *vmem_map; -EXPORT_SYMBOL(vmem_map); -#endif - -struct page *zero_page_memmap_ptr; /* map entry for zero page */ -EXPORT_SYMBOL(zero_page_memmap_ptr); - -void -__ia64_sync_icache_dcache (pte_t pte) -{ - unsigned long addr; - struct page *page; - - page = pte_page(pte); - addr = (unsigned long) page_address(page); - - if (test_bit(PG_arch_1, &page->flags)) - return; /* i-cache is already coherent with d-cache */ - - flush_icache_range(addr, addr + (PAGE_SIZE << compound_order(page))); - set_bit(PG_arch_1, &page->flags); /* mark page as clean */ -} - -/* - * Since DMA is i-cache coherent, any (complete) pages that were written via - * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to - * flush them when they get mapped into an executable vm-area. - */ -void -dma_mark_clean(void *addr, size_t size) -{ - unsigned long pg_addr, end; - - pg_addr = PAGE_ALIGN((unsigned long) addr); - end = (unsigned long) addr + size; - while (pg_addr + PAGE_SIZE <= end) { - struct page *page = virt_to_page(pg_addr); - set_bit(PG_arch_1, &page->flags); - pg_addr += PAGE_SIZE; - } -} - -inline void -ia64_set_rbs_bot (void) -{ - unsigned long stack_size = rlimit_max(RLIMIT_STACK) & -16; - - if (stack_size > MAX_USER_STACK_SIZE) - stack_size = MAX_USER_STACK_SIZE; - current->thread.rbs_bot = PAGE_ALIGN(current->mm->start_stack - stack_size); -} - -/* - * This performs some platform-dependent address space initialization. - * On IA-64, we want to setup the VM area for the register backing - * store (which grows upwards) and install the gateway page which is - * used for signal trampolines, etc. - */ -void -ia64_init_addr_space (void) -{ - struct vm_area_struct *vma; - - ia64_set_rbs_bot(); - - /* - * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore - * the problem. When the process attempts to write to the register backing store - * for the first time, it will get a SEGFAULT in this case. - */ - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (vma) { - INIT_LIST_HEAD(&vma->anon_vma_chain); - vma->vm_mm = current->mm; - vma->vm_start = current->thread.rbs_bot & PAGE_MASK; - vma->vm_end = vma->vm_start + PAGE_SIZE; - vma->vm_flags = VM_DATA_DEFAULT_FLAGS|VM_GROWSUP|VM_ACCOUNT; - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - down_write(¤t->mm->mmap_sem); - if (insert_vm_struct(current->mm, vma)) { - up_write(¤t->mm->mmap_sem); - kmem_cache_free(vm_area_cachep, vma); - return; - } - up_write(¤t->mm->mmap_sem); - } - - /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ - if (!(current->personality & MMAP_PAGE_ZERO)) { - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (vma) { - INIT_LIST_HEAD(&vma->anon_vma_chain); - vma->vm_mm = current->mm; - vma->vm_end = PAGE_SIZE; - vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); - vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO | VM_RESERVED; - down_write(¤t->mm->mmap_sem); - if (insert_vm_struct(current->mm, vma)) { - up_write(¤t->mm->mmap_sem); - kmem_cache_free(vm_area_cachep, vma); - return; - } - up_write(¤t->mm->mmap_sem); - } - } -} - -void -free_initmem (void) -{ - unsigned long addr, eaddr; - - addr = (unsigned long) ia64_imva(__init_begin); - eaddr = (unsigned long) ia64_imva(__init_end); - while (addr < eaddr) { - ClearPageReserved(virt_to_page(addr)); - init_page_count(virt_to_page(addr)); - free_page(addr); - ++totalram_pages; - addr += PAGE_SIZE; - } - printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n", - (__init_end - __init_begin) >> 10); -} - -void __init -free_initrd_mem (unsigned long start, unsigned long end) -{ - struct page *page; - /* - * EFI uses 4KB pages while the kernel can use 4KB or bigger. - * Thus EFI and the kernel may have different page sizes. It is - * therefore possible to have the initrd share the same page as - * the end of the kernel (given current setup). - * - * To avoid freeing/using the wrong page (kernel sized) we: - * - align up the beginning of initrd - * - align down the end of initrd - * - * | | - * |=============| a000 - * | | - * | | - * | | 9000 - * |/////////////| - * |/////////////| - * |=============| 8000 - * |///INITRD////| - * |/////////////| - * |/////////////| 7000 - * | | - * |KKKKKKKKKKKKK| - * |=============| 6000 - * |KKKKKKKKKKKKK| - * |KKKKKKKKKKKKK| - * K=kernel using 8KB pages - * - * In this example, we must free page 8000 ONLY. So we must align up - * initrd_start and keep initrd_end as is. - */ - start = PAGE_ALIGN(start); - end = end & PAGE_MASK; - - if (start < end) - printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); - - for (; start < end; start += PAGE_SIZE) { - if (!virt_addr_valid(start)) - continue; - page = virt_to_page(start); - ClearPageReserved(page); - init_page_count(page); - free_page(start); - ++totalram_pages; - } -} - -/* - * This installs a clean page in the kernel's page table. - */ -static struct page * __init -put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - if (!PageReserved(page)) - printk(KERN_ERR "put_kernel_page: page at 0x%p not in reserved memory\n", - page_address(page)); - - pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ - - { - pud = pud_alloc(&init_mm, pgd, address); - if (!pud) - goto out; - pmd = pmd_alloc(&init_mm, pud, address); - if (!pmd) - goto out; - pte = pte_alloc_kernel(pmd, address); - if (!pte) - goto out; - if (!pte_none(*pte)) - goto out; - set_pte(pte, mk_pte(page, pgprot)); - } - out: - /* no need for flush_tlb */ - return page; -} - -static void __init -setup_gate (void) -{ - void *gate_section; - struct page *page; - - /* - * Map the gate page twice: once read-only to export the ELF - * headers etc. and once execute-only page to enable - * privilege-promotion via "epc": - */ - gate_section = paravirt_get_gate_section(); - page = virt_to_page(ia64_imva(gate_section)); - put_kernel_page(page, GATE_ADDR, PAGE_READONLY); -#ifdef HAVE_BUGGY_SEGREL - page = virt_to_page(ia64_imva(gate_section + PAGE_SIZE)); - put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE); -#else - put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE); - /* Fill in the holes (if any) with read-only zero pages: */ - { - unsigned long addr; - - for (addr = GATE_ADDR + PAGE_SIZE; - addr < GATE_ADDR + PERCPU_PAGE_SIZE; - addr += PAGE_SIZE) - { - put_kernel_page(ZERO_PAGE(0), addr, - PAGE_READONLY); - put_kernel_page(ZERO_PAGE(0), addr + PERCPU_PAGE_SIZE, - PAGE_READONLY); - } - } -#endif - ia64_patch_gate(); -} - -void __devinit -ia64_mmu_init (void *my_cpu_data) -{ - unsigned long pta, impl_va_bits; - extern void __devinit tlb_init (void); - -#ifdef CONFIG_DISABLE_VHPT -# define VHPT_ENABLE_BIT 0 -#else -# define VHPT_ENABLE_BIT 1 -#endif - - /* - * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped - * address space. The IA-64 architecture guarantees that at least 50 bits of - * virtual address space are implemented but if we pick a large enough page size - * (e.g., 64KB), the mapped address space is big enough that it will overlap with - * VMLPT. I assume that once we run on machines big enough to warrant 64KB pages, - * IMPL_VA_MSB will be significantly bigger, so this is unlikely to become a - * problem in practice. Alternatively, we could truncate the top of the mapped - * address space to not permit mappings that would overlap with the VMLPT. - * --davidm 00/12/06 - */ -# define pte_bits 3 -# define mapped_space_bits (3*(PAGE_SHIFT - pte_bits) + PAGE_SHIFT) - /* - * The virtual page table has to cover the entire implemented address space within - * a region even though not all of this space may be mappable. The reason for - * this is that the Access bit and Dirty bit fault handlers perform - * non-speculative accesses to the virtual page table, so the address range of the - * virtual page table itself needs to be covered by virtual page table. - */ -# define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits) -# define POW2(n) (1ULL << (n)) - - impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61))); - - if (impl_va_bits < 51 || impl_va_bits > 61) - panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1); - /* - * mapped_space_bits - PAGE_SHIFT is the total number of ptes we need, - * which must fit into "vmlpt_bits - pte_bits" slots. Second half of - * the test makes sure that our mapped space doesn't overlap the - * unimplemented hole in the middle of the region. - */ - if ((mapped_space_bits - PAGE_SHIFT > vmlpt_bits - pte_bits) || - (mapped_space_bits > impl_va_bits - 1)) - panic("Cannot build a big enough virtual-linear page table" - " to cover mapped address space.\n" - " Try using a smaller page size.\n"); - - - /* place the VMLPT at the end of each page-table mapped region: */ - pta = POW2(61) - POW2(vmlpt_bits); - - /* - * Set the (virtually mapped linear) page table address. Bit - * 8 selects between the short and long format, bits 2-7 the - * size of the table, and bit 0 whether the VHPT walker is - * enabled. - */ - ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT); - - ia64_tlb_init(); - -#ifdef CONFIG_HUGETLB_PAGE - ia64_set_rr(HPAGE_REGION_BASE, HPAGE_SHIFT << 2); - ia64_srlz_d(); -#endif -} - -#ifdef CONFIG_VIRTUAL_MEM_MAP -int vmemmap_find_next_valid_pfn(int node, int i) -{ - unsigned long end_address, hole_next_pfn; - unsigned long stop_address; - pg_data_t *pgdat = NODE_DATA(node); - - end_address = (unsigned long) &vmem_map[pgdat->node_start_pfn + i]; - end_address = PAGE_ALIGN(end_address); - - stop_address = (unsigned long) &vmem_map[ - pgdat->node_start_pfn + pgdat->node_spanned_pages]; - - do { - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - pgd = pgd_offset_k(end_address); - if (pgd_none(*pgd)) { - end_address += PGDIR_SIZE; - continue; - } - - pud = pud_offset(pgd, end_address); - if (pud_none(*pud)) { - end_address += PUD_SIZE; - continue; - } - - pmd = pmd_offset(pud, end_address); - if (pmd_none(*pmd)) { - end_address += PMD_SIZE; - continue; - } - - pte = pte_offset_kernel(pmd, end_address); -retry_pte: - if (pte_none(*pte)) { - end_address += PAGE_SIZE; - pte++; - if ((end_address < stop_address) && - (end_address != ALIGN(end_address, 1UL << PMD_SHIFT))) - goto retry_pte; - continue; - } - /* Found next valid vmem_map page */ - break; - } while (end_address < stop_address); - - end_address = min(end_address, stop_address); - end_address = end_address - (unsigned long) vmem_map + sizeof(struct page) - 1; - hole_next_pfn = end_address / sizeof(struct page); - return hole_next_pfn - pgdat->node_start_pfn; -} - -int __init create_mem_map_page_table(u64 start, u64 end, void *arg) -{ - unsigned long address, start_page, end_page; - struct page *map_start, *map_end; - int node; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); - map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); - - start_page = (unsigned long) map_start & PAGE_MASK; - end_page = PAGE_ALIGN((unsigned long) map_end); - node = paddr_to_nid(__pa(start)); - - for (address = start_page; address < end_page; address += PAGE_SIZE) { - pgd = pgd_offset_k(address); - if (pgd_none(*pgd)) - pgd_populate(&init_mm, pgd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)); - pud = pud_offset(pgd, address); - - if (pud_none(*pud)) - pud_populate(&init_mm, pud, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)); - pmd = pmd_offset(pud, address); - - if (pmd_none(*pmd)) - pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)); - pte = pte_offset_kernel(pmd, address); - - if (pte_none(*pte)) - set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)) >> PAGE_SHIFT, - PAGE_KERNEL)); - } - return 0; -} - -struct memmap_init_callback_data { - struct page *start; - struct page *end; - int nid; - unsigned long zone; -}; - -static int __meminit -virtual_memmap_init(u64 start, u64 end, void *arg) -{ - struct memmap_init_callback_data *args; - struct page *map_start, *map_end; - - args = (struct memmap_init_callback_data *) arg; - map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); - map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); - - if (map_start < args->start) - map_start = args->start; - if (map_end > args->end) - map_end = args->end; - - /* - * We have to initialize "out of bounds" struct page elements that fit completely - * on the same pages that were allocated for the "in bounds" elements because they - * may be referenced later (and found to be "reserved"). - */ - map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1)) / sizeof(struct page); - map_end += ((PAGE_ALIGN((unsigned long) map_end) - (unsigned long) map_end) - / sizeof(struct page)); - - if (map_start < map_end) - memmap_init_zone((unsigned long)(map_end - map_start), - args->nid, args->zone, page_to_pfn(map_start), - MEMMAP_EARLY); - return 0; -} - -void __meminit -memmap_init (unsigned long size, int nid, unsigned long zone, - unsigned long start_pfn) -{ - if (!vmem_map) - memmap_init_zone(size, nid, zone, start_pfn, MEMMAP_EARLY); - else { - struct page *start; - struct memmap_init_callback_data args; - - start = pfn_to_page(start_pfn); - args.start = start; - args.end = start + size; - args.nid = nid; - args.zone = zone; - - efi_memmap_walk(virtual_memmap_init, &args); - } -} - -int -ia64_pfn_valid (unsigned long pfn) -{ - char byte; - struct page *pg = pfn_to_page(pfn); - - return (__get_user(byte, (char __user *) pg) == 0) - && ((((u64)pg & PAGE_MASK) == (((u64)(pg + 1) - 1) & PAGE_MASK)) - || (__get_user(byte, (char __user *) (pg + 1) - 1) == 0)); -} -EXPORT_SYMBOL(ia64_pfn_valid); - -int __init find_largest_hole(u64 start, u64 end, void *arg) -{ - u64 *max_gap = arg; - - static u64 last_end = PAGE_OFFSET; - - /* NOTE: this algorithm assumes efi memmap table is ordered */ - - if (*max_gap < (start - last_end)) - *max_gap = start - last_end; - last_end = end; - return 0; -} - -#endif /* CONFIG_VIRTUAL_MEM_MAP */ - -int __init register_active_ranges(u64 start, u64 len, int nid) -{ - u64 end = start + len; - -#ifdef CONFIG_KEXEC - if (start > crashk_res.start && start < crashk_res.end) - start = crashk_res.end; - if (end > crashk_res.start && end < crashk_res.end) - end = crashk_res.start; -#endif - - if (start < end) - memblock_add_node(__pa(start), end - start, nid); - return 0; -} - -static int __init -count_reserved_pages(u64 start, u64 end, void *arg) -{ - unsigned long num_reserved = 0; - unsigned long *count = arg; - - for (; start < end; start += PAGE_SIZE) - if (PageReserved(virt_to_page(start))) - ++num_reserved; - *count += num_reserved; - return 0; -} - -int -find_max_min_low_pfn (u64 start, u64 end, void *arg) -{ - unsigned long pfn_start, pfn_end; -#ifdef CONFIG_FLATMEM - pfn_start = (PAGE_ALIGN(__pa(start))) >> PAGE_SHIFT; - pfn_end = (PAGE_ALIGN(__pa(end - 1))) >> PAGE_SHIFT; -#else - pfn_start = GRANULEROUNDDOWN(__pa(start)) >> PAGE_SHIFT; - pfn_end = GRANULEROUNDUP(__pa(end - 1)) >> PAGE_SHIFT; -#endif - min_low_pfn = min(min_low_pfn, pfn_start); - max_low_pfn = max(max_low_pfn, pfn_end); - return 0; -} - -/* - * Boot command-line option "nolwsys" can be used to disable the use of any light-weight - * system call handler. When this option is in effect, all fsyscalls will end up bubbling - * down into the kernel and calling the normal (heavy-weight) syscall handler. This is - * useful for performance testing, but conceivably could also come in handy for debugging - * purposes. - */ - -static int nolwsys __initdata; - -static int __init -nolwsys_setup (char *s) -{ - nolwsys = 1; - return 1; -} - -__setup("nolwsys", nolwsys_setup); - -void __init -mem_init (void) -{ - long reserved_pages, codesize, datasize, initsize; - pg_data_t *pgdat; - int i; - - BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE); - BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE); - BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE); - -#ifdef CONFIG_PCI - /* - * This needs to be called _after_ the command line has been parsed but _before_ - * any drivers that may need the PCI DMA interface are initialized or bootmem has - * been freed. - */ - platform_dma_init(); -#endif - -#ifdef CONFIG_FLATMEM - BUG_ON(!mem_map); - max_mapnr = max_low_pfn; -#endif - - high_memory = __va(max_low_pfn * PAGE_SIZE); - - for_each_online_pgdat(pgdat) - if (pgdat->bdata->node_bootmem_map) - totalram_pages += free_all_bootmem_node(pgdat); - - reserved_pages = 0; - efi_memmap_walk(count_reserved_pages, &reserved_pages); - - codesize = (unsigned long) _etext - (unsigned long) _stext; - datasize = (unsigned long) _edata - (unsigned long) _etext; - initsize = (unsigned long) __init_end - (unsigned long) __init_begin; - - printk(KERN_INFO "Memory: %luk/%luk available (%luk code, %luk reserved, " - "%luk data, %luk init)\n", nr_free_pages() << (PAGE_SHIFT - 10), - num_physpages << (PAGE_SHIFT - 10), codesize >> 10, - reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10); - - - /* - * For fsyscall entrpoints with no light-weight handler, use the ordinary - * (heavy-weight) handler, but mark it by setting bit 0, so the fsyscall entry - * code can tell them apart. - */ - for (i = 0; i < NR_syscalls; ++i) { - extern unsigned long sys_call_table[NR_syscalls]; - unsigned long *fsyscall_table = paravirt_get_fsyscall_table(); - - if (!fsyscall_table[i] || nolwsys) - fsyscall_table[i] = sys_call_table[i] | 1; - } - setup_gate(); -} - -#ifdef CONFIG_MEMORY_HOTPLUG -int arch_add_memory(int nid, u64 start, u64 size) -{ - pg_data_t *pgdat; - struct zone *zone; - unsigned long start_pfn = start >> PAGE_SHIFT; - unsigned long nr_pages = size >> PAGE_SHIFT; - int ret; - - pgdat = NODE_DATA(nid); - - zone = pgdat->node_zones + ZONE_NORMAL; - ret = __add_pages(nid, zone, start_pfn, nr_pages); - - if (ret) - printk("%s: Problem encountered in __add_pages() as ret=%d\n", - __func__, ret); - - return ret; -} -#endif - -/* - * Even when CONFIG_IA32_SUPPORT is not enabled it is - * useful to have the Linux/x86 domain registered to - * avoid an attempted module load when emulators call - * personality(PER_LINUX32). This saves several milliseconds - * on each such call. - */ -static struct exec_domain ia32_exec_domain; - -static int __init -per_linux32_init(void) -{ - ia32_exec_domain.name = "Linux/x86"; - ia32_exec_domain.handler = NULL; - ia32_exec_domain.pers_low = PER_LINUX32; - ia32_exec_domain.pers_high = PER_LINUX32; - ia32_exec_domain.signal_map = default_exec_domain.signal_map; - ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; - register_exec_domain(&ia32_exec_domain); - - return 0; -} - -__initcall(per_linux32_init); diff --git a/ANDROID_3.4.5/arch/ia64/mm/ioremap.c b/ANDROID_3.4.5/arch/ia64/mm/ioremap.c deleted file mode 100644 index 3dccdd8e..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/ioremap.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * (c) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P. - * Bjorn Helgaas <bjorn.helgaas@hp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/compiler.h> -#include <linux/module.h> -#include <linux/efi.h> -#include <linux/io.h> -#include <linux/vmalloc.h> -#include <asm/io.h> -#include <asm/meminit.h> - -static inline void __iomem * -__ioremap (unsigned long phys_addr) -{ - return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr); -} - -void __iomem * -early_ioremap (unsigned long phys_addr, unsigned long size) -{ - return __ioremap(phys_addr); -} - -void __iomem * -ioremap (unsigned long phys_addr, unsigned long size) -{ - void __iomem *addr; - struct vm_struct *area; - unsigned long offset; - pgprot_t prot; - u64 attr; - unsigned long gran_base, gran_size; - unsigned long page_base; - - /* - * For things in kern_memmap, we must use the same attribute - * as the rest of the kernel. For more details, see - * Documentation/ia64/aliasing.txt. - */ - attr = kern_mem_attribute(phys_addr, size); - if (attr & EFI_MEMORY_WB) - return (void __iomem *) phys_to_virt(phys_addr); - else if (attr & EFI_MEMORY_UC) - return __ioremap(phys_addr); - - /* - * Some chipsets don't support UC access to memory. If - * WB is supported for the whole granule, we prefer that. - */ - gran_base = GRANULEROUNDDOWN(phys_addr); - gran_size = GRANULEROUNDUP(phys_addr + size) - gran_base; - if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB) - return (void __iomem *) phys_to_virt(phys_addr); - - /* - * WB is not supported for the whole granule, so we can't use - * the region 7 identity mapping. If we can safely cover the - * area with kernel page table mappings, we can use those - * instead. - */ - page_base = phys_addr & PAGE_MASK; - size = PAGE_ALIGN(phys_addr + size) - page_base; - if (efi_mem_attribute(page_base, size) & EFI_MEMORY_WB) { - prot = PAGE_KERNEL; - - /* - * Mappings have to be page-aligned - */ - offset = phys_addr & ~PAGE_MASK; - phys_addr &= PAGE_MASK; - - /* - * Ok, go for it.. - */ - area = get_vm_area(size, VM_IOREMAP); - if (!area) - return NULL; - - area->phys_addr = phys_addr; - addr = (void __iomem *) area->addr; - if (ioremap_page_range((unsigned long) addr, - (unsigned long) addr + size, phys_addr, prot)) { - vunmap((void __force *) addr); - return NULL; - } - - return (void __iomem *) (offset + (char __iomem *)addr); - } - - return __ioremap(phys_addr); -} -EXPORT_SYMBOL(ioremap); - -void __iomem * -ioremap_nocache (unsigned long phys_addr, unsigned long size) -{ - if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB) - return NULL; - - return __ioremap(phys_addr); -} -EXPORT_SYMBOL(ioremap_nocache); - -void -early_iounmap (volatile void __iomem *addr, unsigned long size) -{ -} - -void -iounmap (volatile void __iomem *addr) -{ - if (REGION_NUMBER(addr) == RGN_GATE) - vunmap((void *) ((unsigned long) addr & PAGE_MASK)); -} -EXPORT_SYMBOL(iounmap); diff --git a/ANDROID_3.4.5/arch/ia64/mm/numa.c b/ANDROID_3.4.5/arch/ia64/mm/numa.c deleted file mode 100644 index 3efea7d0..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/numa.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * This file contains NUMA specific variables and functions which can - * be split away from DISCONTIGMEM and are used on NUMA machines with - * contiguous memory. - * - * 2002/08/07 Erich Focht <efocht@ess.nec.de> - */ - -#include <linux/cpu.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/node.h> -#include <linux/init.h> -#include <linux/bootmem.h> -#include <linux/module.h> -#include <asm/mmzone.h> -#include <asm/numa.h> - - -/* - * The following structures are usually initialized by ACPI or - * similar mechanisms and describe the NUMA characteristics of the machine. - */ -int num_node_memblks; -struct node_memblk_s node_memblk[NR_NODE_MEMBLKS]; -struct node_cpuid_s node_cpuid[NR_CPUS] = - { [0 ... NR_CPUS-1] = { .phys_id = 0, .nid = NUMA_NO_NODE } }; - -/* - * This is a matrix with "distances" between nodes, they should be - * proportional to the memory access latency ratios. - */ -u8 numa_slit[MAX_NUMNODES * MAX_NUMNODES]; - -/* Identify which cnode a physical address resides on */ -int -paddr_to_nid(unsigned long paddr) -{ - int i; - - for (i = 0; i < num_node_memblks; i++) - if (paddr >= node_memblk[i].start_paddr && - paddr < node_memblk[i].start_paddr + node_memblk[i].size) - break; - - return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0); -} - -#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA) -/* - * Because of holes evaluate on section limits. - * If the section of memory exists, then return the node where the section - * resides. Otherwise return node 0 as the default. This is used by - * SPARSEMEM to allocate the SPARSEMEM sectionmap on the NUMA node where - * the section resides. - */ -int __meminit __early_pfn_to_nid(unsigned long pfn) -{ - int i, section = pfn >> PFN_SECTION_SHIFT, ssec, esec; - - for (i = 0; i < num_node_memblks; i++) { - ssec = node_memblk[i].start_paddr >> PA_SECTION_SHIFT; - esec = (node_memblk[i].start_paddr + node_memblk[i].size + - ((1L << PA_SECTION_SHIFT) - 1)) >> PA_SECTION_SHIFT; - if (section >= ssec && section < esec) - return node_memblk[i].nid; - } - - return -1; -} - -#ifdef CONFIG_MEMORY_HOTPLUG -/* - * SRAT information is stored in node_memblk[], then we can use SRAT - * information at memory-hot-add if necessary. - */ - -int memory_add_physaddr_to_nid(u64 addr) -{ - int nid = paddr_to_nid(addr); - if (nid < 0) - return 0; - return nid; -} - -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif -#endif diff --git a/ANDROID_3.4.5/arch/ia64/mm/tlb.c b/ANDROID_3.4.5/arch/ia64/mm/tlb.c deleted file mode 100644 index 7b3cdc6c..00000000 --- a/ANDROID_3.4.5/arch/ia64/mm/tlb.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * TLB support routines. - * - * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co - * David Mosberger-Tang <davidm@hpl.hp.com> - * - * 08/02/00 A. Mallick <asit.k.mallick@intel.com> - * Modified RID allocation for SMP - * Goutham Rao <goutham.rao@intel.com> - * IPI based ptc implementation and A-step IPI implementation. - * Rohit Seth <rohit.seth@intel.com> - * Ken Chen <kenneth.w.chen@intel.com> - * Christophe de Dinechin <ddd@hp.com>: Avoid ptc.e on memory allocation - * Copyright (C) 2007 Intel Corp - * Fenghua Yu <fenghua.yu@intel.com> - * Add multiple ptc.g/ptc.ga instruction support in global tlb purge. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/mm.h> -#include <linux/bootmem.h> -#include <linux/slab.h> - -#include <asm/delay.h> -#include <asm/mmu_context.h> -#include <asm/pgalloc.h> -#include <asm/pal.h> -#include <asm/tlbflush.h> -#include <asm/dma.h> -#include <asm/processor.h> -#include <asm/sal.h> -#include <asm/tlb.h> - -static struct { - u64 mask; /* mask of supported purge page-sizes */ - unsigned long max_bits; /* log2 of largest supported purge page-size */ -} purge; - -struct ia64_ctx ia64_ctx = { - .lock = __SPIN_LOCK_UNLOCKED(ia64_ctx.lock), - .next = 1, - .max_ctx = ~0U -}; - -DEFINE_PER_CPU(u8, ia64_need_tlb_flush); -DEFINE_PER_CPU(u8, ia64_tr_num); /*Number of TR slots in current processor*/ -DEFINE_PER_CPU(u8, ia64_tr_used); /*Max Slot number used by kernel*/ - -struct ia64_tr_entry *ia64_idtrs[NR_CPUS]; - -/* - * Initializes the ia64_ctx.bitmap array based on max_ctx+1. - * Called after cpu_init() has setup ia64_ctx.max_ctx based on - * maximum RID that is supported by boot CPU. - */ -void __init -mmu_context_init (void) -{ - ia64_ctx.bitmap = alloc_bootmem((ia64_ctx.max_ctx+1)>>3); - ia64_ctx.flushmap = alloc_bootmem((ia64_ctx.max_ctx+1)>>3); -} - -/* - * Acquire the ia64_ctx.lock before calling this function! - */ -void -wrap_mmu_context (struct mm_struct *mm) -{ - int i, cpu; - unsigned long flush_bit; - - for (i=0; i <= ia64_ctx.max_ctx / BITS_PER_LONG; i++) { - flush_bit = xchg(&ia64_ctx.flushmap[i], 0); - ia64_ctx.bitmap[i] ^= flush_bit; - } - - /* use offset at 300 to skip daemons */ - ia64_ctx.next = find_next_zero_bit(ia64_ctx.bitmap, - ia64_ctx.max_ctx, 300); - ia64_ctx.limit = find_next_bit(ia64_ctx.bitmap, - ia64_ctx.max_ctx, ia64_ctx.next); - - /* - * can't call flush_tlb_all() here because of race condition - * with O(1) scheduler [EF] - */ - cpu = get_cpu(); /* prevent preemption/migration */ - for_each_online_cpu(i) - if (i != cpu) - per_cpu(ia64_need_tlb_flush, i) = 1; - put_cpu(); - local_flush_tlb_all(); -} - -/* - * Implement "spinaphores" ... like counting semaphores, but they - * spin instead of sleeping. If there are ever any other users for - * this primitive it can be moved up to a spinaphore.h header. - */ -struct spinaphore { - unsigned long ticket; - unsigned long serve; -}; - -static inline void spinaphore_init(struct spinaphore *ss, int val) -{ - ss->ticket = 0; - ss->serve = val; -} - -static inline void down_spin(struct spinaphore *ss) -{ - unsigned long t = ia64_fetchadd(1, &ss->ticket, acq), serve; - - if (time_before(t, ss->serve)) - return; - - ia64_invala(); - - for (;;) { - asm volatile ("ld8.c.nc %0=[%1]" : "=r"(serve) : "r"(&ss->serve) : "memory"); - if (time_before(t, serve)) - return; - cpu_relax(); - } -} - -static inline void up_spin(struct spinaphore *ss) -{ - ia64_fetchadd(1, &ss->serve, rel); -} - -static struct spinaphore ptcg_sem; -static u16 nptcg = 1; -static int need_ptcg_sem = 1; -static int toolatetochangeptcgsem = 0; - -/* - * Kernel parameter "nptcg=" overrides max number of concurrent global TLB - * purges which is reported from either PAL or SAL PALO. - * - * We don't have sanity checking for nptcg value. It's the user's responsibility - * for valid nptcg value on the platform. Otherwise, kernel may hang in some - * cases. - */ -static int __init -set_nptcg(char *str) -{ - int value = 0; - - get_option(&str, &value); - setup_ptcg_sem(value, NPTCG_FROM_KERNEL_PARAMETER); - - return 1; -} - -__setup("nptcg=", set_nptcg); - -/* - * Maximum number of simultaneous ptc.g purges in the system can - * be defined by PAL_VM_SUMMARY (in which case we should take - * the smallest value for any cpu in the system) or by the PAL - * override table (in which case we should ignore the value from - * PAL_VM_SUMMARY). - * - * Kernel parameter "nptcg=" overrides maximum number of simultanesous ptc.g - * purges defined in either PAL_VM_SUMMARY or PAL override table. In this case, - * we should ignore the value from either PAL_VM_SUMMARY or PAL override table. - * - * Complicating the logic here is the fact that num_possible_cpus() - * isn't fully setup until we start bringing cpus online. - */ -void -setup_ptcg_sem(int max_purges, int nptcg_from) -{ - static int kp_override; - static int palo_override; - static int firstcpu = 1; - - if (toolatetochangeptcgsem) { - if (nptcg_from == NPTCG_FROM_PAL && max_purges == 0) - BUG_ON(1 < nptcg); - else - BUG_ON(max_purges < nptcg); - return; - } - - if (nptcg_from == NPTCG_FROM_KERNEL_PARAMETER) { - kp_override = 1; - nptcg = max_purges; - goto resetsema; - } - if (kp_override) { - need_ptcg_sem = num_possible_cpus() > nptcg; - return; - } - - if (nptcg_from == NPTCG_FROM_PALO) { - palo_override = 1; - - /* In PALO max_purges == 0 really means it! */ - if (max_purges == 0) - panic("Whoa! Platform does not support global TLB purges.\n"); - nptcg = max_purges; - if (nptcg == PALO_MAX_TLB_PURGES) { - need_ptcg_sem = 0; - return; - } - goto resetsema; - } - if (palo_override) { - if (nptcg != PALO_MAX_TLB_PURGES) - need_ptcg_sem = (num_possible_cpus() > nptcg); - return; - } - - /* In PAL_VM_SUMMARY max_purges == 0 actually means 1 */ - if (max_purges == 0) max_purges = 1; - - if (firstcpu) { - nptcg = max_purges; - firstcpu = 0; - } - if (max_purges < nptcg) - nptcg = max_purges; - if (nptcg == PAL_MAX_PURGES) { - need_ptcg_sem = 0; - return; - } else - need_ptcg_sem = (num_possible_cpus() > nptcg); - -resetsema: - spinaphore_init(&ptcg_sem, max_purges); -} - -void -ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start, - unsigned long end, unsigned long nbits) -{ - struct mm_struct *active_mm = current->active_mm; - - toolatetochangeptcgsem = 1; - - if (mm != active_mm) { - /* Restore region IDs for mm */ - if (mm && active_mm) { - activate_context(mm); - } else { - flush_tlb_all(); - return; - } - } - - if (need_ptcg_sem) - down_spin(&ptcg_sem); - - do { - /* - * Flush ALAT entries also. - */ - ia64_ptcga(start, (nbits << 2)); - ia64_srlz_i(); - start += (1UL << nbits); - } while (start < end); - - if (need_ptcg_sem) - up_spin(&ptcg_sem); - - if (mm != active_mm) { - activate_context(active_mm); - } -} - -void -local_flush_tlb_all (void) -{ - unsigned long i, j, flags, count0, count1, stride0, stride1, addr; - - addr = local_cpu_data->ptce_base; - count0 = local_cpu_data->ptce_count[0]; - count1 = local_cpu_data->ptce_count[1]; - stride0 = local_cpu_data->ptce_stride[0]; - stride1 = local_cpu_data->ptce_stride[1]; - - local_irq_save(flags); - for (i = 0; i < count0; ++i) { - for (j = 0; j < count1; ++j) { - ia64_ptce(addr); - addr += stride1; - } - addr += stride0; - } - local_irq_restore(flags); - ia64_srlz_i(); /* srlz.i implies srlz.d */ -} - -void -flush_tlb_range (struct vm_area_struct *vma, unsigned long start, - unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long size = end - start; - unsigned long nbits; - -#ifndef CONFIG_SMP - if (mm != current->active_mm) { - mm->context = 0; - return; - } -#endif - - nbits = ia64_fls(size + 0xfff); - while (unlikely (((1UL << nbits) & purge.mask) == 0) && - (nbits < purge.max_bits)) - ++nbits; - if (nbits > purge.max_bits) - nbits = purge.max_bits; - start &= ~((1UL << nbits) - 1); - - preempt_disable(); -#ifdef CONFIG_SMP - if (mm != current->active_mm || cpumask_weight(mm_cpumask(mm)) != 1) { - platform_global_tlb_purge(mm, start, end, nbits); - preempt_enable(); - return; - } -#endif - do { - ia64_ptcl(start, (nbits<<2)); - start += (1UL << nbits); - } while (start < end); - preempt_enable(); - ia64_srlz_i(); /* srlz.i implies srlz.d */ -} -EXPORT_SYMBOL(flush_tlb_range); - -void __devinit -ia64_tlb_init (void) -{ - ia64_ptce_info_t uninitialized_var(ptce_info); /* GCC be quiet */ - u64 tr_pgbits; - long status; - pal_vm_info_1_u_t vm_info_1; - pal_vm_info_2_u_t vm_info_2; - int cpu = smp_processor_id(); - - if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) != 0) { - printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with status=%ld; " - "defaulting to architected purge page-sizes.\n", status); - purge.mask = 0x115557000UL; - } - purge.max_bits = ia64_fls(purge.mask); - - ia64_get_ptce(&ptce_info); - local_cpu_data->ptce_base = ptce_info.base; - local_cpu_data->ptce_count[0] = ptce_info.count[0]; - local_cpu_data->ptce_count[1] = ptce_info.count[1]; - local_cpu_data->ptce_stride[0] = ptce_info.stride[0]; - local_cpu_data->ptce_stride[1] = ptce_info.stride[1]; - - local_flush_tlb_all(); /* nuke left overs from bootstrapping... */ - status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2); - - if (status) { - printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status); - per_cpu(ia64_tr_num, cpu) = 8; - return; - } - per_cpu(ia64_tr_num, cpu) = vm_info_1.pal_vm_info_1_s.max_itr_entry+1; - if (per_cpu(ia64_tr_num, cpu) > - (vm_info_1.pal_vm_info_1_s.max_dtr_entry+1)) - per_cpu(ia64_tr_num, cpu) = - vm_info_1.pal_vm_info_1_s.max_dtr_entry+1; - if (per_cpu(ia64_tr_num, cpu) > IA64_TR_ALLOC_MAX) { - static int justonce = 1; - per_cpu(ia64_tr_num, cpu) = IA64_TR_ALLOC_MAX; - if (justonce) { - justonce = 0; - printk(KERN_DEBUG "TR register number exceeds " - "IA64_TR_ALLOC_MAX!\n"); - } - } -} - -/* - * is_tr_overlap - * - * Check overlap with inserted TRs. - */ -static int is_tr_overlap(struct ia64_tr_entry *p, u64 va, u64 log_size) -{ - u64 tr_log_size; - u64 tr_end; - u64 va_rr = ia64_get_rr(va); - u64 va_rid = RR_TO_RID(va_rr); - u64 va_end = va + (1<<log_size) - 1; - - if (va_rid != RR_TO_RID(p->rr)) - return 0; - tr_log_size = (p->itir & 0xff) >> 2; - tr_end = p->ifa + (1<<tr_log_size) - 1; - - if (va > tr_end || p->ifa > va_end) - return 0; - return 1; - -} - -/* - * ia64_insert_tr in virtual mode. Allocate a TR slot - * - * target_mask : 0x1 : itr, 0x2 : dtr, 0x3 : idtr - * - * va : virtual address. - * pte : pte entries inserted. - * log_size: range to be covered. - * - * Return value: <0 : error No. - * - * >=0 : slot number allocated for TR. - * Must be called with preemption disabled. - */ -int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64 log_size) -{ - int i, r; - unsigned long psr; - struct ia64_tr_entry *p; - int cpu = smp_processor_id(); - - if (!ia64_idtrs[cpu]) { - ia64_idtrs[cpu] = kmalloc(2 * IA64_TR_ALLOC_MAX * - sizeof (struct ia64_tr_entry), GFP_KERNEL); - if (!ia64_idtrs[cpu]) - return -ENOMEM; - } - r = -EINVAL; - /*Check overlap with existing TR entries*/ - if (target_mask & 0x1) { - p = ia64_idtrs[cpu]; - for (i = IA64_TR_ALLOC_BASE; i <= per_cpu(ia64_tr_used, cpu); - i++, p++) { - if (p->pte & 0x1) - if (is_tr_overlap(p, va, log_size)) { - printk(KERN_DEBUG "Overlapped Entry" - "Inserted for TR Reigster!!\n"); - goto out; - } - } - } - if (target_mask & 0x2) { - p = ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX; - for (i = IA64_TR_ALLOC_BASE; i <= per_cpu(ia64_tr_used, cpu); - i++, p++) { - if (p->pte & 0x1) - if (is_tr_overlap(p, va, log_size)) { - printk(KERN_DEBUG "Overlapped Entry" - "Inserted for TR Reigster!!\n"); - goto out; - } - } - } - - for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_num, cpu); i++) { - switch (target_mask & 0x3) { - case 1: - if (!((ia64_idtrs[cpu] + i)->pte & 0x1)) - goto found; - continue; - case 2: - if (!((ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + i)->pte & 0x1)) - goto found; - continue; - case 3: - if (!((ia64_idtrs[cpu] + i)->pte & 0x1) && - !((ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + i)->pte & 0x1)) - goto found; - continue; - default: - r = -EINVAL; - goto out; - } - } -found: - if (i >= per_cpu(ia64_tr_num, cpu)) - return -EBUSY; - - /*Record tr info for mca hander use!*/ - if (i > per_cpu(ia64_tr_used, cpu)) - per_cpu(ia64_tr_used, cpu) = i; - - psr = ia64_clear_ic(); - if (target_mask & 0x1) { - ia64_itr(0x1, i, va, pte, log_size); - ia64_srlz_i(); - p = ia64_idtrs[cpu] + i; - p->ifa = va; - p->pte = pte; - p->itir = log_size << 2; - p->rr = ia64_get_rr(va); - } - if (target_mask & 0x2) { - ia64_itr(0x2, i, va, pte, log_size); - ia64_srlz_i(); - p = ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + i; - p->ifa = va; - p->pte = pte; - p->itir = log_size << 2; - p->rr = ia64_get_rr(va); - } - ia64_set_psr(psr); - r = i; -out: - return r; -} -EXPORT_SYMBOL_GPL(ia64_itr_entry); - -/* - * ia64_purge_tr - * - * target_mask: 0x1: purge itr, 0x2 : purge dtr, 0x3 purge idtr. - * slot: slot number to be freed. - * - * Must be called with preemption disabled. - */ -void ia64_ptr_entry(u64 target_mask, int slot) -{ - int cpu = smp_processor_id(); - int i; - struct ia64_tr_entry *p; - - if (slot < IA64_TR_ALLOC_BASE || slot >= per_cpu(ia64_tr_num, cpu)) - return; - - if (target_mask & 0x1) { - p = ia64_idtrs[cpu] + slot; - if ((p->pte&0x1) && is_tr_overlap(p, p->ifa, p->itir>>2)) { - p->pte = 0; - ia64_ptr(0x1, p->ifa, p->itir>>2); - ia64_srlz_i(); - } - } - - if (target_mask & 0x2) { - p = ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + slot; - if ((p->pte & 0x1) && is_tr_overlap(p, p->ifa, p->itir>>2)) { - p->pte = 0; - ia64_ptr(0x2, p->ifa, p->itir>>2); - ia64_srlz_i(); - } - } - - for (i = per_cpu(ia64_tr_used, cpu); i >= IA64_TR_ALLOC_BASE; i--) { - if (((ia64_idtrs[cpu] + i)->pte & 0x1) || - ((ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + i)->pte & 0x1)) - break; - } - per_cpu(ia64_tr_used, cpu) = i; -} -EXPORT_SYMBOL_GPL(ia64_ptr_entry); |