1 /* $OpenBSD: pdc.c,v 1.24 2023/01/06 19:05:46 miod 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/cpufunc.h>
72
73 #include "dev_hppa.h"
74
75 /*
76 * Interface routines to initialize and access the PDC.
77 */
78
79 pdcio_t pdc;
80 int pdcbuf[64] PDC_ALIGNMENT;/* PDC return buffer */
81 struct stable_storage sstor; /* contents of Stable Storage */
82 int sstorsiz; /* size of Stable Storage */
83
84 /*
85 * Initialize PDC and related variables.
86 */
87 void
pdc_init()88 pdc_init()
89 {
90 int err;
91
92 /*
93 * Initialize important global variables (defined above).
94 */
95 pdc = (pdcio_t)PAGE0->mem_pdc;
96
97 err = (*pdc)(PDC_STABLE, PDC_STABLE_SIZE, pdcbuf, 0, 0);
98 if (err >= 0) {
99 sstorsiz = min(pdcbuf[0],sizeof(sstor));
100 err = (*pdc)(PDC_STABLE, PDC_STABLE_READ, 0, &sstor, sstorsiz);
101 }
102
103 /*
104 * Now that we (may) have an output device, if we encountered
105 * an error reading Stable Storage (above), let them know.
106 */
107 #ifdef DEBUG
108 if (debug && err)
109 printf("Stable storage PDC_STABLE Read Ret'd %d\n", err);
110 #endif
111
112 /*
113 * Clear the FAULT light (so we know when we get a real one)
114 */
115 (*pdc)(PDC_CHASSIS, PDC_CHASSIS_DISP,
116 PDC_OSTAT(PDC_OSTAT_BOOT) | 0xCEC0);
117 }
118
119 /*
120 * Generic READ/WRITE through IODC. Takes pointer to PDC device
121 * information, returns (positive) number of bytes actually read or
122 * the (negative) error condition, or zero if at "EOF".
123 */
124 int
iodcstrategy(devdata,rw,blk,size,buf,rsize)125 iodcstrategy(devdata, rw, blk, size, buf, rsize)
126 void *devdata;
127 int rw;
128 daddr_t blk;
129 size_t size;
130 void *buf;
131 size_t *rsize;
132 {
133 struct hppa_dev *dp = devdata;
134 struct pz_device *pzdev = dp->pz_dev;
135 int offset, xfer, ret;
136
137 #ifdef PDCDEBUG
138 if (debug)
139 printf("iodcstrategy(%p, %s, %u, %u, %p, %p)\n", devdata,
140 rw==F_READ? "READ" : "WRITE", blk, size, buf, rsize);
141
142 if (debug > 1)
143 PZDEV_PRINT(pzdev);
144 #endif
145
146 blk += dp->fsoff;
147 blk *= DEV_BSIZE;
148 if ((pzdev->pz_class & PCL_CLASS_MASK) == PCL_SEQU) {
149 /* rewind and re-read to seek */
150 if (blk < dp->last_blk) {
151 #ifdef PDCDEBUG
152 if (debug)
153 printf("iodc: rewind ");
154 #endif
155 if ((ret = ((iodcio_t)pzdev->pz_iodc_io)(pzdev->pz_hpa,
156 IODC_IO_READ, pzdev->pz_spa, pzdev->pz_layers,
157 pdcbuf, 0, dp->buf, 0, 0)) < 0) {
158 #ifdef DEBUG
159 if (debug)
160 printf("IODC_IO: %d\n", ret);
161 #endif
162 return (EIO);
163 } else {
164 dp->last_blk = 0;
165 dp->last_read = 0;
166 }
167 }
168
169 #ifdef PDCDEBUG
170 if (debug)
171 printf("seek %d ", dp->last_blk);
172 #endif
173 for (; (dp->last_blk + dp->last_read) <= blk;
174 dp->last_read = ret) {
175 twiddle();
176 dp->last_blk += dp->last_read;
177 if ((ret = ((iodcio_t)pzdev->pz_iodc_io)(pzdev->pz_hpa,
178 IODC_IO_READ, pzdev->pz_spa, pzdev->pz_layers,
179 pdcbuf, dp->last_blk, dp->buf, IODC_IOSIZ,
180 IODC_IOSIZ)) < 0) {
181 #ifdef DEBUG
182 if (debug)
183 printf("IODC_IO: %d\n", ret);
184 #endif
185 return (EIO);
186 }
187 if ((ret = pdcbuf[0]) == 0)
188 break;
189 #ifdef PDCDEBUG
190 if (debug)
191 printf("-");
192 #endif
193 }
194 #ifdef PDCDEBUG
195 if (debug)
196 printf("> %d[%d]\n", dp->last_blk, dp->last_read);
197 #endif
198 }
199
200 xfer = 0;
201 /* On read, see if we can scratch anything from buffer */
202 if (rw == F_READ &&
203 dp->last_blk <= blk && (dp->last_blk + dp->last_read) > blk) {
204 twiddle();
205 offset = blk - dp->last_blk;
206 xfer = min(dp->last_read - offset, size);
207 size -= xfer;
208 blk += xfer;
209 #ifdef PDCDEBUG
210 if (debug)
211 printf("off=%d,xfer=%d,size=%d,blk=%d\n",
212 offset, xfer, size, blk);
213 #endif
214 bcopy(dp->buf + offset, buf, xfer);
215 buf += xfer;
216 }
217
218 /*
219 * double buffer it all the time, to cache
220 */
221 for (; size; size -= ret, buf += ret, blk += ret, xfer += ret) {
222 offset = blk & IOPGOFSET;
223 if (rw != F_READ) {
224 /* put block into cache, but invalidate cache */
225 bcopy(buf, dp->buf, size);
226 dp->last_blk = 0;
227 dp->last_read = 0;
228 }
229 if ((ret = ((iodcio_t)pzdev->pz_iodc_io)(pzdev->pz_hpa,
230 (rw == F_READ? IODC_IO_READ: IODC_IO_WRITE),
231 pzdev->pz_spa, pzdev->pz_layers, pdcbuf,
232 (u_int)blk - offset, dp->buf, IODC_IOSIZ, IODC_IOSIZ)) < 0) {
233 #ifdef DEBUG
234 if (debug)
235 printf("iodc_read(%d,%d): %d\n",
236 blk - offset, IODC_IOSIZ, ret);
237 #endif
238 if (xfer)
239 break;
240 else
241 return (EIO);
242 }
243 if ((ret = pdcbuf[0]) <= 0)
244 break;
245 if (rw == F_READ) {
246 dp->last_blk = blk - offset;
247 dp->last_read = ret;
248 if ((ret -= offset) > size)
249 ret = size;
250 bcopy(dp->buf + offset, buf, ret);
251 }
252 #ifdef PDCDEBUG
253 if (debug)
254 printf("read %d(%d,%d)@%x ", ret,
255 dp->last_blk, dp->last_read, (u_int)buf);
256 #endif
257 }
258
259 #ifdef PDCDEBUG
260 if (debug)
261 printf("\n");
262 #endif
263
264 if (rsize)
265 *rsize = xfer;
266 return (0);
267 }
268
269 /*
270 * Find a device with specified unit number
271 * (any if unit == -1), and of specified class (PCL_*).
272 */
273 struct pz_device *
pdc_findev(unit,class)274 pdc_findev(unit, class)
275 int unit, class;
276 {
277 static struct pz_device pz;
278 int layers[sizeof(pz.pz_layers)/sizeof(pz.pz_layers[0])];
279 struct iomod *io;
280 iodcio_t iodc;
281 int err = 0;
282
283 #ifdef PDCDEBUG
284 if (debug)
285 printf("pdc_finddev(%d, %x)\n", unit, class);
286 #endif
287 iodc = (iodcio_t)(PAGE0->mem_free + IODC_MAXSIZE);
288 io = (struct iomod *)PAGE0->mem_boot.pz_hpa;
289
290 /* quick hack for boot device */
291 if (PAGE0->mem_boot.pz_class == class &&
292 (unit == -1 || PAGE0->mem_boot.pz_layers[0] == unit)) {
293
294 bcopy (&PAGE0->mem_boot.pz_dp, &pz.pz_dp, sizeof(pz.pz_dp));
295 bcopy (pz.pz_layers, layers, sizeof(layers));
296 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io,
297 IODC_INIT, iodc, IODC_MAXSIZE)) < 0) {
298 #ifdef DEBUG
299 if (debug)
300 printf("IODC_READ: %d\n", err);
301 #endif
302 return NULL;
303 }
304 } else {
305 struct pdc_memmap memmap;
306 struct iodc_data mptr;
307 int i, stp;
308
309 for (i = 0; i < 0xf; i++) {
310 pz.pz_bc[0] = pz.pz_bc[1] =
311 pz.pz_bc[2] = pz.pz_bc[3] = -1;
312 pz.pz_bc[4] = 2;
313 pz.pz_bc[5] = 0; /* core bus */
314 pz.pz_mod = i;
315 if ((pdc)(PDC_MEMMAP, PDC_MEMMAP_HPA, &memmap,
316 &pz.pz_dp) < 0)
317 continue;
318 #ifdef PDCDEBUG
319 if (debug)
320 printf("memap: %d.%d.%d, hpa=%x, mpgs=%x\n",
321 pz.pz_bc[4], pz.pz_bc[5], pz.pz_mod,
322 memmap.hpa, memmap.morepages);
323 #endif
324 io = (struct iomod *) memmap.hpa;
325
326 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, &pdcbuf, io,
327 IODC_DATA, &mptr, sizeof(mptr))) < 0) {
328 #ifdef DEBUG
329 if (debug)
330 printf("IODC_DATA: %d\n", err);
331 #endif
332 continue;
333 }
334
335 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io,
336 IODC_INIT, iodc, IODC_MAXSIZE)) < 0) {
337 #ifdef DEBUG
338 if (debug)
339 printf("IODC_READ: %d\n", err);
340 #endif
341 continue;
342 }
343
344 stp = IODC_INIT_FIRST;
345 do {
346 if ((err = (iodc)((u_int)io, stp, io->io_spa,
347 layers, pdcbuf, 0, 0, 0, 0)) < 0) {
348 #ifdef DEBUG
349 if (debug && err != PDC_ERR_EOD)
350 printf("IODC_INIT_%s: %d\n",
351 stp==IODC_INIT_FIRST?
352 "FIRST":"NEXT", err);
353 #endif
354 break;
355 }
356 #ifdef PDCDEBUG
357 if (debug)
358 printf("[%x,%x,%x,%x,%x,%x], "
359 "[%x,%x,%x,%x,%x,%x]\n",
360 pdcbuf[0], pdcbuf[1], pdcbuf[2],
361 pdcbuf[3], pdcbuf[4], pdcbuf[5],
362 layers[0], layers[1], layers[2],
363 layers[3], layers[4], layers[5]);
364 #endif
365 stp = IODC_INIT_NEXT;
366
367 } while (pdcbuf[1] != class &&
368 unit != -1 && unit != layers[0]);
369
370 if (err >= 0)
371 break;
372 }
373 }
374
375 if (err >= 0) {
376 /* init device */
377 if (0 && (err = (iodc)((u_int)io, IODC_INIT_DEV, io->io_spa,
378 layers, pdcbuf, 0, 0, 0, 0)) < 0) {
379 #ifdef DEBUG
380 if (debug)
381 printf("INIT_DEV: %d\n", err);
382 #endif
383 return NULL;
384 }
385
386 /* read i/o entry code */
387 if ((err = (pdc)(PDC_IODC, PDC_IODC_READ, pdcbuf, io,
388 IODC_IO, iodc, IODC_MAXSIZE)) < 0) {
389 #ifdef DEBUG
390 if (debug)
391 printf("IODC_READ: %d\n", err);
392 #endif
393 return NULL;
394 }
395
396 pz.pz_flags = 0;
397 bcopy(layers, pz.pz_layers, sizeof(pz.pz_layers));
398 pz.pz_hpa = (u_int)io;
399 /* XXX pz.pz_spa = io->io_spa; */
400 pz.pz_iodc_io = (u_int)iodc;
401 pz.pz_class = class;
402
403 return &pz;
404 }
405
406 return NULL;
407 }
408
409 static __inline void
fall(int c_base,int c_count,int c_loop,int c_stride,int data)410 fall(int c_base, int c_count, int c_loop, int c_stride, int data)
411 {
412 int loop; /* Internal vars */
413
414 for (; c_count--; c_base += c_stride)
415 for (loop = c_loop; loop--; )
416 if (data)
417 fdce(0, c_base);
418 else
419 fice(0, c_base);
420 }
421
422 /*
423 * fcacheall - Flush all caches.
424 *
425 * This routine is just a wrapper around the real cache flush routine.
426 */
427 struct pdc_cache pdc_cacheinfo PDC_ALIGNMENT;
428
429 void
fcacheall()430 fcacheall()
431 {
432 int err;
433
434 if ((err = (*pdc)(PDC_CACHE, PDC_CACHE_DFLT, &pdc_cacheinfo)) < 0) {
435 #ifdef DEBUG
436 if (debug)
437 printf("fcacheall: PDC_CACHE failed (%d).\n", err);
438 #endif
439 return;
440 }
441 #if PDCDEBUG
442 if (debug)
443 printf("pdc_cache:\nic={%u,%x,%x,%u,%u,%u}\n"
444 "dc={%u,%x,%x,%u,%u,%u}\n",
445 pdc_cacheinfo.ic_size, *(u_int *)&pdc_cacheinfo.ic_conf,
446 pdc_cacheinfo.ic_base, pdc_cacheinfo.ic_stride,
447 pdc_cacheinfo.ic_count, pdc_cacheinfo.ic_loop,
448 pdc_cacheinfo.dc_size, *(u_int *)&pdc_cacheinfo.ic_conf,
449 pdc_cacheinfo.dc_base, pdc_cacheinfo.dc_stride,
450 pdc_cacheinfo.dc_count, pdc_cacheinfo.dc_loop);
451 #endif
452 /*
453 * Flush the instruction, then data cache.
454 */
455 fall(pdc_cacheinfo.ic_base, pdc_cacheinfo.ic_count,
456 pdc_cacheinfo.ic_loop, pdc_cacheinfo.ic_stride, 0);
457 sync_caches();
458 fall(pdc_cacheinfo.dc_base, pdc_cacheinfo.dc_count,
459 pdc_cacheinfo.dc_loop, pdc_cacheinfo.dc_stride, 1);
460 sync_caches();
461 }
462