Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
b00a6fef | 6 | * @(#)uba.c 7.6 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
961945a8 SL |
8 | |
9 | #include "../machine/pte.h" | |
c14fd247 | 10 | |
ff360633 JB |
11 | #include "param.h" |
12 | #include "systm.h" | |
13 | #include "map.h" | |
14 | #include "buf.h" | |
15 | #include "vm.h" | |
16 | #include "dir.h" | |
17 | #include "user.h" | |
18 | #include "proc.h" | |
19 | #include "conf.h" | |
8e4980c8 | 20 | #include "dkstat.h" |
ff360633 | 21 | #include "kernel.h" |
b7333467 | 22 | |
896962b1 BJ |
23 | #include "../vax/cpu.h" |
24 | #include "../vax/mtpr.h" | |
25 | #include "../vax/nexus.h" | |
ff360633 JB |
26 | #include "ubareg.h" |
27 | #include "ubavar.h" | |
896962b1 | 28 | |
63503d24 | 29 | #ifdef DW780 |
5af3f3f7 BJ |
30 | char ubasr_bits[] = UBASR_BITS; |
31 | #endif | |
32 | ||
8011f5df MK |
33 | #define spluba spl7 /* IPL 17 */ |
34 | ||
861488c5 KB |
35 | #define BDPMASK 0xf0000000 /* see ubavar.h */ |
36 | ||
b7333467 BJ |
37 | /* |
38 | * Do transfer on device argument. The controller | |
39 | * and uba involved are implied by the device. | |
40 | * We queue for resource wait in the uba code if necessary. | |
41 | * We return 1 if the transfer was started, 0 if it was not. | |
861488c5 KB |
42 | * |
43 | * The onq argument must be zero iff the device is not on the | |
44 | * queue for this UBA. If onq is set, the device must be at the | |
45 | * head of the queue. In any case, if the transfer is started, | |
46 | * the device will be off the queue, and if not, it will be on. | |
47 | * | |
48 | * Drivers that allocate one BDP and hold it for some time should | |
49 | * set ud_keepbdp. In this case um_bdp tells which BDP is allocated | |
50 | * to the controller, unless it is zero, indicating that the controller | |
51 | * does not now have a BDP. | |
b7333467 | 52 | */ |
861488c5 | 53 | ubaqueue(ui, onq) |
5ab42896 | 54 | register struct uba_device *ui; |
861488c5 | 55 | int onq; |
b7333467 | 56 | { |
5ab42896 | 57 | register struct uba_ctlr *um = ui->ui_mi; |
b7333467 | 58 | register struct uba_hd *uh; |
861488c5 | 59 | register struct uba_driver *ud; |
b7333467 BJ |
60 | register int s, unit; |
61 | ||
62 | uh = &uba_hd[um->um_ubanum]; | |
861488c5 | 63 | ud = um->um_driver; |
8011f5df | 64 | s = spluba(); |
861488c5 KB |
65 | /* |
66 | * Honor exclusive BDP use requests. | |
67 | */ | |
68 | if (ud->ud_xclu && uh->uh_users > 0 || uh->uh_xclu) | |
0801d37f | 69 | goto rwait; |
861488c5 KB |
70 | if (ud->ud_keepbdp) { |
71 | /* | |
72 | * First get just a BDP (though in fact it comes with | |
73 | * one map register too). | |
74 | */ | |
75 | if (um->um_bdp == 0) { | |
76 | um->um_bdp = uballoc(um->um_ubanum, | |
77 | (caddr_t)0, 0, UBA_NEEDBDP|UBA_CANTWAIT); | |
78 | if (um->um_bdp == 0) | |
79 | goto rwait; | |
80 | } | |
81 | /* now share it with this transfer */ | |
82 | um->um_ubinfo = ubasetup(um->um_ubanum, | |
83 | um->um_tab.b_actf->b_actf, | |
84 | um->um_bdp|UBA_HAVEBDP|UBA_CANTWAIT); | |
85 | } else | |
86 | um->um_ubinfo = ubasetup(um->um_ubanum, | |
87 | um->um_tab.b_actf->b_actf, UBA_NEEDBDP|UBA_CANTWAIT); | |
0801d37f BJ |
88 | if (um->um_ubinfo == 0) |
89 | goto rwait; | |
0801d37f | 90 | uh->uh_users++; |
861488c5 | 91 | if (ud->ud_xclu) |
0801d37f | 92 | uh->uh_xclu = 1; |
b7333467 BJ |
93 | splx(s); |
94 | if (ui->ui_dk >= 0) { | |
95 | unit = ui->ui_dk; | |
96 | dk_busy |= 1<<unit; | |
cc7ff771 BJ |
97 | dk_xfer[unit]++; |
98 | dk_wds[unit] += um->um_tab.b_actf->b_actf->b_bcount>>6; | |
b7333467 | 99 | } |
861488c5 | 100 | if (onq) |
b7333467 | 101 | uh->uh_actf = ui->ui_forw; |
861488c5 | 102 | (*ud->ud_dgo)(um); |
b7333467 | 103 | return (1); |
0801d37f | 104 | rwait: |
861488c5 | 105 | if (!onq) { |
0801d37f BJ |
106 | ui->ui_forw = NULL; |
107 | if (uh->uh_actf == NULL) | |
108 | uh->uh_actf = ui; | |
109 | else | |
110 | uh->uh_actl->ui_forw = ui; | |
111 | uh->uh_actl = ui; | |
112 | } | |
113 | splx(s); | |
114 | return (0); | |
115 | } | |
116 | ||
117 | ubadone(um) | |
5ab42896 | 118 | register struct uba_ctlr *um; |
0801d37f BJ |
119 | { |
120 | register struct uba_hd *uh = &uba_hd[um->um_ubanum]; | |
121 | ||
28ca05a9 | 122 | if (um->um_driver->ud_xclu) |
0801d37f BJ |
123 | uh->uh_xclu = 0; |
124 | uh->uh_users--; | |
861488c5 KB |
125 | if (um->um_driver->ud_keepbdp) |
126 | um->um_ubinfo &= ~BDPMASK; /* keep BDP for misers */ | |
0801d37f | 127 | ubarelse(um->um_ubanum, &um->um_ubinfo); |
b7333467 | 128 | } |
c14fd247 BJ |
129 | |
130 | /* | |
3f3a34c3 BJ |
131 | * Allocate and setup UBA map registers, and bdp's |
132 | * Flags says whether bdp is needed, whether the caller can't | |
133 | * wait (e.g. if the caller is at interrupt level). | |
c14fd247 | 134 | * |
b7333467 | 135 | * Return value: |
c14fd247 BJ |
136 | * Bits 0-8 Byte offset |
137 | * Bits 9-17 Start map reg. no. | |
138 | * Bits 18-27 No. mapping reg's | |
139 | * Bits 28-31 BDP no. | |
140 | */ | |
3f3a34c3 | 141 | ubasetup(uban, bp, flags) |
b0a4a8c6 MK |
142 | int uban; |
143 | register struct buf *bp; | |
144 | register int flags; | |
c14fd247 | 145 | { |
3f3a34c3 | 146 | register struct uba_hd *uh = &uba_hd[uban]; |
b0a4a8c6 MK |
147 | register struct pte *pte, *io; |
148 | register int npf; | |
553d288e | 149 | int pfnum, temp; |
b0a4a8c6 | 150 | int reg, bdp; |
c14fd247 | 151 | unsigned v; |
c14fd247 BJ |
152 | struct proc *rp; |
153 | int a, o, ubinfo; | |
154 | ||
63503d24 MK |
155 | #ifdef DW730 |
156 | if (uh->uh_type == DW730) | |
157 | flags &= ~UBA_NEEDBDP; | |
158 | #endif | |
159 | #ifdef QBA | |
160 | if (uh->uh_type == QBA) | |
a3812a04 BJ |
161 | flags &= ~UBA_NEEDBDP; |
162 | #endif | |
c14fd247 BJ |
163 | o = (int)bp->b_un.b_addr & PGOFSET; |
164 | npf = btoc(bp->b_bcount + o) + 1; | |
8011f5df | 165 | a = spluba(); |
5d30e870 | 166 | while ((reg = rmalloc(uh->uh_map, (long)npf)) == 0) { |
dd56673b BJ |
167 | if (flags & UBA_CANTWAIT) { |
168 | splx(a); | |
3f3a34c3 | 169 | return (0); |
dd56673b | 170 | } |
3f3a34c3 | 171 | uh->uh_mrwant++; |
174d2438 | 172 | sleep((caddr_t)&uh->uh_mrwant, PSWP); |
c14fd247 | 173 | } |
ee0fdd94 MK |
174 | if ((flags & UBA_NEED16) && reg + npf > 128) { |
175 | /* | |
176 | * Could hang around and try again (if we can ever succeed). | |
177 | * Won't help any current device... | |
178 | */ | |
179 | rmfree(uh->uh_map, (long)npf, (long)reg); | |
180 | splx(a); | |
181 | return (0); | |
182 | } | |
c14fd247 | 183 | bdp = 0; |
3f3a34c3 | 184 | if (flags & UBA_NEEDBDP) { |
8011f5df | 185 | while ((bdp = ffs((long)uh->uh_bdpfree)) == 0) { |
3f3a34c3 | 186 | if (flags & UBA_CANTWAIT) { |
5d30e870 | 187 | rmfree(uh->uh_map, (long)npf, (long)reg); |
dd56673b | 188 | splx(a); |
3f3a34c3 BJ |
189 | return (0); |
190 | } | |
191 | uh->uh_bdpwant++; | |
174d2438 | 192 | sleep((caddr_t)&uh->uh_bdpwant, PSWP); |
c14fd247 | 193 | } |
658110d5 | 194 | uh->uh_bdpfree &= ~(1 << (bdp-1)); |
64614526 BJ |
195 | } else if (flags & UBA_HAVEBDP) |
196 | bdp = (flags >> 28) & 0xf; | |
c14fd247 | 197 | splx(a); |
658110d5 | 198 | reg--; |
c14fd247 | 199 | ubinfo = (bdp << 28) | (npf << 18) | (reg << 9) | o; |
5ab42896 | 200 | temp = (bdp << 21) | UBAMR_MRV; |
c14fd247 | 201 | if (bdp && (o & 01)) |
5ab42896 | 202 | temp |= UBAMR_BO; |
309cfbf4 | 203 | if ((bp->b_flags & B_PHYS) == 0) |
b0a4a8c6 | 204 | pte = kvtopte(bp->b_un.b_addr); |
309cfbf4 BJ |
205 | else if (bp->b_flags & B_PAGET) |
206 | pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; | |
b0a4a8c6 MK |
207 | else { |
208 | rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; | |
209 | v = btop(bp->b_un.b_addr); | |
210 | if (bp->b_flags & B_UAREA) | |
211 | pte = &rp->p_addr[v]; | |
212 | else | |
213 | pte = vtopte(rp, v); | |
214 | } | |
63503d24 | 215 | io = &uh->uh_mr[reg]; |
b0a4a8c6 | 216 | while (--npf > 0) { |
553d288e KM |
217 | pfnum = pte->pg_pfnum; |
218 | if (pfnum == 0) | |
309cfbf4 | 219 | panic("uba zero uentry"); |
553d288e KM |
220 | pte++; |
221 | *(int *)io++ = pfnum | temp; | |
c14fd247 | 222 | } |
b0a4a8c6 | 223 | *(int *)io = 0; |
c14fd247 BJ |
224 | return (ubinfo); |
225 | } | |
226 | ||
c14fd247 | 227 | /* |
b7333467 | 228 | * Non buffer setup interface... set up a buffer and call ubasetup. |
c14fd247 | 229 | */ |
3f3a34c3 | 230 | uballoc(uban, addr, bcnt, flags) |
a0eab615 | 231 | int uban; |
c14fd247 | 232 | caddr_t addr; |
a0eab615 | 233 | int bcnt, flags; |
c14fd247 | 234 | { |
89e0f717 | 235 | struct buf ubabuf; |
c14fd247 | 236 | |
c14fd247 BJ |
237 | ubabuf.b_un.b_addr = addr; |
238 | ubabuf.b_flags = B_BUSY; | |
239 | ubabuf.b_bcount = bcnt; | |
89e0f717 | 240 | /* that's all the fields ubasetup() needs */ |
3f3a34c3 | 241 | return (ubasetup(uban, &ubabuf, flags)); |
c14fd247 BJ |
242 | } |
243 | ||
b28deaf8 | 244 | /* |
b7333467 BJ |
245 | * Release resources on uba uban, and then unblock resource waiters. |
246 | * The map register parameter is by value since we need to block | |
247 | * against uba resets on 11/780's. | |
b28deaf8 | 248 | */ |
3f3a34c3 | 249 | ubarelse(uban, amr) |
b28deaf8 | 250 | int *amr; |
c14fd247 | 251 | { |
3f3a34c3 | 252 | register struct uba_hd *uh = &uba_hd[uban]; |
b7333467 | 253 | register int bdp, reg, npf, s; |
b28deaf8 | 254 | int mr; |
c14fd247 | 255 | |
b7333467 BJ |
256 | /* |
257 | * Carefully see if we should release the space, since | |
258 | * it may be released asynchronously at uba reset time. | |
259 | */ | |
8011f5df | 260 | s = spluba(); |
b28deaf8 BJ |
261 | mr = *amr; |
262 | if (mr == 0) { | |
b7333467 BJ |
263 | /* |
264 | * A ubareset() occurred before we got around | |
265 | * to releasing the space... no need to bother. | |
266 | */ | |
267 | splx(s); | |
b28deaf8 BJ |
268 | return; |
269 | } | |
88149598 | 270 | *amr = 0; |
c14fd247 BJ |
271 | bdp = (mr >> 28) & 0x0f; |
272 | if (bdp) { | |
63503d24 | 273 | switch (uh->uh_type) { |
b0a4a8c6 MK |
274 | #ifdef DWBUA |
275 | case DWBUA: | |
276 | BUA(uh->uh_uba)->bua_dpr[bdp] |= BUADPR_PURGE; | |
277 | break; | |
278 | #endif | |
63503d24 MK |
279 | #ifdef DW780 |
280 | case DW780: | |
5ab42896 | 281 | uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; |
5aa9d5ea RE |
282 | break; |
283 | #endif | |
63503d24 MK |
284 | #ifdef DW750 |
285 | case DW750: | |
5ab42896 BJ |
286 | uh->uh_uba->uba_dpr[bdp] |= |
287 | UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; | |
5aa9d5ea RE |
288 | break; |
289 | #endif | |
63503d24 MK |
290 | default: |
291 | break; | |
5aa9d5ea | 292 | } |
b7333467 | 293 | uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */ |
3f3a34c3 BJ |
294 | if (uh->uh_bdpwant) { |
295 | uh->uh_bdpwant = 0; | |
174d2438 | 296 | wakeup((caddr_t)&uh->uh_bdpwant); |
c14fd247 BJ |
297 | } |
298 | } | |
b7333467 BJ |
299 | /* |
300 | * Put back the registers in the resource map. | |
ee0fdd94 MK |
301 | * The map code must not be reentered, |
302 | * nor can the registers be freed twice. | |
303 | * Unblock interrupts once this is done. | |
b7333467 | 304 | */ |
c14fd247 BJ |
305 | npf = (mr >> 18) & 0x3ff; |
306 | reg = ((mr >> 9) & 0x1ff) + 1; | |
5d30e870 | 307 | rmfree(uh->uh_map, (long)npf, (long)reg); |
b7333467 BJ |
308 | splx(s); |
309 | ||
310 | /* | |
311 | * Wakeup sleepers for map registers, | |
312 | * and also, if there are processes blocked in dgo(), | |
313 | * give them a chance at the UNIBUS. | |
314 | */ | |
3f3a34c3 BJ |
315 | if (uh->uh_mrwant) { |
316 | uh->uh_mrwant = 0; | |
174d2438 | 317 | wakeup((caddr_t)&uh->uh_mrwant); |
c14fd247 | 318 | } |
861488c5 | 319 | while (uh->uh_actf && ubaqueue(uh->uh_actf, 1)) |
b7333467 | 320 | ; |
c14fd247 BJ |
321 | } |
322 | ||
27bf6b55 | 323 | ubapurge(um) |
5ab42896 | 324 | register struct uba_ctlr *um; |
27bf6b55 BJ |
325 | { |
326 | register struct uba_hd *uh = um->um_hd; | |
327 | register int bdp = (um->um_ubinfo >> 28) & 0x0f; | |
328 | ||
63503d24 | 329 | switch (uh->uh_type) { |
b0a4a8c6 MK |
330 | #ifdef DWBUA |
331 | case DWBUA: | |
332 | BUA(uh->uh_uba)->bua_dpr[bdp] |= BUADPR_PURGE; | |
333 | break; | |
334 | #endif | |
63503d24 MK |
335 | #ifdef DW780 |
336 | case DW780: | |
5ab42896 | 337 | uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; |
27bf6b55 BJ |
338 | break; |
339 | #endif | |
63503d24 MK |
340 | #ifdef DW750 |
341 | case DW750: | |
5ab42896 | 342 | uh->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; |
27bf6b55 BJ |
343 | break; |
344 | #endif | |
63503d24 MK |
345 | default: |
346 | break; | |
27bf6b55 BJ |
347 | } |
348 | } | |
349 | ||
9305c2b9 BJ |
350 | ubainitmaps(uhp) |
351 | register struct uba_hd *uhp; | |
352 | { | |
353 | ||
63503d24 MK |
354 | rminit(uhp->uh_map, (long)uhp->uh_memsize, (long)1, "uba", UAMSIZ); |
355 | switch (uhp->uh_type) { | |
b0a4a8c6 MK |
356 | #ifdef DWBUA |
357 | case DWBUA: | |
358 | uhp->uh_bdpfree = (1<<NBDPBUA) - 1; | |
359 | break; | |
360 | #endif | |
63503d24 MK |
361 | #ifdef DW780 |
362 | case DW780: | |
9305c2b9 BJ |
363 | uhp->uh_bdpfree = (1<<NBDP780) - 1; |
364 | break; | |
365 | #endif | |
63503d24 MK |
366 | #ifdef DW750 |
367 | case DW750: | |
9305c2b9 BJ |
368 | uhp->uh_bdpfree = (1<<NBDP750) - 1; |
369 | break; | |
370 | #endif | |
63503d24 | 371 | default: |
9305c2b9 | 372 | break; |
9305c2b9 BJ |
373 | } |
374 | } | |
375 | ||
b7333467 BJ |
376 | /* |
377 | * Generate a reset on uba number uban. Then | |
378 | * call each device in the character device table, | |
379 | * giving it a chance to clean up so as to be able to continue. | |
380 | */ | |
3f3a34c3 | 381 | ubareset(uban) |
b7333467 | 382 | int uban; |
2e74ef16 | 383 | { |
2e74ef16 | 384 | register struct cdevsw *cdp; |
a3cb8f60 | 385 | register struct uba_hd *uh = &uba_hd[uban]; |
49c84d3f | 386 | int s; |
2e74ef16 | 387 | |
8011f5df | 388 | s = spluba(); |
a3cb8f60 BJ |
389 | uh->uh_users = 0; |
390 | uh->uh_zvcnt = 0; | |
391 | uh->uh_xclu = 0; | |
a3cb8f60 BJ |
392 | uh->uh_actf = uh->uh_actl = 0; |
393 | uh->uh_bdpwant = 0; | |
394 | uh->uh_mrwant = 0; | |
9305c2b9 | 395 | ubainitmaps(uh); |
a3cb8f60 BJ |
396 | wakeup((caddr_t)&uh->uh_bdpwant); |
397 | wakeup((caddr_t)&uh->uh_mrwant); | |
5ab42896 BJ |
398 | printf("uba%d: reset", uban); |
399 | ubainit(uh->uh_uba); | |
ee0fdd94 | 400 | ubameminit(uban); |
512bbccd | 401 | for (cdp = cdevsw; cdp < cdevsw + nchrdev; cdp++) |
3f3a34c3 | 402 | (*cdp->d_reset)(uban); |
4c3f4cb1 | 403 | ifubareset(uban); |
2e74ef16 | 404 | printf("\n"); |
4ea0bfc4 | 405 | splx(s); |
2e74ef16 | 406 | } |
3f3a34c3 | 407 | |
b7333467 BJ |
408 | /* |
409 | * Init a uba. This is called with a pointer | |
410 | * rather than a virtual address since it is called | |
411 | * by code which runs with memory mapping disabled. | |
412 | * In these cases we really don't need the interrupts | |
413 | * enabled, but since we run with ipl high, we don't care | |
414 | * if they are, they will never happen anyways. | |
63503d24 | 415 | * SHOULD GET POINTER TO UBA_HD INSTEAD OF UBA. |
b7333467 | 416 | */ |
5aa9d5ea RE |
417 | ubainit(uba) |
418 | register struct uba_regs *uba; | |
3f3a34c3 | 419 | { |
63503d24 | 420 | register struct uba_hd *uhp; |
b0a4a8c6 | 421 | #ifdef QBA |
63503d24 | 422 | int isphys = 0; |
b0a4a8c6 | 423 | #endif |
3f3a34c3 | 424 | |
63503d24 MK |
425 | for (uhp = uba_hd; uhp < uba_hd + numuba; uhp++) { |
426 | if (uhp->uh_uba == uba) | |
427 | break; | |
428 | if (uhp->uh_physuba == uba) { | |
b0a4a8c6 | 429 | #ifdef QBA |
63503d24 | 430 | isphys++; |
b0a4a8c6 | 431 | #endif |
63503d24 MK |
432 | break; |
433 | } | |
434 | } | |
435 | if (uhp >= uba_hd + numuba) { | |
436 | printf("init unknown uba\n"); | |
437 | return; | |
438 | } | |
439 | ||
440 | switch (uhp->uh_type) { | |
b0a4a8c6 MK |
441 | #ifdef DWBUA |
442 | case DWBUA: | |
443 | BUA(uba)->bua_csr |= BUACSR_UPI; | |
444 | /* give devices time to recover from power fail */ | |
445 | DELAY(500000); | |
446 | break; | |
447 | #endif | |
63503d24 MK |
448 | #ifdef DW780 |
449 | case DW780: | |
5ab42896 BJ |
450 | uba->uba_cr = UBACR_ADINIT; |
451 | uba->uba_cr = UBACR_IFS|UBACR_BRIE|UBACR_USEFIE|UBACR_SUEFIE; | |
452 | while ((uba->uba_cnfgr & UBACNFGR_UBIC) == 0) | |
453 | ; | |
454 | break; | |
455 | #endif | |
63503d24 MK |
456 | #ifdef DW750 |
457 | case DW750: | |
a3812a04 | 458 | #endif |
63503d24 MK |
459 | #ifdef DW730 |
460 | case DW730: | |
fed9edca | 461 | #endif |
63503d24 MK |
462 | #ifdef QBA |
463 | case QBA: | |
9d2503c6 | 464 | #endif |
63503d24 | 465 | #if DW750 || DW730 || QBA |
fed9edca BJ |
466 | mtpr(IUR, 0); |
467 | /* give devices time to recover from power fail */ | |
468 | /* THIS IS PROBABLY UNNECESSARY */ | |
469 | DELAY(500000); | |
470 | /* END PROBABLY UNNECESSARY */ | |
63503d24 MK |
471 | #ifdef QBA |
472 | /* | |
473 | * Re-enable local memory access | |
474 | * from the Q-bus. | |
475 | */ | |
476 | if (uhp->uh_type == QBA) { | |
477 | if (isphys) | |
478 | *((char *)QIOPAGE630 + QIPCR) = Q_LMEAE; | |
479 | else | |
480 | *(uhp->uh_iopage + QIPCR) = Q_LMEAE; | |
481 | } | |
482 | #endif QBA | |
5ab42896 | 483 | break; |
63503d24 | 484 | #endif DW750 || DW730 || QBA |
5ab42896 | 485 | } |
3f3a34c3 BJ |
486 | } |
487 | ||
63503d24 | 488 | #ifdef DW780 |
3e04ba6a BJ |
489 | int ubawedgecnt = 10; |
490 | int ubacrazy = 500; | |
ee0fdd94 | 491 | int zvcnt_max = 5000; /* in 8 sec */ |
b7333467 | 492 | /* |
46bfb00b JB |
493 | * This routine is called by the locore code to process a UBA |
494 | * error on an 11/780 or 8600. The arguments are passed | |
b7333467 BJ |
495 | * on the stack, and value-result (through some trickery). |
496 | * In particular, the uvec argument is used for further | |
497 | * uba processing so the result aspect of it is very important. | |
498 | * It must not be declared register. | |
499 | */ | |
5aa9d5ea | 500 | /*ARGSUSED*/ |
ee0fdd94 | 501 | ubaerror(uban, uh, ipl, uvec, uba) |
3f3a34c3 BJ |
502 | register int uban; |
503 | register struct uba_hd *uh; | |
ee0fdd94 | 504 | int ipl, uvec; |
3f3a34c3 BJ |
505 | register struct uba_regs *uba; |
506 | { | |
507 | register sr, s; | |
508 | ||
509 | if (uvec == 0) { | |
45d4a789 MK |
510 | /* |
511 | * Declare dt as unsigned so that negative values | |
512 | * are handled as >8 below, in case time was set back. | |
513 | */ | |
514 | u_long dt = time.tv_sec - uh->uh_zvtime; | |
515 | ||
516 | uh->uh_zvtotal++; | |
ee0fdd94 | 517 | if (dt > 8) { |
45d4a789 | 518 | uh->uh_zvtime = time.tv_sec; |
ee0fdd94 MK |
519 | uh->uh_zvcnt = 0; |
520 | } | |
521 | if (++uh->uh_zvcnt > zvcnt_max) { | |
522 | printf("uba%d: too many zero vectors (%d in <%d sec)\n", | |
523 | uban, uh->uh_zvcnt, dt + 1); | |
524 | printf("\tIPL 0x%x\n\tcnfgr: %b Adapter Code: 0x%x\n", | |
525 | ipl, uba->uba_cnfgr&(~0xff), UBACNFGR_BITS, | |
526 | uba->uba_cnfgr&0xff); | |
527 | printf("\tsr: %b\n\tdcr: %x (MIC %sOK)\n", | |
528 | uba->uba_sr, ubasr_bits, uba->uba_dcr, | |
529 | (uba->uba_dcr&0x8000000)?"":"NOT "); | |
3f3a34c3 BJ |
530 | ubareset(uban); |
531 | } | |
3f3a34c3 BJ |
532 | return; |
533 | } | |
534 | if (uba->uba_cnfgr & NEX_CFGFLT) { | |
5af3f3f7 BJ |
535 | printf("uba%d: sbi fault sr=%b cnfgr=%b\n", |
536 | uban, uba->uba_sr, ubasr_bits, | |
d2f165e5 | 537 | uba->uba_cnfgr, NEXFLT_BITS); |
3f3a34c3 BJ |
538 | ubareset(uban); |
539 | uvec = 0; | |
540 | return; | |
541 | } | |
542 | sr = uba->uba_sr; | |
8011f5df | 543 | s = spluba(); |
ec28fe15 BJ |
544 | printf("uba%d: uba error sr=%b fmer=%x fubar=%o\n", |
545 | uban, uba->uba_sr, ubasr_bits, uba->uba_fmer, 4*uba->uba_fubar); | |
3f3a34c3 BJ |
546 | splx(s); |
547 | uba->uba_sr = sr; | |
5ab42896 | 548 | uvec &= UBABRRVR_DIV; |
3e04ba6a BJ |
549 | if (++uh->uh_errcnt % ubawedgecnt == 0) { |
550 | if (uh->uh_errcnt > ubacrazy) | |
551 | panic("uba crazy"); | |
552 | printf("ERROR LIMIT "); | |
553 | ubareset(uban); | |
554 | uvec = 0; | |
555 | return; | |
556 | } | |
3f3a34c3 BJ |
557 | return; |
558 | } | |
559 | #endif | |
1c1f6ecf | 560 | |
ee0fdd94 MK |
561 | /* |
562 | * Look for devices with unibus memory, allow them to configure, then disable | |
563 | * map registers as necessary. Called during autoconfiguration and ubareset. | |
564 | * The device ubamem routine returns 0 on success, 1 on success if it is fully | |
565 | * configured (has no csr or interrupt, so doesn't need to be probed), | |
566 | * and -1 on failure. | |
567 | */ | |
568 | ubameminit(uban) | |
569 | { | |
570 | register struct uba_device *ui; | |
571 | register struct uba_hd *uh = &uba_hd[uban]; | |
572 | caddr_t umembase = umem[uban] + 0x3e000, addr; | |
573 | #define ubaoff(off) ((int)(off) & 0x1fff) | |
574 | ||
575 | uh->uh_lastmem = 0; | |
576 | for (ui = ubdinit; ui->ui_driver; ui++) { | |
577 | if (ui->ui_ubanum != uban && ui->ui_ubanum != '?') | |
578 | continue; | |
579 | if (ui->ui_driver->ud_ubamem) { | |
580 | /* | |
581 | * During autoconfiguration, need to fudge ui_addr. | |
582 | */ | |
583 | addr = ui->ui_addr; | |
584 | ui->ui_addr = umembase + ubaoff(addr); | |
585 | switch ((*ui->ui_driver->ud_ubamem)(ui, uban)) { | |
586 | case 1: | |
587 | ui->ui_alive = 1; | |
588 | /* FALLTHROUGH */ | |
589 | case 0: | |
590 | ui->ui_ubanum = uban; | |
591 | break; | |
592 | } | |
593 | ui->ui_addr = addr; | |
594 | } | |
595 | } | |
63503d24 | 596 | #ifdef DW780 |
ee0fdd94 | 597 | /* |
63503d24 | 598 | * On a DW780, throw away any map registers disabled by rounding |
ee0fdd94 MK |
599 | * the map disable in the configuration register |
600 | * up to the next 8K boundary, or below the last unibus memory. | |
601 | */ | |
63503d24 | 602 | if (uh->uh_type == DW780) { |
ee0fdd94 MK |
603 | register i; |
604 | ||
605 | i = btop(((uh->uh_lastmem + 8191) / 8192) * 8192); | |
606 | while (i) | |
607 | (void) rmget(uh->uh_map, 1, i--); | |
608 | } | |
609 | #endif | |
610 | } | |
611 | ||
1c1f6ecf | 612 | /* |
002dfe8e SL |
613 | * Allocate UNIBUS memory. Allocates and initializes |
614 | * sufficient mapping registers for access. On a 780, | |
615 | * the configuration register is setup to disable UBA | |
616 | * response on DMA transfers to addresses controlled | |
617 | * by the disabled mapping registers. | |
63503d24 | 618 | * On a DW780, should only be called from ubameminit, or in ascending order |
ee0fdd94 MK |
619 | * from 0 with 8K-sized and -aligned addresses; freeing memory that isn't |
620 | * the last unibus memory would free unusable map registers. | |
621 | * Doalloc is 1 to allocate, 0 to deallocate. | |
1c1f6ecf | 622 | */ |
002dfe8e SL |
623 | ubamem(uban, addr, npg, doalloc) |
624 | int uban, addr, npg, doalloc; | |
1c1f6ecf BF |
625 | { |
626 | register struct uba_hd *uh = &uba_hd[uban]; | |
002dfe8e | 627 | register int a; |
ee0fdd94 | 628 | int s; |
1c1f6ecf | 629 | |
ee0fdd94 | 630 | a = (addr >> 9) + 1; |
8011f5df | 631 | s = spluba(); |
ee0fdd94 MK |
632 | if (doalloc) |
633 | a = rmget(uh->uh_map, npg, a); | |
634 | else | |
635 | rmfree(uh->uh_map, (long)npg, (long)a); | |
636 | splx(s); | |
1c1f6ecf | 637 | if (a) { |
002dfe8e SL |
638 | register int i, *m; |
639 | ||
63503d24 | 640 | m = (int *)&uh->uh_mr[a - 1]; |
002dfe8e | 641 | for (i = 0; i < npg; i++) |
1c1f6ecf | 642 | *m++ = 0; /* All off, especially 'valid' */ |
ee0fdd94 MK |
643 | i = addr + npg * 512; |
644 | if (doalloc && i > uh->uh_lastmem) | |
645 | uh->uh_lastmem = i; | |
646 | else if (doalloc == 0 && i == uh->uh_lastmem) | |
647 | uh->uh_lastmem = addr; | |
63503d24 | 648 | #ifdef DW780 |
002dfe8e SL |
649 | /* |
650 | * On a 780, set up the map register disable | |
651 | * field in the configuration register. Beware | |
ee0fdd94 MK |
652 | * of callers that request memory ``out of order'' |
653 | * or in sections other than 8K multiples. | |
654 | * Ubameminit handles such requests properly, however. | |
002dfe8e | 655 | */ |
63503d24 | 656 | if (uh->uh_type == DW780) { |
ee0fdd94 MK |
657 | i = uh->uh_uba->uba_cr &~ 0x7c000000; |
658 | i |= ((uh->uh_lastmem + 8191) / 8192) << 26; | |
659 | uh->uh_uba->uba_cr = i; | |
a26646de BF |
660 | } |
661 | #endif | |
1c1f6ecf | 662 | } |
002dfe8e | 663 | return (a); |
1c1f6ecf | 664 | } |
8e61f556 | 665 | |
413f33da | 666 | #include "ik.h" |
37ccce8f JG |
667 | #include "vs.h" |
668 | #if NIK > 0 || NVS > 0 | |
8e61f556 SL |
669 | /* |
670 | * Map a virtual address into users address space. Actually all we | |
671 | * do is turn on the user mode write protection bits for the particular | |
672 | * page of memory involved. | |
673 | */ | |
674 | maptouser(vaddress) | |
675 | caddr_t vaddress; | |
676 | { | |
677 | ||
b0a4a8c6 | 678 | kvtopte(vaddress)->pg_prot = (PG_UW >> 27); |
8e61f556 SL |
679 | } |
680 | ||
681 | unmaptouser(vaddress) | |
682 | caddr_t vaddress; | |
683 | { | |
684 | ||
b0a4a8c6 | 685 | kvtopte(vaddress)->pg_prot = (PG_KW >> 27); |
8e61f556 | 686 | } |
3b1e560f | 687 | #endif |