1 /* $NetBSD: sun3x.c,v 1.14 2020/06/20 18:46:14 riastradh 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 #include <sys/param.h> 39 #include <machine/mon.h> 40 41 #include <stand.h> 42 43 #include "libsa.h" 44 #include "dvma.h" 45 #include "saio.h" /* enum MAPTYPES */ 46 47 #include <arch/sun3/include/pte3x.h> 48 #include <arch/sun3/sun3x/iommu.h> 49 #include <arch/sun3/sun3x/vme.h> 50 51 /* Names, names... */ 52 #define MON_LOMEM_BASE 0 53 #define MON_LOMEM_SIZE 0x400000 54 #define MON_LOMEM_END (MON_LOMEM_BASE+MON_LOMEM_SIZE) 55 #define MON_KDB_BASE SUN3X_MON_KDB_BASE 56 #define MON_KDB_SIZE SUN3X_MON_KDB_SIZE 57 #define MON_KDB_END (MON_KDB_BASE+MON_KDB_SIZE) 58 #define MON_DVMA_BASE SUN3X_MON_DVMA_BASE 59 #define MON_DVMA_SIZE SUN3X_MON_DVMA_SIZE 60 61 static void mmu_atc_flush(vaddr_t); 62 static void set_iommupte(vaddr_t, paddr_t); 63 64 #ifdef DEBUG_PROM 65 static u_int sun3x_get_pte(vaddr_t); 66 #endif 67 static void sun3x_set_pte(vaddr_t, paddr_t); 68 static void dvma3x_init(void); 69 static char * dvma3x_alloc(int); 70 static void dvma3x_free(char *, int); 71 static char * dvma3x_mapin(char *, int); 72 static void dvma3x_mapout(char *, int); 73 static char * dev3x_mapin(int, u_long, int); 74 75 struct mapinfo { 76 int maptype; 77 u_int base; 78 u_int mask; 79 }; 80 81 struct mapinfo 82 sun3x_mapinfo[MAP__NTYPES] = { 83 /* On-board memory, I/O */ 84 { MAP_MAINMEM, 0, ~0 }, 85 { MAP_OBIO, 0, ~0 }, 86 /* Multibus adapter (A24,A16) */ 87 { MAP_MBMEM, VME24D16_BASE, VME24_MASK }, 88 { MAP_MBIO, VME16D16_BASE, VME16_MASK }, 89 /* VME A16 */ 90 { MAP_VME16A16D, VME16D16_BASE, VME16_MASK }, 91 { MAP_VME16A32D, VME16D32_BASE, VME16_MASK }, 92 /* VME A24 */ 93 { MAP_VME24A16D, VME24D16_BASE, VME24_MASK }, 94 { MAP_VME24A32D, VME24D32_BASE, VME24_MASK }, 95 /* VME A32 */ 96 { MAP_VME32A16D, VME32D16_BASE, VME32_MASK }, 97 { MAP_VME32A32D, VME32D32_BASE, VME32_MASK }, 98 }; 99 100 /* The virtual address we will use for PROM device mappings. */ 101 u_int sun3x_devmap = MON_KDB_BASE; 102 103 static char * 104 dev3x_mapin(int maptype, u_long physaddr, int length) 105 { 106 u_int i, pa, pte, pgva, va; 107 108 if ((sun3x_devmap + length) > (MON_KDB_BASE + MON_KDB_SIZE)) 109 panic("dev3x_mapin: length=%d", length); 110 111 for (i = 0; i < MAP__NTYPES; i++) 112 if (sun3x_mapinfo[i].maptype == maptype) 113 goto found; 114 panic("dev3x_mapin: bad maptype"); 115 found: 116 117 if (physaddr & ~(sun3x_mapinfo[i].mask)) 118 panic("dev3x_mapin: bad address"); 119 pa = sun3x_mapinfo[i].base + physaddr; 120 121 pte = pa | MMU_DT_PAGE | MMU_SHORT_PTE_CI; 122 123 va = pgva = sun3x_devmap; 124 do { 125 sun3x_set_pte(pgva, pte); 126 pgva += NBPG; 127 pte += NBPG; 128 length -= NBPG; 129 } while (length > 0); 130 sun3x_devmap = pgva; 131 va += (physaddr & PGOFSET); 132 133 #ifdef DEBUG_PROM 134 if (debug) 135 printf("dev3x_mapin: va=0x%x pte=0x%x\n", 136 va, sun3x_get_pte(va)); 137 #endif 138 return ((char*)va); 139 } 140 141 /***************************************************************** 142 * DVMA support 143 */ 144 145 #define SA_MIN_VA 0x200000 146 #define SA_MAX_VA (SA_MIN_VA + MON_DVMA_SIZE - (8 * NBPG)) 147 148 #define MON_DVMA_MAPLEN (MON_DVMA_SIZE - NBPG) 149 150 /* This points to the end of the free DVMA space. */ 151 u_int dvma3x_end = MON_DVMA_BASE + MON_DVMA_MAPLEN; 152 153 static void 154 dvma3x_init(void) 155 { 156 u_int va, pa; 157 158 pa = SA_MIN_VA; 159 va = MON_DVMA_BASE; 160 161 while (pa < SA_MAX_VA) { 162 sun3x_set_pte(va, pa | MMU_DT_PAGE | MMU_SHORT_PTE_CI); 163 set_iommupte(va, pa | IOMMU_PDE_DT_VALID | IOMMU_PDE_CI); 164 va += NBPG; 165 pa += NBPG; 166 } 167 } 168 169 /* Convert a local address to a DVMA address. */ 170 char * 171 dvma3x_mapin(char *addr, int len) 172 { 173 int va = (int)addr; 174 175 /* Make sure the address is in the DVMA map. */ 176 if ((va < SA_MIN_VA) || (va >= SA_MAX_VA)) 177 panic("dvma3x_mapin"); 178 179 va -= SA_MIN_VA; 180 va += MON_DVMA_BASE; 181 182 return ((char *) va); 183 } 184 185 /* Convert a DVMA address to a local address. */ 186 static void 187 dvma3x_mapout(char *addr, int len) 188 { 189 int va = (int)addr; 190 191 /* Make sure the address is in the DVMA map. */ 192 if ((va < MON_DVMA_BASE) || 193 (va >= (MON_DVMA_BASE + MON_DVMA_MAPLEN))) 194 panic("dvma3x_mapout"); 195 } 196 197 static char * 198 dvma3x_alloc(int len) 199 { 200 len = m68k_round_page(len); 201 dvma3x_end -= len; 202 return((char *)dvma3x_end); 203 } 204 205 static void 206 dvma3x_free(char *dvma, int len) 207 { 208 /* not worth the trouble */ 209 } 210 211 /***************************************************************** 212 * MMU (and I/O MMU) support 213 */ 214 215 #ifdef DEBUG_PROM 216 static u_int 217 sun3x_get_pte(vaddr_t va) 218 { 219 u_int pn; 220 mmu_short_pte_t *tbl; 221 222 if (va >= MON_LOMEM_BASE && va < MON_LOMEM_END) { 223 tbl = (mmu_short_pte_t *) *romVectorPtr->lomemptaddr; 224 } else if (va >= MON_KDB_BASE && va < MON_KDB_END) { 225 va -= MON_KDB_BASE; 226 tbl = (mmu_short_pte_t *) *romVectorPtr->monptaddr; 227 } else if (va >= MON_DVMA_BASE) { 228 va -= MON_DVMA_BASE; 229 tbl = (mmu_short_pte_t *) *romVectorPtr->shadowpteaddr; 230 } else { 231 return 0; 232 } 233 234 /* Calculate the page number within the selected table. */ 235 pn = (va >> MMU_PAGE_SHIFT); 236 /* Extract the PTE from the table. */ 237 return tbl[pn].attr.raw; 238 } 239 #endif 240 241 static void 242 sun3x_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 static void 278 mmu_atc_flush(vaddr_t va) 279 { 280 281 __asm volatile ("pflush #0,#0,%0@" : : "a" (va)); 282 } 283 284 static 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