1 /* $OpenBSD: pdc.c,v 1.23 2020/12/09 18:10:18 krw 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 daddr_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 /* On read, see if we can scratch anything from buffer */ 205 if (rw == F_READ && 206 dp->last_blk <= blk && (dp->last_blk + dp->last_read) > blk) { 207 twiddle(); 208 offset = blk - dp->last_blk; 209 xfer = min(dp->last_read - offset, size); 210 size -= xfer; 211 blk += xfer; 212 #ifdef PDCDEBUG 213 if (debug) 214 printf("off=%d,xfer=%d,size=%d,blk=%d\n", 215 offset, xfer, size, blk); 216 #endif 217 bcopy(dp->buf + offset, buf, xfer); 218 buf += xfer; 219 } 220 221 /* 222 * double buffer it all the time, to cache 223 */ 224 for (; size; size -= ret, buf += ret, blk += ret, xfer += ret) { 225 offset = blk & IOPGOFSET; 226 if (rw != F_READ) { 227 /* put block into cache, but invalidate cache */ 228 bcopy(buf, dp->buf, size); 229 dp->last_blk = 0; 230 dp->last_read = 0; 231 } 232 if ((ret = ((iodcio_t)pzdev->pz_iodc_io)(pzdev->pz_hpa, 233 (rw == F_READ? IODC_IO_READ: IODC_IO_WRITE), 234 pzdev->pz_spa, pzdev->pz_layers, pdcbuf, 235 (u_int)blk - offset, dp->buf, IODC_IOSIZ, IODC_IOSIZ)) < 0) { 236 #ifdef DEBUG 237 if (debug) 238 printf("iodc_read(%d,%d): %d\n", 239 blk - offset, IODC_IOSIZ, ret); 240 #endif 241 if (xfer) 242 break; 243 else 244 return (EIO); 245 } 246 if ((ret = pdcbuf[0]) <= 0) 247 break; 248 if (rw == F_READ) { 249 dp->last_blk = blk - offset; 250 dp->last_read = ret; 251 if ((ret -= offset) > size) 252 ret = size; 253 bcopy(dp->buf + offset, buf, ret); 254 } 255 #ifdef PDCDEBUG 256 if (debug) 257 printf("read %d(%d,%d)@%x ", ret, 258 dp->last_blk, dp->last_read, (u_int)buf); 259 #endif 260 } 261 262 #ifdef PDCDEBUG 263 if (debug) 264 printf("\n"); 265 #endif 266 267 if (rsize) 268 *rsize = xfer; 269 return (0); 270 } 271 272 /* 273 * Find a device with specified unit number 274 * (any if unit == -1), and of specified class (PCL_*). 275 */ 276 struct pz_device * 277 pdc_findev(unit, class) 278 int unit, class; 279 { 280 static struct pz_device pz; 281 int layers[sizeof(pz.pz_layers)/sizeof(pz.pz_layers[0])]; 282 struct iomod *io; 283 iodcio_t iodc; 284 int err = 0; 285 286 #ifdef PDCDEBUG 287 if (debug) 288 printf("pdc_finddev(%d, %x)\n", unit, class); 289 #endif 290 iodc = (iodcio_t)(PAGE0->mem_free + IODC_MAXSIZE); 291 io = (struct iomod *)PAGE0->mem_boot.pz_hpa; 292 293 /* quick hack for boot device */ 294 if (PAGE0->mem_boot.pz_class == class && 295 (unit == -1 || PAGE0->mem_boot.pz_layers[0] == unit)) { 296 297 bcopy (&PAGE0->mem_boot.pz_dp, &pz.pz_dp, sizeof(pz.pz_dp)); 298 bcopy (pz.pz_layers, layers, sizeof(layers)); 299 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io, 300 IODC_INIT, iodc, IODC_MAXSIZE)) < 0) { 301 #ifdef DEBUG 302 if (debug) 303 printf("IODC_READ: %d\n", err); 304 #endif 305 return NULL; 306 } 307 } else { 308 struct pdc_memmap memmap; 309 struct iodc_data mptr; 310 int i, stp; 311 312 for (i = 0; i < 0xf; i++) { 313 pz.pz_bc[0] = pz.pz_bc[1] = 314 pz.pz_bc[2] = pz.pz_bc[3] = -1; 315 pz.pz_bc[4] = 2; 316 pz.pz_bc[5] = 0; /* core bus */ 317 pz.pz_mod = i; 318 if ((pdc)(PDC_MEMMAP, PDC_MEMMAP_HPA, &memmap, 319 &pz.pz_dp) < 0) 320 continue; 321 #ifdef PDCDEBUG 322 if (debug) 323 printf("memap: %d.%d.%d, hpa=%x, mpgs=%x\n", 324 pz.pz_bc[4], pz.pz_bc[5], pz.pz_mod, 325 memmap.hpa, memmap.morepages); 326 #endif 327 io = (struct iomod *) memmap.hpa; 328 329 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, &pdcbuf, io, 330 IODC_DATA, &mptr, sizeof(mptr))) < 0) { 331 #ifdef DEBUG 332 if (debug) 333 printf("IODC_DATA: %d\n", err); 334 #endif 335 continue; 336 } 337 338 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io, 339 IODC_INIT, iodc, IODC_MAXSIZE)) < 0) { 340 #ifdef DEBUG 341 if (debug) 342 printf("IODC_READ: %d\n", err); 343 #endif 344 continue; 345 } 346 347 stp = IODC_INIT_FIRST; 348 do { 349 if ((err = (iodc)((u_int)io, stp, io->io_spa, 350 layers, pdcbuf, 0, 0, 0, 0)) < 0) { 351 #ifdef DEBUG 352 if (debug && err != PDC_ERR_EOD) 353 printf("IODC_INIT_%s: %d\n", 354 stp==IODC_INIT_FIRST? 355 "FIRST":"NEXT", err); 356 #endif 357 break; 358 } 359 #ifdef PDCDEBUG 360 if (debug) 361 printf("[%x,%x,%x,%x,%x,%x], " 362 "[%x,%x,%x,%x,%x,%x]\n", 363 pdcbuf[0], pdcbuf[1], pdcbuf[2], 364 pdcbuf[3], pdcbuf[4], pdcbuf[5], 365 layers[0], layers[1], layers[2], 366 layers[3], layers[4], layers[5]); 367 #endif 368 stp = IODC_INIT_NEXT; 369 370 } while (pdcbuf[1] != class && 371 unit != -1 && unit != layers[0]); 372 373 if (err >= 0) 374 break; 375 } 376 } 377 378 if (err >= 0) { 379 /* init device */ 380 if (0 && (err = (iodc)((u_int)io, IODC_INIT_DEV, io->io_spa, 381 layers, pdcbuf, 0, 0, 0, 0)) < 0) { 382 #ifdef DEBUG 383 if (debug) 384 printf("INIT_DEV: %d\n", err); 385 #endif 386 return NULL; 387 } 388 389 /* read i/o entry code */ 390 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io, 391 IODC_IO, iodc, IODC_MAXSIZE)) < 0) { 392 #ifdef DEBUG 393 if (debug) 394 printf("IODC_READ: %d\n", err); 395 #endif 396 return NULL; 397 } 398 399 pz.pz_flags = 0; 400 bcopy(layers, pz.pz_layers, sizeof(pz.pz_layers)); 401 pz.pz_hpa = (u_int)io; 402 /* XXX pz.pz_spa = io->io_spa; */ 403 pz.pz_iodc_io = (u_int)iodc; 404 pz.pz_class = class; 405 406 return &pz; 407 } 408 409 return NULL; 410 } 411 412 static __inline void 413 fall(int c_base, int c_count, int c_loop, int c_stride, int data) 414 { 415 int loop; /* Internal vars */ 416 417 for (; c_count--; c_base += c_stride) 418 for (loop = c_loop; loop--; ) 419 if (data) 420 fdce(0, c_base); 421 else 422 fice(0, c_base); 423 } 424 425 /* 426 * fcacheall - Flush all caches. 427 * 428 * This routine is just a wrapper around the real cache flush routine. 429 */ 430 struct pdc_cache pdc_cacheinfo PDC_ALIGNMENT; 431 432 void 433 fcacheall() 434 { 435 int err; 436 437 if ((err = (*pdc)(PDC_CACHE, PDC_CACHE_DFLT, &pdc_cacheinfo)) < 0) { 438 #ifdef DEBUG 439 if (debug) 440 printf("fcacheall: PDC_CACHE failed (%d).\n", err); 441 #endif 442 return; 443 } 444 #if PDCDEBUG 445 if (debug) 446 printf("pdc_cache:\nic={%u,%x,%x,%u,%u,%u}\n" 447 "dc={%u,%x,%x,%u,%u,%u}\n", 448 pdc_cacheinfo.ic_size, *(u_int *)&pdc_cacheinfo.ic_conf, 449 pdc_cacheinfo.ic_base, pdc_cacheinfo.ic_stride, 450 pdc_cacheinfo.ic_count, pdc_cacheinfo.ic_loop, 451 pdc_cacheinfo.dc_size, *(u_int *)&pdc_cacheinfo.ic_conf, 452 pdc_cacheinfo.dc_base, pdc_cacheinfo.dc_stride, 453 pdc_cacheinfo.dc_count, pdc_cacheinfo.dc_loop); 454 #endif 455 /* 456 * Flush the instruction, then data cache. 457 */ 458 fall(pdc_cacheinfo.ic_base, pdc_cacheinfo.ic_count, 459 pdc_cacheinfo.ic_loop, pdc_cacheinfo.ic_stride, 0); 460 sync_caches(); 461 fall(pdc_cacheinfo.dc_base, pdc_cacheinfo.dc_count, 462 pdc_cacheinfo.dc_loop, pdc_cacheinfo.dc_stride, 1); 463 sync_caches(); 464 } 465