1 /* $NetBSD: sun3x.c,v 1.12 2009/12/11 18:45:05 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jeremy Cooper and Gordon Ross 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Standalone functions specific to the Sun3X. 34 */ 35 36 #define _SUN3X_ XXX 37 38 /* Avoid conflicts on these: */ 39 #define get_pte sun3x_get_pte 40 #define set_pte sun3x_set_pte 41 42 #include <sys/param.h> 43 #include <machine/mon.h> 44 45 #include <stand.h> 46 47 #include "libsa.h" 48 #include "dvma.h" 49 #include "saio.h" /* enum MAPTYPES */ 50 51 #include <arch/sun3/include/pte3x.h> 52 #include <arch/sun3/sun3x/iommu.h> 53 #include <arch/sun3/sun3x/vme.h> 54 55 /* Names, names... */ 56 #define MON_LOMEM_BASE 0 57 #define MON_LOMEM_SIZE 0x400000 58 #define MON_LOMEM_END (MON_LOMEM_BASE+MON_LOMEM_SIZE) 59 #define MON_KDB_BASE SUN3X_MON_KDB_BASE 60 #define MON_KDB_SIZE SUN3X_MON_KDB_SIZE 61 #define MON_KDB_END (MON_KDB_BASE+MON_KDB_SIZE) 62 #define MON_DVMA_BASE SUN3X_MON_DVMA_BASE 63 #define MON_DVMA_SIZE SUN3X_MON_DVMA_SIZE 64 65 void mmu_atc_flush(vaddr_t); 66 void set_iommupte(vaddr_t, paddr_t); 67 68 u_int get_pte(vaddr_t); 69 void set_pte(vaddr_t, paddr_t); 70 void dvma3x_init(void); 71 char * dvma3x_alloc(int); 72 void dvma3x_free(char *, int); 73 char * dvma3x_mapin(char *, int); 74 void dvma3x_mapout(char *, int); 75 char * dev3x_mapin(int, u_long, int); 76 77 struct mapinfo { 78 int maptype; 79 u_int base; 80 u_int mask; 81 }; 82 83 struct mapinfo 84 sun3x_mapinfo[MAP__NTYPES] = { 85 /* On-board memory, I/O */ 86 { MAP_MAINMEM, 0, ~0 }, 87 { MAP_OBIO, 0, ~0 }, 88 /* Multibus adapter (A24,A16) */ 89 { MAP_MBMEM, VME24D16_BASE, VME24_MASK }, 90 { MAP_MBIO, VME16D16_BASE, VME16_MASK }, 91 /* VME A16 */ 92 { MAP_VME16A16D, VME16D16_BASE, VME16_MASK }, 93 { MAP_VME16A32D, VME16D32_BASE, VME16_MASK }, 94 /* VME A24 */ 95 { MAP_VME24A16D, VME24D16_BASE, VME24_MASK }, 96 { MAP_VME24A32D, VME24D32_BASE, VME24_MASK }, 97 /* VME A32 */ 98 { MAP_VME32A16D, VME32D16_BASE, VME32_MASK }, 99 { MAP_VME32A32D, VME32D32_BASE, VME32_MASK }, 100 }; 101 102 /* The virtual address we will use for PROM device mappings. */ 103 u_int sun3x_devmap = MON_KDB_BASE; 104 105 char * 106 dev3x_mapin(int maptype, u_long physaddr, int length) 107 { 108 u_int i, pa, pte, pgva, va; 109 110 if ((sun3x_devmap + length) > (MON_KDB_BASE + MON_KDB_SIZE)) 111 panic("dev3x_mapin: length=%d", length); 112 113 for (i = 0; i < MAP__NTYPES; i++) 114 if (sun3x_mapinfo[i].maptype == maptype) 115 goto found; 116 panic("dev3x_mapin: bad maptype"); 117 found: 118 119 if (physaddr & ~(sun3x_mapinfo[i].mask)) 120 panic("dev3x_mapin: bad address"); 121 pa = sun3x_mapinfo[i].base + physaddr; 122 123 pte = pa | MMU_DT_PAGE | MMU_SHORT_PTE_CI; 124 125 va = pgva = sun3x_devmap; 126 do { 127 set_pte(pgva, pte); 128 pgva += NBPG; 129 pte += NBPG; 130 length -= NBPG; 131 } while (length > 0); 132 sun3x_devmap = pgva; 133 va += (physaddr & PGOFSET); 134 135 #ifdef DEBUG_PROM 136 if (debug) 137 printf("dev3x_mapin: va=0x%x pte=0x%x\n", 138 va, get_pte(va)); 139 #endif 140 return ((char*)va); 141 } 142 143 /***************************************************************** 144 * DVMA support 145 */ 146 147 #define SA_MIN_VA 0x200000 148 #define SA_MAX_VA (SA_MIN_VA + MON_DVMA_SIZE - (8 * NBPG)) 149 150 #define MON_DVMA_MAPLEN (MON_DVMA_SIZE - NBPG) 151 152 /* This points to the end of the free DVMA space. */ 153 u_int dvma3x_end = MON_DVMA_BASE + MON_DVMA_MAPLEN; 154 155 void 156 dvma3x_init(void) 157 { 158 u_int va, pa; 159 160 pa = SA_MIN_VA; 161 va = MON_DVMA_BASE; 162 163 while (pa < SA_MAX_VA) { 164 set_pte(va, pa | MMU_DT_PAGE | MMU_SHORT_PTE_CI); 165 set_iommupte(va, pa | IOMMU_PDE_DT_VALID | IOMMU_PDE_CI); 166 va += NBPG; 167 pa += NBPG; 168 } 169 } 170 171 /* Convert a local address to a DVMA address. */ 172 char * 173 dvma3x_mapin(char *addr, int len) 174 { 175 int va = (int)addr; 176 177 /* Make sure the address is in the DVMA map. */ 178 if ((va < SA_MIN_VA) || (va >= SA_MAX_VA)) 179 panic("dvma3x_mapin"); 180 181 va -= SA_MIN_VA; 182 va += MON_DVMA_BASE; 183 184 return ((char *) va); 185 } 186 187 /* Convert a DVMA address to a local address. */ 188 void 189 dvma3x_mapout(char *addr, int len) 190 { 191 int va = (int)addr; 192 193 /* Make sure the address is in the DVMA map. */ 194 if ((va < MON_DVMA_BASE) || 195 (va >= (MON_DVMA_BASE + MON_DVMA_MAPLEN))) 196 panic("dvma3x_mapout"); 197 } 198 199 char * 200 dvma3x_alloc(int len) 201 { 202 len = m68k_round_page(len); 203 dvma3x_end -= len; 204 return((char *)dvma3x_end); 205 } 206 207 void 208 dvma3x_free(char *dvma, int len) 209 { 210 /* not worth the trouble */ 211 } 212 213 /***************************************************************** 214 * MMU (and I/O MMU) support 215 */ 216 217 u_int 218 get_pte(vaddr_t va) 219 { 220 u_int pn; 221 mmu_short_pte_t *tbl; 222 223 if (va >= MON_LOMEM_BASE && va < MON_LOMEM_END) { 224 tbl = (mmu_short_pte_t *) *romVectorPtr->lomemptaddr; 225 } else if (va >= MON_KDB_BASE && va < MON_KDB_END) { 226 va -= MON_KDB_BASE; 227 tbl = (mmu_short_pte_t *) *romVectorPtr->monptaddr; 228 } else if (va >= MON_DVMA_BASE) { 229 va -= MON_DVMA_BASE; 230 tbl = (mmu_short_pte_t *) *romVectorPtr->shadowpteaddr; 231 } else { 232 return 0; 233 } 234 235 /* Calculate the page number within the selected table. */ 236 pn = (va >> MMU_PAGE_SHIFT); 237 /* Extract the PTE from the table. */ 238 return tbl[pn].attr.raw; 239 } 240 241 void 242 set_pte(vaddr_t va, paddr_t pa) 243 { 244 u_int pn; 245 mmu_short_pte_t *tbl; 246 247 if (va >= MON_LOMEM_BASE && va < (MON_LOMEM_BASE + MON_LOMEM_SIZE)) { 248 /* 249 * Main memory range. 250 */ 251 tbl = (mmu_short_pte_t *) *romVectorPtr->lomemptaddr; 252 } else if (va >= MON_KDB_BASE && va < (MON_KDB_BASE + MON_KDB_SIZE)) { 253 /* 254 * Kernel Debugger range. 255 */ 256 va -= MON_KDB_BASE; 257 tbl = (mmu_short_pte_t *) *romVectorPtr->monptaddr; 258 } else if (va >= MON_DVMA_BASE) { 259 /* 260 * DVMA range. 261 */ 262 va -= MON_DVMA_BASE; 263 tbl = (mmu_short_pte_t *) *romVectorPtr->shadowpteaddr; 264 } else { 265 /* invalid range */ 266 return; 267 } 268 269 /* Calculate the page number within the selected table. */ 270 pn = (va >> MMU_PAGE_SHIFT); 271 /* Enter the PTE into the table. */ 272 tbl[pn].attr.raw = pa; 273 /* Flush the ATC of any cached entries for the va. */ 274 mmu_atc_flush(va); 275 } 276 277 void 278 mmu_atc_flush(vaddr_t va) 279 { 280 281 __asm volatile ("pflush #0,#0,%0@" : : "a" (va)); 282 } 283 284 void 285 set_iommupte(vaddr_t va, paddr_t pa) 286 { 287 iommu_pde_t *iommu_va; 288 int pn; 289 290 iommu_va = (iommu_pde_t *) *romVectorPtr->dvmaptaddr; 291 292 /* Adjust the virtual address into an offset within the DVMA map. */ 293 va -= MON_DVMA_BASE; 294 295 /* Convert the slave address into a page index. */ 296 pn = IOMMU_BTOP(va); 297 298 iommu_va[pn].addr.raw = pa; 299 } 300 301 /***************************************************************** 302 * Init our function pointers, etc. 303 */ 304 305 void 306 sun3x_init(void) 307 { 308 309 /* Set the function pointers. */ 310 dev_mapin_p = dev3x_mapin; 311 dvma_alloc_p = dvma3x_alloc; 312 dvma_free_p = dvma3x_free; 313 dvma_mapin_p = dvma3x_mapin; 314 dvma_mapout_p = dvma3x_mapout; 315 316 dvma3x_init(); 317 } 318