1 /* $NetBSD: obio.c,v 1.14 1994/12/12 18:59:22 gwr Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Gordon W. Ross 5 * Copyright (c) 1993 Adam Glass 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Adam Glass and Gordon Ross. 19 * 4. The name of the authors may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 38 #include <machine/autoconf.h> 39 #include <machine/pte.h> 40 #include <machine/mon.h> 41 #include <machine/isr.h> 42 #include <machine/obio.h> 43 44 static void obio_attach __P((struct device *, struct device *, void *)); 45 static void obio_scan __P((struct device *, void *)); 46 47 struct cfdriver obiocd = { 48 NULL, "obio", always_match, obio_attach, DV_DULL, 49 sizeof(struct device), 0 }; 50 51 static void 52 obio_attach(parent, self, args) 53 struct device *parent; 54 struct device *self; 55 void *args; 56 { 57 printf("\n"); 58 config_scan(obio_scan, self); 59 } 60 61 static void 62 obio_scan(parent, child) 63 struct device *parent; 64 void *child; 65 { 66 bus_scan(parent, child, BUS_OBIO); 67 } 68 69 /* 70 * Spacing of "interesting" OBIO mappings. We will 71 * record only those with an OBIO address that is a 72 * multiple of SAVE_INCR and below SAVE_LAST. 73 * The saved mappings are just one page each, which 74 * is good enough for all the devices that use this. 75 */ 76 #define SAVE_SHIFT 17 77 #define SAVE_INCR (1<<SAVE_SHIFT) 78 #define SAVE_MASK (SAVE_INCR-1) 79 #define SAVE_SLOTS 16 80 #define SAVE_LAST (SAVE_SLOTS * SAVE_INCR) 81 82 /* 83 * This is our record of "interesting" OBIO mappings that 84 * the PROM has left in the virtual space reserved for it. 85 * Each non-null array element holds the virtual address 86 * of an OBIO mapping where the OBIO address mapped is: 87 * (array_index * SAVE_INCR) 88 * and the length of the mapping is one page. 89 */ 90 static caddr_t prom_mappings[SAVE_SLOTS]; 91 92 caddr_t obio_find_mapping(int pa, int size) 93 { 94 if ((size <= NBPG) && 95 (pa < SAVE_LAST) && 96 ((pa & SAVE_MASK) == 0)) 97 { 98 return prom_mappings[pa >> SAVE_SHIFT]; 99 } 100 return (caddr_t)0; 101 } 102 103 /* 104 * This defines the permission bits to put in our PTEs. 105 * Device space is never cached, and the PROM appears to 106 * leave off the "no-cache" bit, so we can do the same. 107 */ 108 #define PGBITS (PG_VALID|PG_WRITE|PG_SYSTEM) 109 110 static void save_prom_mappings() 111 { 112 vm_offset_t pa; 113 caddr_t segva, pgva; 114 int pte, sme, i; 115 116 segva = (caddr_t)MONSTART; 117 while (segva < (caddr_t)MONEND) { 118 sme = get_segmap(segva); 119 if (sme == SEGINV) { 120 segva += NBSG; 121 continue; /* next segment */ 122 } 123 /* 124 * We have a valid segmap entry, so examine the 125 * PTEs for all the pages in this segment. 126 */ 127 pgva = segva; /* starting page */ 128 segva += NBSG; /* ending page (next seg) */ 129 while (pgva < segva) { 130 pte = get_pte(pgva); 131 if ((pte & (PG_VALID | PG_TYPE)) == 132 (PG_VALID | PGT_OBIO)) 133 { 134 /* Have a valid OBIO mapping. */ 135 pa = PG_PA(pte); 136 /* Is it one we want to record? */ 137 if ((pa < SAVE_LAST) && 138 ((pa & SAVE_MASK) == 0)) 139 { 140 i = pa >> SAVE_SHIFT; 141 if (prom_mappings[i] == NULL) { 142 prom_mappings[i] = pgva; 143 #ifdef DEBUG 144 mon_printf("obio: found pa=0x%x\n", pa); 145 #endif 146 } 147 } 148 /* Make sure it has the right permissions. */ 149 if ((pte & PGBITS) != PGBITS) { 150 #ifdef DEBUG 151 mon_printf("obio: fixing pte=0x%x\n", pte); 152 #endif 153 pte |= PGBITS; 154 set_pte(pgva, pte); 155 } 156 } 157 pgva += NBPG; /* next page */ 158 } 159 } 160 } 161 162 /* 163 * These are all the OBIO address that are required early 164 * in the life of the kernel. All are less one page long. 165 */ 166 static vm_offset_t required_mappings[] = { 167 /* Basically the first six OBIO devices. */ 168 OBIO_KEYBD_MS, 169 OBIO_ZS, 170 OBIO_EEPROM, 171 OBIO_CLOCK, 172 OBIO_MEMERR, 173 OBIO_INTERREG, 174 (vm_offset_t)-1, /* end marker */ 175 }; 176 177 static void make_required_mappings() 178 { 179 vm_offset_t pa, *rmp; 180 int idx; 181 182 rmp = required_mappings; 183 while (*rmp != (vm_offset_t)-1) { 184 if (!obio_find_mapping(*rmp, NBPG)) { 185 /* 186 * XXX - Ack! Need to create one! 187 * I don't think this can happen, but if 188 * it does, we can allocate a PMEG in the 189 * "high segment" and add it there. -gwr 190 */ 191 mon_printf("obio: no mapping for 0x%x\n", *rmp); 192 mon_panic("obio: Ancient PROM?\n"); 193 } 194 rmp++; 195 } 196 } 197 198 199 /* 200 * this routine "configures" any internal OBIO devices which must be 201 * accessible before the mainline OBIO autoconfiguration as part of 202 * configure(). 203 */ 204 void obio_init() 205 { 206 save_prom_mappings(); 207 make_required_mappings(); 208 } 209 210 caddr_t obio_alloc(obio_addr, obio_size) 211 int obio_addr, obio_size; 212 { 213 int npages; 214 vm_offset_t va, high_segment_alloc(), obio_pa, obio_va, pte_proto; 215 caddr_t cp; 216 217 cp = obio_find_mapping((vm_offset_t)obio_addr, obio_size); 218 if (cp) return (cp); 219 220 npages = PA_PGNUM(sun3_round_page(obio_size)); 221 if (!npages) 222 panic("obio_alloc: attempt to allocate 0 pages for obio"); 223 va = high_segment_alloc(npages); 224 if (!va) 225 va = (vm_offset_t) obio_vm_alloc(npages); 226 if (!va) 227 panic("obio_alloc: unable to allocate va for obio mapping"); 228 /* Drivers always get writable, non-cached mappings. */ 229 pte_proto = PG_VALID | PG_WRITE | PG_SYSTEM | PGT_OBIO | PG_NC; 230 obio_va = va; 231 obio_pa = (vm_offset_t) obio_addr; 232 for (; npages ; npages--, obio_va += NBPG, obio_pa += NBPG) 233 set_pte(obio_va, pte_proto | PA_PGNUM(obio_pa)); 234 return (caddr_t) va; 235 } 236