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