diff options
Diffstat (limited to 'arch/tile/mm/pgtable.c')
| -rw-r--r-- | arch/tile/mm/pgtable.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c new file mode 100644 index 000000000000..28c23140c947 --- /dev/null +++ b/arch/tile/mm/pgtable.c | |||
| @@ -0,0 +1,530 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2010 Tilera Corporation. All Rights Reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation, version 2. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, but | ||
| 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/sched.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/errno.h> | ||
| 18 | #include <linux/mm.h> | ||
| 19 | #include <linux/swap.h> | ||
| 20 | #include <linux/smp.h> | ||
| 21 | #include <linux/highmem.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/pagemap.h> | ||
| 24 | #include <linux/spinlock.h> | ||
| 25 | #include <linux/cpumask.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/io.h> | ||
| 28 | #include <linux/vmalloc.h> | ||
| 29 | #include <linux/smp.h> | ||
| 30 | |||
| 31 | #include <asm/system.h> | ||
| 32 | #include <asm/pgtable.h> | ||
| 33 | #include <asm/pgalloc.h> | ||
| 34 | #include <asm/fixmap.h> | ||
| 35 | #include <asm/tlb.h> | ||
| 36 | #include <asm/tlbflush.h> | ||
| 37 | #include <asm/homecache.h> | ||
| 38 | |||
| 39 | #define K(x) ((x) << (PAGE_SHIFT-10)) | ||
| 40 | |||
| 41 | /* | ||
| 42 | * The normal show_free_areas() is too verbose on Tile, with dozens | ||
| 43 | * of processors and often four NUMA zones each with high and lowmem. | ||
| 44 | */ | ||
| 45 | void show_mem(void) | ||
| 46 | { | ||
| 47 | struct zone *zone; | ||
| 48 | |||
| 49 | pr_err("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu" | ||
| 50 | " free:%lu\n slab:%lu mapped:%lu pagetables:%lu bounce:%lu" | ||
| 51 | " pagecache:%lu swap:%lu\n", | ||
| 52 | (global_page_state(NR_ACTIVE_ANON) + | ||
| 53 | global_page_state(NR_ACTIVE_FILE)), | ||
| 54 | (global_page_state(NR_INACTIVE_ANON) + | ||
| 55 | global_page_state(NR_INACTIVE_FILE)), | ||
| 56 | global_page_state(NR_FILE_DIRTY), | ||
| 57 | global_page_state(NR_WRITEBACK), | ||
| 58 | global_page_state(NR_UNSTABLE_NFS), | ||
| 59 | global_page_state(NR_FREE_PAGES), | ||
| 60 | (global_page_state(NR_SLAB_RECLAIMABLE) + | ||
| 61 | global_page_state(NR_SLAB_UNRECLAIMABLE)), | ||
| 62 | global_page_state(NR_FILE_MAPPED), | ||
| 63 | global_page_state(NR_PAGETABLE), | ||
| 64 | global_page_state(NR_BOUNCE), | ||
| 65 | global_page_state(NR_FILE_PAGES), | ||
| 66 | nr_swap_pages); | ||
| 67 | |||
| 68 | for_each_zone(zone) { | ||
| 69 | unsigned long flags, order, total = 0, largest_order = -1; | ||
| 70 | |||
| 71 | if (!populated_zone(zone)) | ||
| 72 | continue; | ||
| 73 | |||
| 74 | spin_lock_irqsave(&zone->lock, flags); | ||
| 75 | for (order = 0; order < MAX_ORDER; order++) { | ||
| 76 | int nr = zone->free_area[order].nr_free; | ||
| 77 | total += nr << order; | ||
| 78 | if (nr) | ||
| 79 | largest_order = order; | ||
| 80 | } | ||
| 81 | spin_unlock_irqrestore(&zone->lock, flags); | ||
| 82 | pr_err("Node %d %7s: %lukB (largest %luKb)\n", | ||
| 83 | zone_to_nid(zone), zone->name, | ||
| 84 | K(total), largest_order ? K(1UL) << largest_order : 0); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Associate a virtual page frame with a given physical page frame | ||
| 90 | * and protection flags for that frame. | ||
| 91 | */ | ||
| 92 | static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) | ||
| 93 | { | ||
| 94 | pgd_t *pgd; | ||
| 95 | pud_t *pud; | ||
| 96 | pmd_t *pmd; | ||
| 97 | pte_t *pte; | ||
| 98 | |||
| 99 | pgd = swapper_pg_dir + pgd_index(vaddr); | ||
| 100 | if (pgd_none(*pgd)) { | ||
| 101 | BUG(); | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | pud = pud_offset(pgd, vaddr); | ||
| 105 | if (pud_none(*pud)) { | ||
| 106 | BUG(); | ||
| 107 | return; | ||
| 108 | } | ||
| 109 | pmd = pmd_offset(pud, vaddr); | ||
| 110 | if (pmd_none(*pmd)) { | ||
| 111 | BUG(); | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | pte = pte_offset_kernel(pmd, vaddr); | ||
| 115 | /* <pfn,flags> stored as-is, to permit clearing entries */ | ||
| 116 | set_pte(pte, pfn_pte(pfn, flags)); | ||
| 117 | |||
| 118 | /* | ||
| 119 | * It's enough to flush this one mapping. | ||
| 120 | * This appears conservative since it is only called | ||
| 121 | * from __set_fixmap. | ||
| 122 | */ | ||
| 123 | local_flush_tlb_page(NULL, vaddr, PAGE_SIZE); | ||
| 124 | } | ||
| 125 | |||
| 126 | void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags) | ||
| 127 | { | ||
| 128 | unsigned long address = __fix_to_virt(idx); | ||
| 129 | |||
| 130 | if (idx >= __end_of_fixed_addresses) { | ||
| 131 | BUG(); | ||
| 132 | return; | ||
| 133 | } | ||
| 134 | set_pte_pfn(address, phys >> PAGE_SHIFT, flags); | ||
| 135 | } | ||
| 136 | |||
| 137 | #if defined(CONFIG_HIGHPTE) | ||
| 138 | pte_t *_pte_offset_map(pmd_t *dir, unsigned long address, enum km_type type) | ||
| 139 | { | ||
| 140 | pte_t *pte = kmap_atomic(pmd_page(*dir), type) + | ||
| 141 | (pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK; | ||
| 142 | return &pte[pte_index(address)]; | ||
| 143 | } | ||
| 144 | #endif | ||
| 145 | |||
| 146 | /* | ||
| 147 | * List of all pgd's needed so it can invalidate entries in both cached | ||
| 148 | * and uncached pgd's. This is essentially codepath-based locking | ||
| 149 | * against pageattr.c; it is the unique case in which a valid change | ||
| 150 | * of kernel pagetables can't be lazily synchronized by vmalloc faults. | ||
| 151 | * vmalloc faults work because attached pagetables are never freed. | ||
| 152 | * The locking scheme was chosen on the basis of manfred's | ||
| 153 | * recommendations and having no core impact whatsoever. | ||
| 154 | * -- wli | ||
| 155 | */ | ||
| 156 | DEFINE_SPINLOCK(pgd_lock); | ||
| 157 | LIST_HEAD(pgd_list); | ||
| 158 | |||
| 159 | static inline void pgd_list_add(pgd_t *pgd) | ||
| 160 | { | ||
| 161 | list_add(pgd_to_list(pgd), &pgd_list); | ||
| 162 | } | ||
| 163 | |||
| 164 | static inline void pgd_list_del(pgd_t *pgd) | ||
| 165 | { | ||
| 166 | list_del(pgd_to_list(pgd)); | ||
| 167 | } | ||
| 168 | |||
| 169 | #define KERNEL_PGD_INDEX_START pgd_index(PAGE_OFFSET) | ||
| 170 | #define KERNEL_PGD_PTRS (PTRS_PER_PGD - KERNEL_PGD_INDEX_START) | ||
| 171 | |||
| 172 | static void pgd_ctor(pgd_t *pgd) | ||
| 173 | { | ||
| 174 | unsigned long flags; | ||
| 175 | |||
| 176 | memset(pgd, 0, KERNEL_PGD_INDEX_START*sizeof(pgd_t)); | ||
| 177 | spin_lock_irqsave(&pgd_lock, flags); | ||
| 178 | |||
| 179 | #ifndef __tilegx__ | ||
| 180 | /* | ||
| 181 | * Check that the user interrupt vector has no L2. | ||
| 182 | * It never should for the swapper, and new page tables | ||
| 183 | * should always start with an empty user interrupt vector. | ||
| 184 | */ | ||
| 185 | BUG_ON(((u64 *)swapper_pg_dir)[pgd_index(MEM_USER_INTRPT)] != 0); | ||
| 186 | #endif | ||
| 187 | |||
| 188 | clone_pgd_range(pgd + KERNEL_PGD_INDEX_START, | ||
| 189 | swapper_pg_dir + KERNEL_PGD_INDEX_START, | ||
| 190 | KERNEL_PGD_PTRS); | ||
| 191 | |||
| 192 | pgd_list_add(pgd); | ||
| 193 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
| 194 | } | ||
| 195 | |||
| 196 | static void pgd_dtor(pgd_t *pgd) | ||
| 197 | { | ||
| 198 | unsigned long flags; /* can be called from interrupt context */ | ||
| 199 | |||
| 200 | spin_lock_irqsave(&pgd_lock, flags); | ||
| 201 | pgd_list_del(pgd); | ||
| 202 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
| 203 | } | ||
| 204 | |||
| 205 | pgd_t *pgd_alloc(struct mm_struct *mm) | ||
| 206 | { | ||
| 207 | pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL); | ||
| 208 | if (pgd) | ||
| 209 | pgd_ctor(pgd); | ||
| 210 | return pgd; | ||
| 211 | } | ||
| 212 | |||
| 213 | void pgd_free(struct mm_struct *mm, pgd_t *pgd) | ||
| 214 | { | ||
| 215 | pgd_dtor(pgd); | ||
| 216 | kmem_cache_free(pgd_cache, pgd); | ||
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | #define L2_USER_PGTABLE_PAGES (1 << L2_USER_PGTABLE_ORDER) | ||
| 221 | |||
| 222 | struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) | ||
| 223 | { | ||
| 224 | gfp_t flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO|__GFP_COMP; | ||
| 225 | struct page *p; | ||
| 226 | |||
| 227 | #ifdef CONFIG_HIGHPTE | ||
| 228 | flags |= __GFP_HIGHMEM; | ||
| 229 | #endif | ||
| 230 | |||
| 231 | p = alloc_pages(flags, L2_USER_PGTABLE_ORDER); | ||
| 232 | if (p == NULL) | ||
| 233 | return NULL; | ||
| 234 | |||
| 235 | pgtable_page_ctor(p); | ||
| 236 | return p; | ||
| 237 | } | ||
| 238 | |||
| 239 | /* | ||
| 240 | * Free page immediately (used in __pte_alloc if we raced with another | ||
| 241 | * process). We have to correct whatever pte_alloc_one() did before | ||
| 242 | * returning the pages to the allocator. | ||
| 243 | */ | ||
| 244 | void pte_free(struct mm_struct *mm, struct page *p) | ||
| 245 | { | ||
| 246 | pgtable_page_dtor(p); | ||
| 247 | __free_pages(p, L2_USER_PGTABLE_ORDER); | ||
| 248 | } | ||
| 249 | |||
| 250 | void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte, | ||
| 251 | unsigned long address) | ||
| 252 | { | ||
| 253 | int i; | ||
| 254 | |||
| 255 | pgtable_page_dtor(pte); | ||
| 256 | tlb->need_flush = 1; | ||
| 257 | if (tlb_fast_mode(tlb)) { | ||
| 258 | struct page *pte_pages[L2_USER_PGTABLE_PAGES]; | ||
| 259 | for (i = 0; i < L2_USER_PGTABLE_PAGES; ++i) | ||
| 260 | pte_pages[i] = pte + i; | ||
| 261 | free_pages_and_swap_cache(pte_pages, L2_USER_PGTABLE_PAGES); | ||
| 262 | return; | ||
| 263 | } | ||
| 264 | for (i = 0; i < L2_USER_PGTABLE_PAGES; ++i) { | ||
| 265 | tlb->pages[tlb->nr++] = pte + i; | ||
| 266 | if (tlb->nr >= FREE_PTE_NR) | ||
| 267 | tlb_flush_mmu(tlb, 0, 0); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | #ifndef __tilegx__ | ||
| 272 | |||
| 273 | /* | ||
| 274 | * FIXME: needs to be atomic vs hypervisor writes. For now we make the | ||
| 275 | * window of vulnerability a bit smaller by doing an unlocked 8-bit update. | ||
| 276 | */ | ||
| 277 | int ptep_test_and_clear_young(struct vm_area_struct *vma, | ||
| 278 | unsigned long addr, pte_t *ptep) | ||
| 279 | { | ||
| 280 | #if HV_PTE_INDEX_ACCESSED < 8 || HV_PTE_INDEX_ACCESSED >= 16 | ||
| 281 | # error Code assumes HV_PTE "accessed" bit in second byte | ||
| 282 | #endif | ||
| 283 | u8 *tmp = (u8 *)ptep; | ||
| 284 | u8 second_byte = tmp[1]; | ||
| 285 | if (!(second_byte & (1 << (HV_PTE_INDEX_ACCESSED - 8)))) | ||
| 286 | return 0; | ||
| 287 | tmp[1] = second_byte & ~(1 << (HV_PTE_INDEX_ACCESSED - 8)); | ||
| 288 | return 1; | ||
| 289 | } | ||
| 290 | |||
| 291 | /* | ||
| 292 | * This implementation is atomic vs hypervisor writes, since the hypervisor | ||
| 293 | * always writes the low word (where "accessed" and "dirty" are) and this | ||
| 294 | * routine only writes the high word. | ||
| 295 | */ | ||
| 296 | void ptep_set_wrprotect(struct mm_struct *mm, | ||
| 297 | unsigned long addr, pte_t *ptep) | ||
| 298 | { | ||
| 299 | #if HV_PTE_INDEX_WRITABLE < 32 | ||
| 300 | # error Code assumes HV_PTE "writable" bit in high word | ||
| 301 | #endif | ||
| 302 | u32 *tmp = (u32 *)ptep; | ||
| 303 | tmp[1] = tmp[1] & ~(1 << (HV_PTE_INDEX_WRITABLE - 32)); | ||
| 304 | } | ||
| 305 | |||
| 306 | #endif | ||
| 307 | |||
| 308 | pte_t *virt_to_pte(struct mm_struct* mm, unsigned long addr) | ||
| 309 | { | ||
| 310 | pgd_t *pgd; | ||
| 311 | pud_t *pud; | ||
| 312 | pmd_t *pmd; | ||
| 313 | |||
| 314 | if (pgd_addr_invalid(addr)) | ||
| 315 | return NULL; | ||
| 316 | |||
| 317 | pgd = mm ? pgd_offset(mm, addr) : swapper_pg_dir + pgd_index(addr); | ||
| 318 | pud = pud_offset(pgd, addr); | ||
| 319 | if (!pud_present(*pud)) | ||
| 320 | return NULL; | ||
| 321 | pmd = pmd_offset(pud, addr); | ||
| 322 | if (pmd_huge_page(*pmd)) | ||
| 323 | return (pte_t *)pmd; | ||
| 324 | if (!pmd_present(*pmd)) | ||
| 325 | return NULL; | ||
| 326 | return pte_offset_kernel(pmd, addr); | ||
| 327 | } | ||
| 328 | |||
| 329 | pgprot_t set_remote_cache_cpu(pgprot_t prot, int cpu) | ||
| 330 | { | ||
| 331 | unsigned int width = smp_width; | ||
| 332 | int x = cpu % width; | ||
| 333 | int y = cpu / width; | ||
| 334 | BUG_ON(y >= smp_height); | ||
| 335 | BUG_ON(hv_pte_get_mode(prot) != HV_PTE_MODE_CACHE_TILE_L3); | ||
| 336 | BUG_ON(cpu < 0 || cpu >= NR_CPUS); | ||
| 337 | BUG_ON(!cpu_is_valid_lotar(cpu)); | ||
| 338 | return hv_pte_set_lotar(prot, HV_XY_TO_LOTAR(x, y)); | ||
| 339 | } | ||
| 340 | |||
| 341 | int get_remote_cache_cpu(pgprot_t prot) | ||
| 342 | { | ||
| 343 | HV_LOTAR lotar = hv_pte_get_lotar(prot); | ||
| 344 | int x = HV_LOTAR_X(lotar); | ||
| 345 | int y = HV_LOTAR_Y(lotar); | ||
| 346 | BUG_ON(hv_pte_get_mode(prot) != HV_PTE_MODE_CACHE_TILE_L3); | ||
| 347 | return x + y * smp_width; | ||
| 348 | } | ||
| 349 | |||
| 350 | void set_pte_order(pte_t *ptep, pte_t pte, int order) | ||
| 351 | { | ||
| 352 | unsigned long pfn = pte_pfn(pte); | ||
| 353 | struct page *page = pfn_to_page(pfn); | ||
| 354 | |||
| 355 | /* Update the home of a PTE if necessary */ | ||
| 356 | pte = pte_set_home(pte, page_home(page)); | ||
| 357 | |||
| 358 | #ifdef __tilegx__ | ||
| 359 | *ptep = pte; | ||
| 360 | #else | ||
| 361 | /* | ||
| 362 | * When setting a PTE, write the high bits first, then write | ||
| 363 | * the low bits. This sets the "present" bit only after the | ||
| 364 | * other bits are in place. If a particular PTE update | ||
| 365 | * involves transitioning from one valid PTE to another, it | ||
| 366 | * may be necessary to call set_pte_order() more than once, | ||
| 367 | * transitioning via a suitable intermediate state. | ||
| 368 | * Note that this sequence also means that if we are transitioning | ||
| 369 | * from any migrating PTE to a non-migrating one, we will not | ||
| 370 | * see a half-updated PTE with the migrating bit off. | ||
| 371 | */ | ||
| 372 | #if HV_PTE_INDEX_PRESENT >= 32 || HV_PTE_INDEX_MIGRATING >= 32 | ||
| 373 | # error Must write the present and migrating bits last | ||
| 374 | #endif | ||
| 375 | ((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32); | ||
| 376 | barrier(); | ||
| 377 | ((u32 *)ptep)[0] = (u32)(pte_val(pte)); | ||
| 378 | #endif | ||
| 379 | } | ||
| 380 | |||
| 381 | /* Can this mm load a PTE with cached_priority set? */ | ||
| 382 | static inline int mm_is_priority_cached(struct mm_struct *mm) | ||
| 383 | { | ||
| 384 | return mm->context.priority_cached; | ||
| 385 | } | ||
| 386 | |||
| 387 | /* | ||
| 388 | * Add a priority mapping to an mm_context and | ||
| 389 | * notify the hypervisor if this is the first one. | ||
| 390 | */ | ||
| 391 | void start_mm_caching(struct mm_struct *mm) | ||
| 392 | { | ||
| 393 | if (!mm_is_priority_cached(mm)) { | ||
| 394 | mm->context.priority_cached = -1U; | ||
| 395 | hv_set_caching(-1U); | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | /* | ||
| 400 | * Validate and return the priority_cached flag. We know if it's zero | ||
| 401 | * that we don't need to scan, since we immediately set it non-zero | ||
| 402 | * when we first consider a MAP_CACHE_PRIORITY mapping. | ||
| 403 | * | ||
| 404 | * We only _try_ to acquire the mmap_sem semaphore; if we can't acquire it, | ||
| 405 | * since we're in an interrupt context (servicing switch_mm) we don't | ||
| 406 | * worry about it and don't unset the "priority_cached" field. | ||
| 407 | * Presumably we'll come back later and have more luck and clear | ||
| 408 | * the value then; for now we'll just keep the cache marked for priority. | ||
| 409 | */ | ||
| 410 | static unsigned int update_priority_cached(struct mm_struct *mm) | ||
| 411 | { | ||
| 412 | if (mm->context.priority_cached && down_write_trylock(&mm->mmap_sem)) { | ||
| 413 | struct vm_area_struct *vm; | ||
| 414 | for (vm = mm->mmap; vm; vm = vm->vm_next) { | ||
| 415 | if (hv_pte_get_cached_priority(vm->vm_page_prot)) | ||
| 416 | break; | ||
| 417 | } | ||
| 418 | if (vm == NULL) | ||
| 419 | mm->context.priority_cached = 0; | ||
| 420 | up_write(&mm->mmap_sem); | ||
| 421 | } | ||
| 422 | return mm->context.priority_cached; | ||
| 423 | } | ||
| 424 | |||
| 425 | /* Set caching correctly for an mm that we are switching to. */ | ||
| 426 | void check_mm_caching(struct mm_struct *prev, struct mm_struct *next) | ||
| 427 | { | ||
| 428 | if (!mm_is_priority_cached(next)) { | ||
| 429 | /* | ||
| 430 | * If the new mm doesn't use priority caching, just see if we | ||
| 431 | * need the hv_set_caching(), or can assume it's already zero. | ||
| 432 | */ | ||
| 433 | if (mm_is_priority_cached(prev)) | ||
| 434 | hv_set_caching(0); | ||
| 435 | } else { | ||
| 436 | hv_set_caching(update_priority_cached(next)); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | #if CHIP_HAS_MMIO() | ||
| 441 | |||
| 442 | /* Map an arbitrary MMIO address, homed according to pgprot, into VA space. */ | ||
| 443 | void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size, | ||
| 444 | pgprot_t home) | ||
| 445 | { | ||
| 446 | void *addr; | ||
| 447 | struct vm_struct *area; | ||
| 448 | unsigned long offset, last_addr; | ||
| 449 | pgprot_t pgprot; | ||
| 450 | |||
| 451 | /* Don't allow wraparound or zero size */ | ||
| 452 | last_addr = phys_addr + size - 1; | ||
| 453 | if (!size || last_addr < phys_addr) | ||
| 454 | return NULL; | ||
| 455 | |||
| 456 | /* Create a read/write, MMIO VA mapping homed at the requested shim. */ | ||
| 457 | pgprot = PAGE_KERNEL; | ||
| 458 | pgprot = hv_pte_set_mode(pgprot, HV_PTE_MODE_MMIO); | ||
| 459 | pgprot = hv_pte_set_lotar(pgprot, hv_pte_get_lotar(home)); | ||
| 460 | |||
| 461 | /* | ||
| 462 | * Mappings have to be page-aligned | ||
| 463 | */ | ||
| 464 | offset = phys_addr & ~PAGE_MASK; | ||
| 465 | phys_addr &= PAGE_MASK; | ||
| 466 | size = PAGE_ALIGN(last_addr+1) - phys_addr; | ||
| 467 | |||
| 468 | /* | ||
| 469 | * Ok, go for it.. | ||
| 470 | */ | ||
| 471 | area = get_vm_area(size, VM_IOREMAP /* | other flags? */); | ||
| 472 | if (!area) | ||
| 473 | return NULL; | ||
| 474 | area->phys_addr = phys_addr; | ||
| 475 | addr = area->addr; | ||
| 476 | if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, | ||
| 477 | phys_addr, pgprot)) { | ||
| 478 | remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr)); | ||
| 479 | return NULL; | ||
| 480 | } | ||
| 481 | return (__force void __iomem *) (offset + (char *)addr); | ||
| 482 | } | ||
| 483 | EXPORT_SYMBOL(ioremap_prot); | ||
| 484 | |||
| 485 | /* Map a PCI MMIO bus address into VA space. */ | ||
| 486 | void __iomem *ioremap(resource_size_t phys_addr, unsigned long size) | ||
| 487 | { | ||
| 488 | panic("ioremap for PCI MMIO is not supported"); | ||
| 489 | } | ||
| 490 | EXPORT_SYMBOL(ioremap); | ||
| 491 | |||
| 492 | /* Unmap an MMIO VA mapping. */ | ||
| 493 | void iounmap(volatile void __iomem *addr_in) | ||
| 494 | { | ||
| 495 | volatile void __iomem *addr = (volatile void __iomem *) | ||
| 496 | (PAGE_MASK & (unsigned long __force)addr_in); | ||
| 497 | #if 1 | ||
| 498 | vunmap((void * __force)addr); | ||
| 499 | #else | ||
| 500 | /* x86 uses this complicated flow instead of vunmap(). Is | ||
| 501 | * there any particular reason we should do the same? */ | ||
| 502 | struct vm_struct *p, *o; | ||
| 503 | |||
| 504 | /* Use the vm area unlocked, assuming the caller | ||
| 505 | ensures there isn't another iounmap for the same address | ||
| 506 | in parallel. Reuse of the virtual address is prevented by | ||
| 507 | leaving it in the global lists until we're done with it. | ||
| 508 | cpa takes care of the direct mappings. */ | ||
| 509 | read_lock(&vmlist_lock); | ||
| 510 | for (p = vmlist; p; p = p->next) { | ||
| 511 | if (p->addr == addr) | ||
| 512 | break; | ||
| 513 | } | ||
| 514 | read_unlock(&vmlist_lock); | ||
| 515 | |||
| 516 | if (!p) { | ||
| 517 | pr_err("iounmap: bad address %p\n", addr); | ||
| 518 | dump_stack(); | ||
| 519 | return; | ||
| 520 | } | ||
| 521 | |||
| 522 | /* Finally remove it */ | ||
| 523 | o = remove_vm_area((void *)addr); | ||
| 524 | BUG_ON(p != o || o == NULL); | ||
| 525 | kfree(p); | ||
| 526 | #endif | ||
| 527 | } | ||
| 528 | EXPORT_SYMBOL(iounmap); | ||
| 529 | |||
| 530 | #endif /* CHIP_HAS_MMIO() */ | ||
