1 /* 2 * This file contains ioremap and related functions for 64-bit machines. 3 * 4 * Derived from arch/ppc64/mm/init.c 5 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 6 * 7 * Modifications by Paul Mackerras (PowerMac) (paulus@samba.org) 8 * and Cort Dougan (PReP) (cort@cs.nmt.edu) 9 * Copyright (C) 1996 Paul Mackerras 10 * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). 11 * 12 * Derived from "arch/i386/mm/init.c" 13 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 14 * 15 * Dave Engebretsen <engebret@us.ibm.com> 16 * Rework for PPC64 port. 17 * 18 * This program is free software; you can redistribute it and/or 19 * modify it under the terms of the GNU General Public License 20 * as published by the Free Software Foundation; either version 21 * 2 of the License, or (at your option) any later version. 22 * 23 */ 24 25 #include <linux/config.h> 26 #include <linux/signal.h> 27 #include <linux/sched.h> 28 #include <linux/kernel.h> 29 #include <linux/errno.h> 30 #include <linux/string.h> 31 #include <linux/types.h> 32 #include <linux/mman.h> 33 #include <linux/mm.h> 34 #include <linux/swap.h> 35 #include <linux/stddef.h> 36 #include <linux/vmalloc.h> 37 #include <linux/init.h> 38 #include <linux/delay.h> 39 #include <linux/bootmem.h> 40 #include <linux/highmem.h> 41 #include <linux/idr.h> 42 #include <linux/nodemask.h> 43 #include <linux/module.h> 44 45 #include <asm/pgalloc.h> 46 #include <asm/page.h> 47 #include <asm/prom.h> 48 #include <asm/lmb.h> 49 #include <asm/rtas.h> 50 #include <asm/io.h> 51 #include <asm/mmu_context.h> 52 #include <asm/pgtable.h> 53 #include <asm/mmu.h> 54 #include <asm/uaccess.h> 55 #include <asm/smp.h> 56 #include <asm/machdep.h> 57 #include <asm/tlb.h> 58 #include <asm/eeh.h> 59 #include <asm/processor.h> 60 #include <asm/mmzone.h> 61 #include <asm/cputable.h> 62 #include <asm/ppcdebug.h> 63 #include <asm/sections.h> 64 #include <asm/system.h> 65 #include <asm/iommu.h> 66 #include <asm/abs_addr.h> 67 #include <asm/vdso.h> 68 #include <asm/imalloc.h> 69 70 unsigned long ioremap_bot = IMALLOC_BASE; 71 static unsigned long phbs_io_bot = PHBS_IO_BASE; 72 73 #ifdef CONFIG_PPC_ISERIES 74 75 void __iomem *ioremap(unsigned long addr, unsigned long size) 76 { 77 return (void __iomem *)addr; 78 } 79 80 extern void __iomem *__ioremap(unsigned long addr, unsigned long size, 81 unsigned long flags) 82 { 83 return (void __iomem *)addr; 84 } 85 86 void iounmap(volatile void __iomem *addr) 87 { 88 return; 89 } 90 91 #else 92 93 /* 94 * map_io_page currently only called by __ioremap 95 * map_io_page adds an entry to the ioremap page table 96 * and adds an entry to the HPT, possibly bolting it 97 */ 98 static int map_io_page(unsigned long ea, unsigned long pa, int flags) 99 { 100 pgd_t *pgdp; 101 pud_t *pudp; 102 pmd_t *pmdp; 103 pte_t *ptep; 104 105 if (mem_init_done) { 106 pgdp = pgd_offset_k(ea); 107 pudp = pud_alloc(&init_mm, pgdp, ea); 108 if (!pudp) 109 return -ENOMEM; 110 pmdp = pmd_alloc(&init_mm, pudp, ea); 111 if (!pmdp) 112 return -ENOMEM; 113 ptep = pte_alloc_kernel(pmdp, ea); 114 if (!ptep) 115 return -ENOMEM; 116 set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT, 117 __pgprot(flags))); 118 } else { 119 /* 120 * If the mm subsystem is not fully up, we cannot create a 121 * linux page table entry for this mapping. Simply bolt an 122 * entry in the hardware page table. 123 * 124 */ 125 if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags, 126 mmu_virtual_psize)) 127 panic("Can't map bolted IO mapping"); 128 } 129 return 0; 130 } 131 132 133 static void __iomem * __ioremap_com(unsigned long addr, unsigned long pa, 134 unsigned long ea, unsigned long size, 135 unsigned long flags) 136 { 137 unsigned long i; 138 139 if ((flags & _PAGE_PRESENT) == 0) 140 flags |= pgprot_val(PAGE_KERNEL); 141 142 for (i = 0; i < size; i += PAGE_SIZE) 143 if (map_io_page(ea+i, pa+i, flags)) 144 return NULL; 145 146 return (void __iomem *) (ea + (addr & ~PAGE_MASK)); 147 } 148 149 150 void __iomem * 151 ioremap(unsigned long addr, unsigned long size) 152 { 153 return __ioremap(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED); 154 } 155 156 void __iomem * __ioremap(unsigned long addr, unsigned long size, 157 unsigned long flags) 158 { 159 unsigned long pa, ea; 160 void __iomem *ret; 161 162 /* 163 * Choose an address to map it to. 164 * Once the imalloc system is running, we use it. 165 * Before that, we map using addresses going 166 * up from ioremap_bot. imalloc will use 167 * the addresses from ioremap_bot through 168 * IMALLOC_END 169 * 170 */ 171 pa = addr & PAGE_MASK; 172 size = PAGE_ALIGN(addr + size) - pa; 173 174 if (size == 0) 175 return NULL; 176 177 if (mem_init_done) { 178 struct vm_struct *area; 179 area = im_get_free_area(size); 180 if (area == NULL) 181 return NULL; 182 ea = (unsigned long)(area->addr); 183 ret = __ioremap_com(addr, pa, ea, size, flags); 184 if (!ret) 185 im_free(area->addr); 186 } else { 187 ea = ioremap_bot; 188 ret = __ioremap_com(addr, pa, ea, size, flags); 189 if (ret) 190 ioremap_bot += size; 191 } 192 return ret; 193 } 194 195 #define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK)) 196 197 int __ioremap_explicit(unsigned long pa, unsigned long ea, 198 unsigned long size, unsigned long flags) 199 { 200 struct vm_struct *area; 201 void __iomem *ret; 202 203 /* For now, require page-aligned values for pa, ea, and size */ 204 if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) || 205 !IS_PAGE_ALIGNED(size)) { 206 printk(KERN_ERR "unaligned value in %s\n", __FUNCTION__); 207 return 1; 208 } 209 210 if (!mem_init_done) { 211 /* Two things to consider in this case: 212 * 1) No records will be kept (imalloc, etc) that the region 213 * has been remapped 214 * 2) It won't be easy to iounmap() the region later (because 215 * of 1) 216 */ 217 ; 218 } else { 219 area = im_get_area(ea, size, 220 IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS); 221 if (area == NULL) { 222 /* Expected when PHB-dlpar is in play */ 223 return 1; 224 } 225 if (ea != (unsigned long) area->addr) { 226 printk(KERN_ERR "unexpected addr return from " 227 "im_get_area\n"); 228 return 1; 229 } 230 } 231 232 ret = __ioremap_com(pa, pa, ea, size, flags); 233 if (ret == NULL) { 234 printk(KERN_ERR "ioremap_explicit() allocation failure !\n"); 235 return 1; 236 } 237 if (ret != (void *) ea) { 238 printk(KERN_ERR "__ioremap_com() returned unexpected addr\n"); 239 return 1; 240 } 241 242 return 0; 243 } 244 245 /* 246 * Unmap an IO region and remove it from imalloc'd list. 247 * Access to IO memory should be serialized by driver. 248 * This code is modeled after vmalloc code - unmap_vm_area() 249 * 250 * XXX what about calls before mem_init_done (ie python_countermeasures()) 251 */ 252 void iounmap(volatile void __iomem *token) 253 { 254 void *addr; 255 256 if (!mem_init_done) 257 return; 258 259 addr = (void *) ((unsigned long __force) token & PAGE_MASK); 260 261 im_free(addr); 262 } 263 264 static int iounmap_subset_regions(unsigned long addr, unsigned long size) 265 { 266 struct vm_struct *area; 267 268 /* Check whether subsets of this region exist */ 269 area = im_get_area(addr, size, IM_REGION_SUPERSET); 270 if (area == NULL) 271 return 1; 272 273 while (area) { 274 iounmap((void __iomem *) area->addr); 275 area = im_get_area(addr, size, 276 IM_REGION_SUPERSET); 277 } 278 279 return 0; 280 } 281 282 int iounmap_explicit(volatile void __iomem *start, unsigned long size) 283 { 284 struct vm_struct *area; 285 unsigned long addr; 286 int rc; 287 288 addr = (unsigned long __force) start & PAGE_MASK; 289 290 /* Verify that the region either exists or is a subset of an existing 291 * region. In the latter case, split the parent region to create 292 * the exact region 293 */ 294 area = im_get_area(addr, size, 295 IM_REGION_EXISTS | IM_REGION_SUBSET); 296 if (area == NULL) { 297 /* Determine whether subset regions exist. If so, unmap */ 298 rc = iounmap_subset_regions(addr, size); 299 if (rc) { 300 printk(KERN_ERR 301 "%s() cannot unmap nonexistent range 0x%lx\n", 302 __FUNCTION__, addr); 303 return 1; 304 } 305 } else { 306 iounmap((void __iomem *) area->addr); 307 } 308 /* 309 * FIXME! This can't be right: 310 iounmap(area->addr); 311 * Maybe it should be "iounmap(area);" 312 */ 313 return 0; 314 } 315 316 #endif 317 318 EXPORT_SYMBOL(ioremap); 319 EXPORT_SYMBOL(__ioremap); 320 EXPORT_SYMBOL(iounmap); 321 322 void __iomem * reserve_phb_iospace(unsigned long size) 323 { 324 void __iomem *virt_addr; 325 326 if (phbs_io_bot >= IMALLOC_BASE) 327 panic("reserve_phb_iospace(): phb io space overflow\n"); 328 329 virt_addr = (void __iomem *) phbs_io_bot; 330 phbs_io_bot += size; 331 332 return virt_addr; 333 } 334