|
|
1.1 ! root 1: /* uba.c 4.36 81/10/27 */ ! 2: ! 3: #include "../h/param.h" ! 4: #include "../h/systm.h" ! 5: #include "../h/cpu.h" ! 6: #include "../h/map.h" ! 7: #include "../h/pte.h" ! 8: #include "../h/buf.h" ! 9: #include "../h/vm.h" ! 10: #include "../h/ubareg.h" ! 11: #include "../h/ubavar.h" ! 12: #include "../h/dir.h" ! 13: #include "../h/user.h" ! 14: #include "../h/proc.h" ! 15: #include "../h/conf.h" ! 16: #include "../h/mtpr.h" ! 17: #include "../h/nexus.h" ! 18: #include "../h/dk.h" ! 19: ! 20: #if VAX780 ! 21: char ubasr_bits[] = UBASR_BITS; ! 22: #endif ! 23: ! 24: /* ! 25: * Do transfer on device argument. The controller ! 26: * and uba involved are implied by the device. ! 27: * We queue for resource wait in the uba code if necessary. ! 28: * We return 1 if the transfer was started, 0 if it was not. ! 29: * If you call this routine with the head of the queue for a ! 30: * UBA, it will automatically remove the device from the UBA ! 31: * queue before it returns. If some other device is given ! 32: * as argument, it will be added to the request queue if the ! 33: * request cannot be started immediately. This means that ! 34: * passing a device which is on the queue but not at the head ! 35: * of the request queue is likely to be a disaster. ! 36: */ ! 37: ubago(ui) ! 38: register struct uba_device *ui; ! 39: { ! 40: register struct uba_ctlr *um = ui->ui_mi; ! 41: register struct uba_hd *uh; ! 42: register int s, unit; ! 43: ! 44: uh = &uba_hd[um->um_ubanum]; ! 45: s = spl6(); ! 46: if (um->um_driver->ud_xclu && uh->uh_users > 0 || uh->uh_xclu) ! 47: goto rwait; ! 48: um->um_ubinfo = ubasetup(um->um_ubanum, um->um_tab.b_actf->b_actf, ! 49: UBA_NEEDBDP|UBA_CANTWAIT); ! 50: if (um->um_ubinfo == 0) ! 51: goto rwait; ! 52: uh->uh_users++; ! 53: if (um->um_driver->ud_xclu) ! 54: uh->uh_xclu = 1; ! 55: splx(s); ! 56: if (ui->ui_dk >= 0) { ! 57: unit = ui->ui_dk; ! 58: dk_busy |= 1<<unit; ! 59: } ! 60: if (uh->uh_actf == ui) ! 61: uh->uh_actf = ui->ui_forw; ! 62: (*um->um_driver->ud_dgo)(um); ! 63: if (ui->ui_dk >= 0) { ! 64: dk_xfer[unit]++; ! 65: dk_wds[unit] += um->um_tab.b_actf->b_actf->b_bcount>>6; ! 66: } ! 67: return (1); ! 68: rwait: ! 69: if (uh->uh_actf != ui) { ! 70: ui->ui_forw = NULL; ! 71: if (uh->uh_actf == NULL) ! 72: uh->uh_actf = ui; ! 73: else ! 74: uh->uh_actl->ui_forw = ui; ! 75: uh->uh_actl = ui; ! 76: } ! 77: splx(s); ! 78: return (0); ! 79: } ! 80: ! 81: ubadone(um) ! 82: register struct uba_ctlr *um; ! 83: { ! 84: register struct uba_hd *uh = &uba_hd[um->um_ubanum]; ! 85: ! 86: if (um->um_driver->ud_xclu) ! 87: uh->uh_xclu = 0; ! 88: uh->uh_users--; ! 89: ubarelse(um->um_ubanum, &um->um_ubinfo); ! 90: } ! 91: ! 92: /* ! 93: * Allocate and setup UBA map registers, and bdp's ! 94: * Flags says whether bdp is needed, whether the caller can't ! 95: * wait (e.g. if the caller is at interrupt level). ! 96: * ! 97: * Return value: ! 98: * Bits 0-8 Byte offset ! 99: * Bits 9-17 Start map reg. no. ! 100: * Bits 18-27 No. mapping reg's ! 101: * Bits 28-31 BDP no. ! 102: */ ! 103: ubasetup(uban, bp, flags) ! 104: struct buf *bp; ! 105: { ! 106: register struct uba_hd *uh = &uba_hd[uban]; ! 107: register int temp, i; ! 108: int npf, reg, bdp; ! 109: unsigned v; ! 110: register struct pte *pte, *io; ! 111: struct proc *rp; ! 112: int a, o, ubinfo; ! 113: ! 114: #if VAX7ZZ ! 115: if (cpu == VAX_7ZZ) ! 116: flags &= ~UBA_NEEDBDP; ! 117: #endif ! 118: v = btop(bp->b_un.b_addr); ! 119: o = (int)bp->b_un.b_addr & PGOFSET; ! 120: npf = btoc(bp->b_bcount + o) + 1; ! 121: a = spl6(); ! 122: while ((reg = rmalloc(uh->uh_map, npf)) == 0) { ! 123: if (flags & UBA_CANTWAIT) { ! 124: splx(a); ! 125: return (0); ! 126: } ! 127: uh->uh_mrwant++; ! 128: sleep((caddr_t)uh->uh_map, PSWP); ! 129: } ! 130: bdp = 0; ! 131: if (flags & UBA_NEEDBDP) { ! 132: while ((bdp = ffs(uh->uh_bdpfree)) == 0) { ! 133: if (flags & UBA_CANTWAIT) { ! 134: rmfree(uh->uh_map, npf, reg); ! 135: splx(a); ! 136: return (0); ! 137: } ! 138: uh->uh_bdpwant++; ! 139: sleep((caddr_t)uh->uh_map, PSWP); ! 140: } ! 141: uh->uh_bdpfree &= ~(1 << (bdp-1)); ! 142: } else if (flags & UBA_HAVEBDP) ! 143: bdp = (flags >> 28) & 0xf; ! 144: splx(a); ! 145: reg--; ! 146: ubinfo = (bdp << 28) | (npf << 18) | (reg << 9) | o; ! 147: io = &uh->uh_uba->uba_map[reg]; ! 148: temp = (bdp << 21) | UBAMR_MRV; ! 149: rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; ! 150: if (bdp && (o & 01)) ! 151: temp |= UBAMR_BO; ! 152: if (bp->b_flags & B_UAREA) { ! 153: for (i = UPAGES - bp->b_bcount / NBPG; i < UPAGES; i++) { ! 154: if (rp->p_addr[i].pg_pfnum == 0) ! 155: panic("uba: zero upage"); ! 156: *(int *)io++ = rp->p_addr[i].pg_pfnum | temp; ! 157: } ! 158: } else if ((bp->b_flags & B_PHYS) == 0) { ! 159: pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)]; ! 160: while (--npf != 0) ! 161: *(int *)io++ = pte++->pg_pfnum | temp; ! 162: } else { ! 163: if (bp->b_flags & B_PAGET) ! 164: pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; ! 165: else ! 166: pte = vtopte(rp, v); ! 167: while (--npf != 0) { ! 168: if (pte->pg_pfnum == 0) ! 169: panic("uba zero uentry"); ! 170: *(int *)io++ = pte++->pg_pfnum | temp; ! 171: } ! 172: } ! 173: *(int *)io++ = 0; ! 174: return (ubinfo); ! 175: } ! 176: ! 177: /* ! 178: * Non buffer setup interface... set up a buffer and call ubasetup. ! 179: */ ! 180: uballoc(uban, addr, bcnt, flags) ! 181: int uban; ! 182: caddr_t addr; ! 183: int bcnt, flags; ! 184: { ! 185: struct buf ubabuf; ! 186: ! 187: ubabuf.b_un.b_addr = addr; ! 188: ubabuf.b_flags = B_BUSY; ! 189: ubabuf.b_bcount = bcnt; ! 190: /* that's all the fields ubasetup() needs */ ! 191: return (ubasetup(uban, &ubabuf, flags)); ! 192: } ! 193: ! 194: /* ! 195: * Release resources on uba uban, and then unblock resource waiters. ! 196: * The map register parameter is by value since we need to block ! 197: * against uba resets on 11/780's. ! 198: */ ! 199: ubarelse(uban, amr) ! 200: int *amr; ! 201: { ! 202: register struct uba_hd *uh = &uba_hd[uban]; ! 203: register int bdp, reg, npf, s; ! 204: int mr; ! 205: ! 206: /* ! 207: * Carefully see if we should release the space, since ! 208: * it may be released asynchronously at uba reset time. ! 209: */ ! 210: s = spl6(); ! 211: mr = *amr; ! 212: if (mr == 0) { ! 213: /* ! 214: * A ubareset() occurred before we got around ! 215: * to releasing the space... no need to bother. ! 216: */ ! 217: splx(s); ! 218: return; ! 219: } ! 220: *amr = 0; ! 221: splx(s); /* let interrupts in, we're safe for a while */ ! 222: bdp = (mr >> 28) & 0x0f; ! 223: if (bdp) { ! 224: switch (cpu) { ! 225: #if VAX780 ! 226: case VAX_780: ! 227: uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; ! 228: break; ! 229: #endif ! 230: #if VAX750 ! 231: case VAX_750: ! 232: uh->uh_uba->uba_dpr[bdp] |= ! 233: UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; ! 234: break; ! 235: #endif ! 236: } ! 237: uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */ ! 238: if (uh->uh_bdpwant) { ! 239: uh->uh_bdpwant = 0; ! 240: wakeup((caddr_t)uh->uh_map); ! 241: } ! 242: } ! 243: /* ! 244: * Put back the registers in the resource map. ! 245: * The map code must not be reentered, so we do this ! 246: * at high ipl. ! 247: */ ! 248: npf = (mr >> 18) & 0x3ff; ! 249: reg = ((mr >> 9) & 0x1ff) + 1; ! 250: s = spl6(); ! 251: rmfree(uh->uh_map, npf, reg); ! 252: splx(s); ! 253: ! 254: /* ! 255: * Wakeup sleepers for map registers, ! 256: * and also, if there are processes blocked in dgo(), ! 257: * give them a chance at the UNIBUS. ! 258: */ ! 259: if (uh->uh_mrwant) { ! 260: uh->uh_mrwant = 0; ! 261: wakeup((caddr_t)uh->uh_map); ! 262: } ! 263: while (uh->uh_actf && ubago(uh->uh_actf)) ! 264: ; ! 265: } ! 266: ! 267: ubapurge(um) ! 268: register struct uba_ctlr *um; ! 269: { ! 270: register struct uba_hd *uh = um->um_hd; ! 271: register int bdp = (um->um_ubinfo >> 28) & 0x0f; ! 272: ! 273: switch (cpu) { ! 274: #if VAX780 ! 275: case VAX_780: ! 276: uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; ! 277: break; ! 278: #endif ! 279: #if VAX750 ! 280: case VAX_750: ! 281: uh->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; ! 282: break; ! 283: #endif ! 284: } ! 285: } ! 286: ! 287: /* ! 288: * Generate a reset on uba number uban. Then ! 289: * call each device in the character device table, ! 290: * giving it a chance to clean up so as to be able to continue. ! 291: */ ! 292: ubareset(uban) ! 293: int uban; ! 294: { ! 295: register struct cdevsw *cdp; ! 296: register struct uba_hd *uh = &uba_hd[uban]; ! 297: int s; ! 298: ! 299: s = spl6(); ! 300: uh->uh_users = 0; ! 301: uh->uh_zvcnt = 0; ! 302: uh->uh_xclu = 0; ! 303: uh->uh_hangcnt = 0; ! 304: uh->uh_actf = uh->uh_actl = 0; ! 305: uh->uh_bdpwant = 0; ! 306: uh->uh_mrwant = 0; ! 307: wakeup((caddr_t)&uh->uh_bdpwant); ! 308: wakeup((caddr_t)&uh->uh_mrwant); ! 309: printf("uba%d: reset", uban); ! 310: ubainit(uh->uh_uba); ! 311: for (cdp = cdevsw; cdp->d_open; cdp++) ! 312: (*cdp->d_reset)(uban); ! 313: printf("\n"); ! 314: splx(s); ! 315: } ! 316: ! 317: /* ! 318: * Init a uba. This is called with a pointer ! 319: * rather than a virtual address since it is called ! 320: * by code which runs with memory mapping disabled. ! 321: * In these cases we really don't need the interrupts ! 322: * enabled, but since we run with ipl high, we don't care ! 323: * if they are, they will never happen anyways. ! 324: */ ! 325: ubainit(uba) ! 326: register struct uba_regs *uba; ! 327: { ! 328: ! 329: switch (cpu) { ! 330: #if VAX780 ! 331: case VAX_780: ! 332: uba->uba_cr = UBACR_ADINIT; ! 333: uba->uba_cr = UBACR_IFS|UBACR_BRIE|UBACR_USEFIE|UBACR_SUEFIE; ! 334: while ((uba->uba_cnfgr & UBACNFGR_UBIC) == 0) ! 335: ; ! 336: break; ! 337: #endif ! 338: #if VAX750 ! 339: case VAX_750: ! 340: #endif ! 341: #if VAX7ZZ ! 342: case VAX_7ZZ: ! 343: #endif ! 344: #if defined(VAX750) || defined(VAX7ZZ) ! 345: mtpr(IUR, 0); ! 346: /* give devices time to recover from power fail */ ! 347: /* THIS IS PROBABLY UNNECESSARY */ ! 348: DELAY(500000); ! 349: /* END PROBABLY UNNECESSARY */ ! 350: break; ! 351: #endif ! 352: } ! 353: } ! 354: ! 355: #if VAX780 ! 356: /* ! 357: * Check to make sure the UNIBUS adaptor is not hung, ! 358: * with an interrupt in the register to be presented, ! 359: * but not presenting it for an extended period (5 seconds). ! 360: */ ! 361: unhang() ! 362: { ! 363: register int uban; ! 364: ! 365: for (uban = 0; uban < numuba; uban++) { ! 366: register struct uba_hd *uh = &uba_hd[uban]; ! 367: register struct uba_regs *up = uh->uh_uba; ! 368: ! 369: if (up->uba_sr == 0) ! 370: return; ! 371: up->uba_sr = UBASR_CRD|UBASR_LEB; ! 372: uh->uh_hangcnt++; ! 373: if (uh->uh_hangcnt > 5*hz) { ! 374: uh->uh_hangcnt = 0; ! 375: printf("uba%d: hung\n", uban); ! 376: ubareset(uban); ! 377: } ! 378: } ! 379: } ! 380: ! 381: /* ! 382: * This is a timeout routine which decrements the ``i forgot to ! 383: * interrupt'' counts, on an 11/780. This prevents slowly growing ! 384: * counts from causing a UBA reset since we are interested only ! 385: * in hang situations. ! 386: */ ! 387: ubawatch() ! 388: { ! 389: register struct uba_hd *uh; ! 390: register int uban; ! 391: ! 392: if (panicstr) ! 393: return; ! 394: for (uban = 0; uban < numuba; uban++) { ! 395: uh = &uba_hd[uban]; ! 396: if (uh->uh_hangcnt) ! 397: uh->uh_hangcnt--; ! 398: } ! 399: } ! 400: ! 401: int ubawedgecnt = 10; ! 402: int ubacrazy = 500; ! 403: /* ! 404: * This routine is called by the locore code to ! 405: * process a UBA error on an 11/780. The arguments are passed ! 406: * on the stack, and value-result (through some trickery). ! 407: * In particular, the uvec argument is used for further ! 408: * uba processing so the result aspect of it is very important. ! 409: * It must not be declared register. ! 410: */ ! 411: /*ARGSUSED*/ ! 412: ubaerror(uban, uh, xx, uvec, uba) ! 413: register int uban; ! 414: register struct uba_hd *uh; ! 415: int uvec; ! 416: register struct uba_regs *uba; ! 417: { ! 418: register sr, s; ! 419: ! 420: if (uvec == 0) { ! 421: uh->uh_zvcnt++; ! 422: if (uh->uh_zvcnt > 250000) { ! 423: printf("uba%d: too many zero vectors\n"); ! 424: ubareset(uban); ! 425: } ! 426: uvec = 0; ! 427: return; ! 428: } ! 429: if (uba->uba_cnfgr & NEX_CFGFLT) { ! 430: printf("uba%d: sbi fault sr=%b cnfgr=%b\n", ! 431: uban, uba->uba_sr, ubasr_bits, ! 432: uba->uba_cnfgr, NEXFLT_BITS); ! 433: ubareset(uban); ! 434: uvec = 0; ! 435: return; ! 436: } ! 437: sr = uba->uba_sr; ! 438: s = spl7(); ! 439: printf("uba%d: uba error sr=%b fmer=%x fubar=%o\n", ! 440: uban, uba->uba_sr, ubasr_bits, uba->uba_fmer, 4*uba->uba_fubar); ! 441: splx(s); ! 442: uba->uba_sr = sr; ! 443: uvec &= UBABRRVR_DIV; ! 444: if (++uh->uh_errcnt % ubawedgecnt == 0) { ! 445: if (uh->uh_errcnt > ubacrazy) ! 446: panic("uba crazy"); ! 447: printf("ERROR LIMIT "); ! 448: ubareset(uban); ! 449: uvec = 0; ! 450: return; ! 451: } ! 452: return; ! 453: } ! 454: #endif ! 455: ! 456: /* ! 457: * This routine allows remapping of previously ! 458: * allocated UNIBUS bdp and map resources ! 459: * onto different memory addresses. ! 460: * It should only be used by routines which need ! 461: * small fixed length mappings for long periods of time ! 462: * (like the ARPANET ACC IMP interface). ! 463: * It only maps kernel addresses. ! 464: */ ! 465: ubaremap(uban, ubinfo, addr) ! 466: int uban; ! 467: register unsigned ubinfo; ! 468: caddr_t addr; ! 469: { ! 470: register struct uba_hd *uh = &uba_hd[uban]; ! 471: register struct pte *pte, *io; ! 472: register int temp, bdp; ! 473: int npf, o; ! 474: ! 475: o = (int)addr & PGOFSET; ! 476: bdp = (ubinfo >> 28) & 0xf; ! 477: npf = (ubinfo >> 18) & 0x3ff; ! 478: io = &uh->uh_uba->uba_map[(ubinfo >> 9) & 0x1ff]; ! 479: temp = (bdp << 21) | UBAMR_MRV; ! 480: ! 481: /* ! 482: * If using buffered data path initiate purge ! 483: * of old data and set byte offset bit if next ! 484: * transfer will be from odd address. ! 485: */ ! 486: if (bdp) { ! 487: switch (cpu) { ! 488: #if VAX780 ! 489: case VAX_780: ! 490: uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; ! 491: break; ! 492: #endif ! 493: #if VAX750 ! 494: case VAX_750: ! 495: uh->uh_uba->uba_dpr[bdp] |= ! 496: UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; ! 497: break; ! 498: #endif ! 499: } ! 500: if (o & 1) ! 501: temp |= UBAMR_BO; ! 502: } ! 503: ! 504: /* ! 505: * Set up the map registers, leaving an invalid reg ! 506: * at the end to guard against wild unibus transfers. ! 507: */ ! 508: pte = &Sysmap[btop(((int)addr)&0x7fffffff)]; ! 509: while (--npf != 0) ! 510: *(int *)io++ = pte++->pg_pfnum | temp; ! 511: *(int *)io = 0; ! 512: ! 513: /* ! 514: * Return effective UNIBUS address. ! 515: */ ! 516: return (ubinfo | o); ! 517: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.