1 /* $OpenBSD: pdc.c,v 1.21 2013/03/23 16:08:28 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1998-2004 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /* 29 * Copyright 1996 1995 by Open Software Foundation, Inc. 30 * All Rights Reserved 31 * 32 * Permission to use, copy, modify, and distribute this software and 33 * its documentation for any purpose and without fee is hereby granted, 34 * provided that the above copyright notice appears in all copies and 35 * that both the copyright notice and this permission notice appear in 36 * supporting documentation. 37 * 38 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 39 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 40 * FOR A PARTICULAR PURPOSE. 41 * 42 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 43 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 44 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 45 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 46 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 47 * 48 */ 49 /* 50 * Copyright (c) 1990 mt Xinu, Inc. All rights reserved. 51 * Copyright (c) 1990 University of Utah. All rights reserved. 52 * 53 * This file may be freely distributed in any form as long as 54 * this copyright notice is included. 55 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 56 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 57 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 58 * 59 * Utah $Hdr: pdc.c 1.8 92/03/14$ 60 */ 61 62 #include <sys/param.h> 63 #include <sys/time.h> 64 #include "libsa.h" 65 #include <sys/reboot.h> 66 #include <sys/disklabel.h> 67 68 #include <machine/trap.h> 69 #include <machine/pdc.h> 70 #include <machine/iomod.h> 71 #include <machine/nvm.h> 72 #include <machine/cpufunc.h> 73 74 #include "dev_hppa.h" 75 76 /* 77 * Interface routines to initialize and access the PDC. 78 */ 79 80 pdcio_t pdc; 81 int pdcbuf[64] PDC_ALIGNMENT;/* PDC return buffer */ 82 struct stable_storage sstor; /* contents of Stable Storage */ 83 int sstorsiz; /* size of Stable Storage */ 84 struct bootdata bd; 85 int bdsize = sizeof(struct bootdata); 86 87 /* 88 * Initialize PDC and related variables. 89 */ 90 void 91 pdc_init() 92 { 93 int err; 94 95 /* 96 * Initialize important global variables (defined above). 97 */ 98 pdc = (pdcio_t)PAGE0->mem_pdc; 99 100 err = (*pdc)(PDC_STABLE, PDC_STABLE_SIZE, pdcbuf, 0, 0); 101 if (err >= 0) { 102 sstorsiz = min(pdcbuf[0],sizeof(sstor)); 103 err = (*pdc)(PDC_STABLE, PDC_STABLE_READ, 0, &sstor, sstorsiz); 104 } 105 106 /* 107 * Now that we (may) have an output device, if we encountered 108 * an error reading Stable Storage (above), let them know. 109 */ 110 #ifdef DEBUG 111 if (debug && err) 112 printf("Stable storage PDC_STABLE Read Ret'd %d\n", err); 113 #endif 114 115 /* 116 * Clear the FAULT light (so we know when we get a real one) 117 */ 118 (*pdc)(PDC_CHASSIS, PDC_CHASSIS_DISP, 119 PDC_OSTAT(PDC_OSTAT_BOOT) | 0xCEC0); 120 } 121 122 /* 123 * Generic READ/WRITE through IODC. Takes pointer to PDC device 124 * information, returns (positive) number of bytes actually read or 125 * the (negative) error condition, or zero if at "EOF". 126 */ 127 int 128 iodcstrategy(devdata, rw, blk, size, buf, rsize) 129 void *devdata; 130 int rw; 131 daddr32_t blk; 132 size_t size; 133 void *buf; 134 size_t *rsize; 135 { 136 struct hppa_dev *dp = devdata; 137 struct pz_device *pzdev = dp->pz_dev; 138 int offset, xfer, ret; 139 140 #ifdef PDCDEBUG 141 if (debug) 142 printf("iodcstrategy(%p, %s, %u, %u, %p, %p)\n", devdata, 143 rw==F_READ? "READ" : "WRITE", blk, size, buf, rsize); 144 145 if (debug > 1) 146 PZDEV_PRINT(pzdev); 147 #endif 148 149 blk += dp->fsoff; 150 blk *= DEV_BSIZE; 151 if ((pzdev->pz_class & PCL_CLASS_MASK) == PCL_SEQU) { 152 /* rewind and re-read to seek */ 153 if (blk < dp->last_blk) { 154 #ifdef PDCDEBUG 155 if (debug) 156 printf("iodc: rewind "); 157 #endif 158 if ((ret = ((iodcio_t)pzdev->pz_iodc_io)(pzdev->pz_hpa, 159 IODC_IO_READ, pzdev->pz_spa, pzdev->pz_layers, 160 pdcbuf, 0, dp->buf, 0, 0)) < 0) { 161 #ifdef DEBUG 162 if (debug) 163 printf("IODC_IO: %d\n", ret); 164 #endif 165 return (EIO); 166 } else { 167 dp->last_blk = 0; 168 dp->last_read = 0; 169 } 170 } 171 172 #ifdef PDCDEBUG 173 if (debug) 174 printf("seek %d ", dp->last_blk); 175 #endif 176 for (; (dp->last_blk + dp->last_read) <= blk; 177 dp->last_read = ret) { 178 twiddle(); 179 dp->last_blk += dp->last_read; 180 if ((ret = ((iodcio_t)pzdev->pz_iodc_io)(pzdev->pz_hpa, 181 IODC_IO_READ, pzdev->pz_spa, pzdev->pz_layers, 182 pdcbuf, dp->last_blk, dp->buf, IODC_IOSIZ, 183 IODC_IOSIZ)) < 0) { 184 #ifdef DEBUG 185 if (debug) 186 printf("IODC_IO: %d\n", ret); 187 #endif 188 return (EIO); 189 } 190 if ((ret = pdcbuf[0]) == 0) 191 break; 192 #ifdef PDCDEBUG 193 if (debug) 194 printf("-"); 195 #endif 196 } 197 #ifdef PDCDEBUG 198 if (debug) 199 printf("> %d[%d]\n", dp->last_blk, dp->last_read); 200 #endif 201 } 202 203 xfer = 0; 204 /* see if we can scratch anything from buffer */ 205 if (dp->last_blk <= blk && (dp->last_blk + dp->last_read) > blk) { 206 twiddle(); 207 offset = blk - dp->last_blk; 208 xfer = min(dp->last_read - offset, size); 209 size -= xfer; 210 blk += xfer; 211 #ifdef PDCDEBUG 212 if (debug) 213 printf("off=%d,xfer=%d,size=%d,blk=%d\n", 214 offset, xfer, size, blk); 215 #endif 216 bcopy(dp->buf + offset, buf, xfer); 217 buf += xfer; 218 } 219 220 /* 221 * double buffer it all the time, to cache 222 */ 223 for (; size; size -= ret, buf += ret, blk += ret, xfer += ret) { 224 offset = blk & IOPGOFSET; 225 if ((ret = ((iodcio_t)pzdev->pz_iodc_io)(pzdev->pz_hpa, 226 (rw == F_READ? IODC_IO_READ: IODC_IO_WRITE), 227 pzdev->pz_spa, pzdev->pz_layers, pdcbuf, 228 blk - offset, dp->buf, IODC_IOSIZ, IODC_IOSIZ)) < 0) { 229 #ifdef DEBUG 230 if (debug) 231 printf("iodc_read(%d,%d): %d\n", 232 blk - offset, IODC_IOSIZ, ret); 233 #endif 234 if (xfer) 235 break; 236 else 237 return (EIO); 238 } 239 if ((ret = pdcbuf[0]) <= 0) 240 break; 241 dp->last_blk = blk - offset; 242 dp->last_read = ret; 243 if ((ret -= offset) > size) 244 ret = size; 245 bcopy(dp->buf + offset, buf, ret); 246 #ifdef PDCDEBUG 247 if (debug) 248 printf("read %d(%d,%d)@%x ", ret, 249 dp->last_blk, dp->last_read, (u_int)buf); 250 #endif 251 } 252 253 #ifdef PDCDEBUG 254 if (debug) 255 printf("\n"); 256 #endif 257 258 if (rsize) 259 *rsize = xfer; 260 return (0); 261 } 262 263 /* 264 * Find a device with specified unit number 265 * (any if unit == -1), and of specified class (PCL_*). 266 */ 267 struct pz_device * 268 pdc_findev(unit, class) 269 int unit, class; 270 { 271 static struct pz_device pz; 272 int layers[sizeof(pz.pz_layers)/sizeof(pz.pz_layers[0])]; 273 struct iomod *io; 274 iodcio_t iodc; 275 int err = 0; 276 277 #ifdef PDCDEBUG 278 if (debug) 279 printf("pdc_finddev(%d, %x)\n", unit, class); 280 #endif 281 iodc = (iodcio_t)(PAGE0->mem_free + IODC_MAXSIZE); 282 io = (struct iomod *)PAGE0->mem_boot.pz_hpa; 283 284 /* quick hack for boot device */ 285 if (PAGE0->mem_boot.pz_class == class && 286 (unit == -1 || PAGE0->mem_boot.pz_layers[0] == unit)) { 287 288 bcopy (&PAGE0->mem_boot.pz_dp, &pz.pz_dp, sizeof(pz.pz_dp)); 289 bcopy (pz.pz_layers, layers, sizeof(layers)); 290 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io, 291 IODC_INIT, iodc, IODC_MAXSIZE)) < 0) { 292 #ifdef DEBUG 293 if (debug) 294 printf("IODC_READ: %d\n", err); 295 #endif 296 return NULL; 297 } 298 } else { 299 struct pdc_memmap memmap; 300 struct iodc_data mptr; 301 int i, stp; 302 303 for (i = 0; i < 0xf; i++) { 304 pz.pz_bc[0] = pz.pz_bc[1] = 305 pz.pz_bc[2] = pz.pz_bc[3] = -1; 306 pz.pz_bc[4] = 2; 307 pz.pz_bc[5] = 0; /* core bus */ 308 pz.pz_mod = i; 309 if ((pdc)(PDC_MEMMAP, PDC_MEMMAP_HPA, &memmap, 310 &pz.pz_dp) < 0) 311 continue; 312 #ifdef PDCDEBUG 313 if (debug) 314 printf("memap: %d.%d.%d, hpa=%x, mpgs=%x\n", 315 pz.pz_bc[4], pz.pz_bc[5], pz.pz_mod, 316 memmap.hpa, memmap.morepages); 317 #endif 318 io = (struct iomod *) memmap.hpa; 319 320 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, &pdcbuf, io, 321 IODC_DATA, &mptr, sizeof(mptr))) < 0) { 322 #ifdef DEBUG 323 if (debug) 324 printf("IODC_DATA: %d\n", err); 325 #endif 326 continue; 327 } 328 329 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io, 330 IODC_INIT, iodc, IODC_MAXSIZE)) < 0) { 331 #ifdef DEBUG 332 if (debug) 333 printf("IODC_READ: %d\n", err); 334 #endif 335 continue; 336 } 337 338 stp = IODC_INIT_FIRST; 339 do { 340 if ((err = (iodc)((u_int)io, stp, io->io_spa, 341 layers, pdcbuf, 0, 0, 0, 0)) < 0) { 342 #ifdef DEBUG 343 if (debug && err != PDC_ERR_EOD) 344 printf("IODC_INIT_%s: %d\n", 345 stp==IODC_INIT_FIRST? 346 "FIRST":"NEXT", err); 347 #endif 348 break; 349 } 350 #ifdef PDCDEBUG 351 if (debug) 352 printf("[%x,%x,%x,%x,%x,%x], " 353 "[%x,%x,%x,%x,%x,%x]\n", 354 pdcbuf[0], pdcbuf[1], pdcbuf[2], 355 pdcbuf[3], pdcbuf[4], pdcbuf[5], 356 layers[0], layers[1], layers[2], 357 layers[3], layers[4], layers[5]); 358 #endif 359 stp = IODC_INIT_NEXT; 360 361 } while (pdcbuf[1] != class && 362 unit != -1 && unit != layers[0]); 363 364 if (err >= 0) 365 break; 366 } 367 } 368 369 if (err >= 0) { 370 /* init device */ 371 if (0 && (err = (iodc)((u_int)io, IODC_INIT_DEV, io->io_spa, 372 layers, pdcbuf, 0, 0, 0, 0)) < 0) { 373 #ifdef DEBUG 374 if (debug) 375 printf("INIT_DEV: %d\n", err); 376 #endif 377 return NULL; 378 } 379 380 /* read i/o entry code */ 381 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io, 382 IODC_IO, iodc, IODC_MAXSIZE)) < 0) { 383 #ifdef DEBUG 384 if (debug) 385 printf("IODC_READ: %d\n", err); 386 #endif 387 return NULL; 388 } 389 390 pz.pz_flags = 0; 391 bcopy(layers, pz.pz_layers, sizeof(pz.pz_layers)); 392 pz.pz_hpa = (u_int)io; 393 /* XXX pz.pz_spa = io->io_spa; */ 394 pz.pz_iodc_io = (u_int)iodc; 395 pz.pz_class = class; 396 397 return &pz; 398 } 399 400 return NULL; 401 } 402 403 static __inline void 404 fall(int c_base, int c_count, int c_loop, int c_stride, int data) 405 { 406 int loop; /* Internal vars */ 407 408 for (; c_count--; c_base += c_stride) 409 for (loop = c_loop; loop--; ) 410 if (data) 411 fdce(0, c_base); 412 else 413 fice(0, c_base); 414 } 415 416 /* 417 * fcacheall - Flush all caches. 418 * 419 * This routine is just a wrapper around the real cache flush routine. 420 */ 421 struct pdc_cache pdc_cacheinfo PDC_ALIGNMENT; 422 423 void 424 fcacheall() 425 { 426 int err; 427 428 if ((err = (*pdc)(PDC_CACHE, PDC_CACHE_DFLT, &pdc_cacheinfo)) < 0) { 429 #ifdef DEBUG 430 if (debug) 431 printf("fcacheall: PDC_CACHE failed (%d).\n", err); 432 #endif 433 return; 434 } 435 #if PDCDEBUG 436 if (debug) 437 printf("pdc_cache:\nic={%u,%x,%x,%u,%u,%u}\n" 438 "dc={%u,%x,%x,%u,%u,%u}\n", 439 pdc_cacheinfo.ic_size, *(u_int *)&pdc_cacheinfo.ic_conf, 440 pdc_cacheinfo.ic_base, pdc_cacheinfo.ic_stride, 441 pdc_cacheinfo.ic_count, pdc_cacheinfo.ic_loop, 442 pdc_cacheinfo.dc_size, *(u_int *)&pdc_cacheinfo.ic_conf, 443 pdc_cacheinfo.dc_base, pdc_cacheinfo.dc_stride, 444 pdc_cacheinfo.dc_count, pdc_cacheinfo.dc_loop); 445 #endif 446 /* 447 * Flush the instruction, then data cache. 448 */ 449 fall(pdc_cacheinfo.ic_base, pdc_cacheinfo.ic_count, 450 pdc_cacheinfo.ic_loop, pdc_cacheinfo.ic_stride, 0); 451 sync_caches(); 452 fall(pdc_cacheinfo.dc_base, pdc_cacheinfo.dc_count, 453 pdc_cacheinfo.dc_loop, pdc_cacheinfo.dc_stride, 1); 454 sync_caches(); 455 } 456