1*2929Swnj /* uba.c 4.19 03/06/81 */ 240Sbill 32570Swnj #define DELAY(N) { register int d; d = N; while (--d > 0); } 42570Swnj 540Sbill #include "../h/param.h" 62395Swnj #include "../h/systm.h" 72395Swnj #include "../h/cpu.h" 840Sbill #include "../h/map.h" 940Sbill #include "../h/pte.h" 102395Swnj #include "../h/buf.h" 112570Swnj #include "../h/vm.h" 1240Sbill #include "../h/uba.h" 1340Sbill #include "../h/dir.h" 1440Sbill #include "../h/user.h" 1540Sbill #include "../h/proc.h" 16284Sbill #include "../h/conf.h" 171901Swnj #include "../h/mtpr.h" 182395Swnj #include "../h/nexus.h" 192570Swnj #include "../h/dk.h" 2040Sbill 21*2929Swnj #if VAX780 22*2929Swnj char ubasr_bits[] = UBASR_BITS; 23*2929Swnj #endif 24*2929Swnj 2540Sbill /* 262570Swnj * Do transfer on device argument. The controller 272570Swnj * and uba involved are implied by the device. 282570Swnj * We queue for resource wait in the uba code if necessary. 292570Swnj * We return 1 if the transfer was started, 0 if it was not. 302570Swnj * If you call this routine with the head of the queue for a 312570Swnj * UBA, it will automatically remove the device from the UBA 322570Swnj * queue before it returns. If some other device is given 332570Swnj * as argument, it will be added to the request queue if the 342570Swnj * request cannot be started immediately. This means that 352570Swnj * passing a device which is on the queue but not at the head 362570Swnj * of the request queue is likely to be a disaster. 372570Swnj */ 382570Swnj ubago(ui) 392570Swnj register struct uba_dinfo *ui; 402570Swnj { 412570Swnj register struct uba_minfo *um = ui->ui_mi; 422570Swnj register struct uba_hd *uh; 432570Swnj register int s, unit; 442570Swnj 452570Swnj uh = &uba_hd[um->um_ubanum]; 462570Swnj s = spl6(); 472628Swnj if (um->um_driver->ud_xclu && uh->uh_users > 0 || uh->uh_xclu) 482616Swnj goto rwait; 492570Swnj um->um_ubinfo = ubasetup(um->um_ubanum, um->um_tab.b_actf->b_actf, 502570Swnj UBA_NEEDBDP|UBA_CANTWAIT); 512616Swnj if (um->um_ubinfo == 0) 522616Swnj goto rwait; 532616Swnj uh->uh_users++; 542628Swnj if (um->um_driver->ud_xclu) 552616Swnj uh->uh_xclu = 1; 562570Swnj splx(s); 572570Swnj if (ui->ui_dk >= 0) { 582570Swnj unit = ui->ui_dk; 592570Swnj dk_busy |= 1<<unit; 602570Swnj } 612570Swnj if (uh->uh_actf == ui) 622570Swnj uh->uh_actf = ui->ui_forw; 632570Swnj (*um->um_driver->ud_dgo)(um); 642570Swnj if (ui->ui_dk >= 0) { 652570Swnj dk_xfer[unit]++; 662570Swnj dk_wds[unit] += um->um_tab.b_actf->b_bcount>>6; 672570Swnj } 682570Swnj return (1); 692616Swnj rwait: 702616Swnj if (uh->uh_actf != ui) { 712616Swnj ui->ui_forw = NULL; 722616Swnj if (uh->uh_actf == NULL) 732616Swnj uh->uh_actf = ui; 742616Swnj else 752616Swnj uh->uh_actl->ui_forw = ui; 762616Swnj uh->uh_actl = ui; 772616Swnj } 782616Swnj splx(s); 792616Swnj return (0); 802570Swnj } 812570Swnj 822616Swnj ubadone(um) 832616Swnj register struct uba_minfo *um; 842616Swnj { 852616Swnj register struct uba_hd *uh = &uba_hd[um->um_ubanum]; 862616Swnj 872628Swnj if (um->um_driver->ud_xclu) 882616Swnj uh->uh_xclu = 0; 892616Swnj uh->uh_users--; 902616Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 912616Swnj } 922616Swnj 932570Swnj /* 942395Swnj * Allocate and setup UBA map registers, and bdp's 952395Swnj * Flags says whether bdp is needed, whether the caller can't 962395Swnj * wait (e.g. if the caller is at interrupt level). 9740Sbill * 982570Swnj * Return value: 9940Sbill * Bits 0-8 Byte offset 10040Sbill * Bits 9-17 Start map reg. no. 10140Sbill * Bits 18-27 No. mapping reg's 10240Sbill * Bits 28-31 BDP no. 10340Sbill */ 1042395Swnj ubasetup(uban, bp, flags) 1052395Swnj struct buf *bp; 10640Sbill { 1072395Swnj register struct uba_hd *uh = &uba_hd[uban]; 10840Sbill register int temp, i; 10940Sbill int npf, reg, bdp; 11040Sbill unsigned v; 11140Sbill register struct pte *pte, *io; 11240Sbill struct proc *rp; 11340Sbill int a, o, ubinfo; 11440Sbill 11540Sbill v = btop(bp->b_un.b_addr); 11640Sbill o = (int)bp->b_un.b_addr & PGOFSET; 11740Sbill npf = btoc(bp->b_bcount + o) + 1; 11840Sbill a = spl6(); 1192784Swnj while ((reg = rmalloc(uh->uh_map, npf)) == 0) { 1202395Swnj if (flags & UBA_CANTWAIT) 1212395Swnj return (0); 1222395Swnj uh->uh_mrwant++; 1232395Swnj sleep((caddr_t)uh->uh_map, PSWP); 12440Sbill } 12540Sbill bdp = 0; 1262395Swnj if (flags & UBA_NEEDBDP) { 1272395Swnj while ((bdp = ffs(uh->uh_bdpfree)) == 0) { 1282395Swnj if (flags & UBA_CANTWAIT) { 1292784Swnj rmfree(uh->uh_map, npf, reg); 1302395Swnj return (0); 1312395Swnj } 1322395Swnj uh->uh_bdpwant++; 1332395Swnj sleep((caddr_t)uh->uh_map, PSWP); 13440Sbill } 1352463Swnj uh->uh_bdpfree &= ~(1 << (bdp-1)); 1362395Swnj } 13740Sbill splx(a); 1382463Swnj reg--; 13940Sbill ubinfo = (bdp << 28) | (npf << 18) | (reg << 9) | o; 1402395Swnj io = &uh->uh_uba->uba_map[reg]; 1412395Swnj temp = (bdp << 21) | UBA_MRV; 14240Sbill rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; 14340Sbill if (bdp && (o & 01)) 1442395Swnj temp |= UBA_BO; 14540Sbill if (bp->b_flags & B_UAREA) { 14640Sbill for (i = UPAGES - bp->b_bcount / NBPG; i < UPAGES; i++) { 14740Sbill if (rp->p_addr[i].pg_pfnum == 0) 14840Sbill panic("uba: zero upage"); 14940Sbill *(int *)io++ = rp->p_addr[i].pg_pfnum | temp; 15040Sbill } 15140Sbill } else if ((bp->b_flags & B_PHYS) == 0) { 152728Sbill pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)]; 15340Sbill while (--npf != 0) 154728Sbill *(int *)io++ = pte++->pg_pfnum | temp; 15540Sbill } else { 15640Sbill if (bp->b_flags & B_PAGET) 15740Sbill pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 15840Sbill else 15940Sbill pte = vtopte(rp, v); 16040Sbill while (--npf != 0) { 16140Sbill if (pte->pg_pfnum == 0) 16240Sbill panic("uba zero uentry"); 16340Sbill *(int *)io++ = pte++->pg_pfnum | temp; 16440Sbill } 16540Sbill } 16640Sbill *(int *)io++ = 0; 16740Sbill return (ubinfo); 16840Sbill } 16940Sbill 17040Sbill /* 1712570Swnj * Non buffer setup interface... set up a buffer and call ubasetup. 17240Sbill */ 1732395Swnj uballoc(uban, addr, bcnt, flags) 17440Sbill caddr_t addr; 17540Sbill unsigned short bcnt; 17640Sbill { 177883Sbill struct buf ubabuf; 17840Sbill 17940Sbill ubabuf.b_un.b_addr = addr; 18040Sbill ubabuf.b_flags = B_BUSY; 18140Sbill ubabuf.b_bcount = bcnt; 182883Sbill /* that's all the fields ubasetup() needs */ 1832395Swnj return (ubasetup(uban, &ubabuf, flags)); 18440Sbill } 18540Sbill 1862053Swnj /* 1872570Swnj * Release resources on uba uban, and then unblock resource waiters. 1882570Swnj * The map register parameter is by value since we need to block 1892570Swnj * against uba resets on 11/780's. 1902053Swnj */ 1912395Swnj ubarelse(uban, amr) 1922053Swnj int *amr; 19340Sbill { 1942395Swnj register struct uba_hd *uh = &uba_hd[uban]; 1952570Swnj register int bdp, reg, npf, s; 1962053Swnj int mr; 19740Sbill 1982570Swnj /* 1992570Swnj * Carefully see if we should release the space, since 2002570Swnj * it may be released asynchronously at uba reset time. 2012570Swnj */ 2022570Swnj s = spl6(); 2032053Swnj mr = *amr; 2042053Swnj if (mr == 0) { 2052570Swnj /* 2062570Swnj * A ubareset() occurred before we got around 2072570Swnj * to releasing the space... no need to bother. 2082570Swnj */ 2092570Swnj splx(s); 2102053Swnj return; 2112053Swnj } 2122067Swnj *amr = 0; 2132570Swnj splx(s); /* let interrupts in, we're safe for a while */ 21440Sbill bdp = (mr >> 28) & 0x0f; 21540Sbill if (bdp) { 2162729Swnj switch (cpu) { 2172423Skre #if VAX780 2182423Skre case VAX_780: 2192423Skre uh->uh_uba->uba_dpr[bdp] |= UBA_BNE; 2202423Skre break; 2212423Skre #endif 2222423Skre #if VAX750 2232423Skre case VAX_750: 2242423Skre uh->uh_uba->uba_dpr[bdp] |= UBA_PURGE|UBA_NXM|UBA_UCE; 2252423Skre break; 2262423Skre #endif 2272423Skre } 2282570Swnj uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */ 2292395Swnj if (uh->uh_bdpwant) { 2302395Swnj uh->uh_bdpwant = 0; 2312395Swnj wakeup((caddr_t)uh->uh_map); 23240Sbill } 23340Sbill } 2342570Swnj /* 2352570Swnj * Put back the registers in the resource map. 2362570Swnj * The map code must not be reentered, so we do this 2372570Swnj * at high ipl. 2382570Swnj */ 23940Sbill npf = (mr >> 18) & 0x3ff; 24040Sbill reg = ((mr >> 9) & 0x1ff) + 1; 2412570Swnj s = spl6(); 2422784Swnj rmfree(uh->uh_map, npf, reg); 2432570Swnj splx(s); 2442570Swnj 2452570Swnj /* 2462570Swnj * Wakeup sleepers for map registers, 2472570Swnj * and also, if there are processes blocked in dgo(), 2482570Swnj * give them a chance at the UNIBUS. 2492570Swnj */ 2502395Swnj if (uh->uh_mrwant) { 2512395Swnj uh->uh_mrwant = 0; 2522395Swnj wakeup((caddr_t)uh->uh_map); 25340Sbill } 2542570Swnj while (uh->uh_actf && ubago(uh->uh_actf)) 2552570Swnj ; 25640Sbill } 25740Sbill 2582729Swnj ubapurge(um) 2592729Swnj register struct uba_minfo *um; 2602729Swnj { 2612729Swnj register struct uba_hd *uh = um->um_hd; 2622729Swnj register int bdp = (um->um_ubinfo >> 28) & 0x0f; 2632729Swnj 2642729Swnj switch (cpu) { 2652729Swnj #if VAX780 2662729Swnj case VAX_780: 2672729Swnj uh->uh_uba->uba_dpr[bdp] |= UBA_BNE; 2682729Swnj break; 2692729Swnj #endif 2702729Swnj #if VAX750 2712729Swnj case VAX_750: 2722729Swnj uh->uh_uba->uba_dpr[bdp] |= UBA_PURGE|UBA_NXM|UBA_UCE; 2732729Swnj break; 2742729Swnj #endif 2752729Swnj } 2762729Swnj } 2772729Swnj 2782570Swnj /* 2792570Swnj * Generate a reset on uba number uban. Then 2802570Swnj * call each device in the character device table, 2812570Swnj * giving it a chance to clean up so as to be able to continue. 2822570Swnj */ 2832395Swnj ubareset(uban) 2842570Swnj int uban; 285284Sbill { 286284Sbill register struct cdevsw *cdp; 2872646Swnj register struct uba_hd *uh = &uba_hd[uban]; 2881781Sbill int s; 289284Sbill 290302Sbill s = spl6(); 2912646Swnj uh->uh_users = 0; 2922646Swnj uh->uh_zvcnt = 0; 2932646Swnj uh->uh_xclu = 0; 2942646Swnj uh->uh_hangcnt = 0; 2952646Swnj uh->uh_actf = uh->uh_actl = 0; 2962646Swnj uh->uh_bdpwant = 0; 2972646Swnj uh->uh_mrwant = 0; 2982646Swnj wakeup((caddr_t)&uh->uh_bdpwant); 2992646Swnj wakeup((caddr_t)&uh->uh_mrwant); 3002395Swnj switch (cpu) { 3012692Swnj #if VAX780 3022395Swnj case VAX_780: 303*2929Swnj printf("uba%d: reset", uban); 3042646Swnj ubainit(uh->uh_uba); 3052395Swnj break; 3061901Swnj #endif 3072692Swnj #if VAX750 3082395Swnj case VAX_750: 309*2929Swnj printf("uba0: reset"); 3102395Swnj mtpr(IUR, 1); 311*2929Swnj /* give devices time to recover from power fail */ 312*2929Swnj DELAY(5000000); 3132395Swnj break; 3141901Swnj #endif 3152395Swnj } 316284Sbill for (cdp = cdevsw; cdp->d_open; cdp++) 3172395Swnj (*cdp->d_reset)(uban); 318284Sbill printf("\n"); 319302Sbill splx(s); 320284Sbill } 3212395Swnj 3222729Swnj #if VAX780 3232570Swnj /* 3242570Swnj * Init a uba. This is called with a pointer 3252570Swnj * rather than a virtual address since it is called 3262570Swnj * by code which runs with memory mapping disabled. 3272570Swnj * In these cases we really don't need the interrupts 3282570Swnj * enabled, but since we run with ipl high, we don't care 3292570Swnj * if they are, they will never happen anyways. 3302570Swnj */ 3312423Skre ubainit(uba) 3322423Skre register struct uba_regs *uba; 3332395Swnj { 3342395Swnj 3352423Skre uba->uba_cr = UBA_ADINIT; 3362423Skre uba->uba_cr = UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE; 3372423Skre while ((uba->uba_cnfgr & UBA_UBIC) == 0) 3382395Swnj ; 3392395Swnj } 3402395Swnj 3412570Swnj /* 3422570Swnj * Check to make sure the UNIBUS adaptor is not hung, 3432570Swnj * with an interrupt in the register to be presented, 3442570Swnj * but not presenting it for an extended period (5 seconds). 3452570Swnj */ 3462395Swnj unhang() 3472395Swnj { 3482395Swnj register int uban; 3492395Swnj 3502395Swnj for (uban = 0; uban < numuba; uban++) { 3512395Swnj register struct uba_hd *uh = &uba_hd[uban]; 3522395Swnj register struct uba_regs *up = uh->uh_uba; 3532395Swnj 3542395Swnj if (up->uba_sr == 0) 3552395Swnj return; 3562395Swnj uh->uh_hangcnt++; 3572759Swnj if (uh->uh_hangcnt > 5*hz) { 3582395Swnj uh->uh_hangcnt = 0; 359*2929Swnj printf("uba%d: hung\n", uban); 3602395Swnj ubareset(uban); 3612395Swnj } 3622395Swnj } 3632395Swnj } 3642395Swnj 3652570Swnj /* 3662570Swnj * This is a timeout routine which decrements the ``i forgot to 3672570Swnj * interrupt'' counts, on an 11/780. This prevents slowly growing 3682570Swnj * counts from causing a UBA reset since we are interested only 3692570Swnj * in hang situations. 3702570Swnj */ 3712395Swnj ubawatch() 3722395Swnj { 3732395Swnj register struct uba_hd *uh; 3742395Swnj register int uban; 3752395Swnj 3762784Swnj if (panicstr) 3772784Swnj return; 3782395Swnj for (uban = 0; uban < numuba; uban++) { 3792395Swnj uh = &uba_hd[uban]; 3802395Swnj if (uh->uh_hangcnt) 3812395Swnj uh->uh_hangcnt--; 3822395Swnj } 3832395Swnj } 3842395Swnj 3852570Swnj /* 3862570Swnj * This routine is called by the locore code to 3872570Swnj * process a UBA error on an 11/780. The arguments are passed 3882570Swnj * on the stack, and value-result (through some trickery). 3892570Swnj * In particular, the uvec argument is used for further 3902570Swnj * uba processing so the result aspect of it is very important. 3912570Swnj * It must not be declared register. 3922570Swnj */ 3932423Skre /*ARGSUSED*/ 3942395Swnj ubaerror(uban, uh, xx, uvec, uba) 3952395Swnj register int uban; 3962395Swnj register struct uba_hd *uh; 3972395Swnj int uvec; 3982395Swnj register struct uba_regs *uba; 3992395Swnj { 4002395Swnj register sr, s; 4012395Swnj 4022395Swnj if (uvec == 0) { 4032395Swnj uh->uh_zvcnt++; 4042395Swnj if (uh->uh_zvcnt > 250000) { 405*2929Swnj printf("uba%d: too many zero vectors\n"); 4062395Swnj ubareset(uban); 4072395Swnj } 4082395Swnj uvec = 0; 4092395Swnj return; 4102395Swnj } 4112395Swnj if (uba->uba_cnfgr & NEX_CFGFLT) { 412*2929Swnj printf("uba%d: sbi fault sr=%b cnfgr=%b\n", 413*2929Swnj uban, uba->uba_sr, ubasr_bits, 414*2929Swnj uba->uba_cnfgr, nexflt_bits); 4152395Swnj ubareset(uban); 4162395Swnj uvec = 0; 4172395Swnj return; 4182395Swnj } 4192395Swnj sr = uba->uba_sr; 4202395Swnj s = spl7(); 421*2929Swnj printf("uba%d: uba error sr=%x fmer=%x fubar=%o\n", 4222470Swnj uban, uba->uba_sr, uba->uba_fmer, 4*uba->uba_fubar); 4232395Swnj splx(s); 4242395Swnj uba->uba_sr = sr; 4252395Swnj uvec &= UBA_DIV; 4262395Swnj return; 4272395Swnj } 4282395Swnj #endif 429