1*2729Swnj /* uba.c 4.16 02/26/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 2140Sbill /* 222570Swnj * Do transfer on device argument. The controller 232570Swnj * and uba involved are implied by the device. 242570Swnj * We queue for resource wait in the uba code if necessary. 252570Swnj * We return 1 if the transfer was started, 0 if it was not. 262570Swnj * If you call this routine with the head of the queue for a 272570Swnj * UBA, it will automatically remove the device from the UBA 282570Swnj * queue before it returns. If some other device is given 292570Swnj * as argument, it will be added to the request queue if the 302570Swnj * request cannot be started immediately. This means that 312570Swnj * passing a device which is on the queue but not at the head 322570Swnj * of the request queue is likely to be a disaster. 332570Swnj */ 342570Swnj ubago(ui) 352570Swnj register struct uba_dinfo *ui; 362570Swnj { 372570Swnj register struct uba_minfo *um = ui->ui_mi; 382570Swnj register struct uba_hd *uh; 392570Swnj register int s, unit; 402570Swnj 412570Swnj uh = &uba_hd[um->um_ubanum]; 422570Swnj s = spl6(); 432628Swnj if (um->um_driver->ud_xclu && uh->uh_users > 0 || uh->uh_xclu) 442616Swnj goto rwait; 452570Swnj um->um_ubinfo = ubasetup(um->um_ubanum, um->um_tab.b_actf->b_actf, 462570Swnj UBA_NEEDBDP|UBA_CANTWAIT); 472616Swnj if (um->um_ubinfo == 0) 482616Swnj goto rwait; 492616Swnj uh->uh_users++; 502628Swnj if (um->um_driver->ud_xclu) 512616Swnj uh->uh_xclu = 1; 522570Swnj splx(s); 532570Swnj if (ui->ui_dk >= 0) { 542570Swnj unit = ui->ui_dk; 552570Swnj dk_busy |= 1<<unit; 562570Swnj } 572570Swnj if (uh->uh_actf == ui) 582570Swnj uh->uh_actf = ui->ui_forw; 592570Swnj (*um->um_driver->ud_dgo)(um); 602570Swnj if (ui->ui_dk >= 0) { 612570Swnj dk_xfer[unit]++; 622570Swnj dk_wds[unit] += um->um_tab.b_actf->b_bcount>>6; 632570Swnj } 642570Swnj return (1); 652616Swnj rwait: 662616Swnj if (uh->uh_actf != ui) { 672616Swnj ui->ui_forw = NULL; 682616Swnj if (uh->uh_actf == NULL) 692616Swnj uh->uh_actf = ui; 702616Swnj else 712616Swnj uh->uh_actl->ui_forw = ui; 722616Swnj uh->uh_actl = ui; 732616Swnj } 742616Swnj splx(s); 752616Swnj return (0); 762570Swnj } 772570Swnj 782616Swnj ubadone(um) 792616Swnj register struct uba_minfo *um; 802616Swnj { 812616Swnj register struct uba_hd *uh = &uba_hd[um->um_ubanum]; 822616Swnj 832628Swnj if (um->um_driver->ud_xclu) 842616Swnj uh->uh_xclu = 0; 852616Swnj uh->uh_users--; 862616Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 872616Swnj } 882616Swnj 892570Swnj /* 902395Swnj * Allocate and setup UBA map registers, and bdp's 912395Swnj * Flags says whether bdp is needed, whether the caller can't 922395Swnj * wait (e.g. if the caller is at interrupt level). 9340Sbill * 942570Swnj * Return value: 9540Sbill * Bits 0-8 Byte offset 9640Sbill * Bits 9-17 Start map reg. no. 9740Sbill * Bits 18-27 No. mapping reg's 9840Sbill * Bits 28-31 BDP no. 9940Sbill */ 1002395Swnj ubasetup(uban, bp, flags) 1012395Swnj struct buf *bp; 10240Sbill { 1032395Swnj register struct uba_hd *uh = &uba_hd[uban]; 10440Sbill register int temp, i; 10540Sbill int npf, reg, bdp; 10640Sbill unsigned v; 10740Sbill register struct pte *pte, *io; 10840Sbill struct proc *rp; 10940Sbill int a, o, ubinfo; 11040Sbill 11140Sbill v = btop(bp->b_un.b_addr); 11240Sbill o = (int)bp->b_un.b_addr & PGOFSET; 11340Sbill npf = btoc(bp->b_bcount + o) + 1; 11440Sbill a = spl6(); 1152395Swnj while ((reg = malloc(uh->uh_map, npf)) == 0) { 1162395Swnj if (flags & UBA_CANTWAIT) 1172395Swnj return (0); 1182395Swnj uh->uh_mrwant++; 1192395Swnj sleep((caddr_t)uh->uh_map, PSWP); 12040Sbill } 12140Sbill bdp = 0; 1222395Swnj if (flags & UBA_NEEDBDP) { 1232395Swnj while ((bdp = ffs(uh->uh_bdpfree)) == 0) { 1242395Swnj if (flags & UBA_CANTWAIT) { 1252395Swnj mfree(uh->uh_map, npf, reg); 1262395Swnj return (0); 1272395Swnj } 1282395Swnj uh->uh_bdpwant++; 1292395Swnj sleep((caddr_t)uh->uh_map, PSWP); 13040Sbill } 1312463Swnj uh->uh_bdpfree &= ~(1 << (bdp-1)); 1322395Swnj } 13340Sbill splx(a); 1342463Swnj reg--; 13540Sbill ubinfo = (bdp << 28) | (npf << 18) | (reg << 9) | o; 1362395Swnj io = &uh->uh_uba->uba_map[reg]; 1372395Swnj temp = (bdp << 21) | UBA_MRV; 13840Sbill rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; 13940Sbill if (bdp && (o & 01)) 1402395Swnj temp |= UBA_BO; 14140Sbill if (bp->b_flags & B_UAREA) { 14240Sbill for (i = UPAGES - bp->b_bcount / NBPG; i < UPAGES; i++) { 14340Sbill if (rp->p_addr[i].pg_pfnum == 0) 14440Sbill panic("uba: zero upage"); 14540Sbill *(int *)io++ = rp->p_addr[i].pg_pfnum | temp; 14640Sbill } 14740Sbill } else if ((bp->b_flags & B_PHYS) == 0) { 148728Sbill pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)]; 14940Sbill while (--npf != 0) 150728Sbill *(int *)io++ = pte++->pg_pfnum | temp; 15140Sbill } else { 15240Sbill if (bp->b_flags & B_PAGET) 15340Sbill pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 15440Sbill else 15540Sbill pte = vtopte(rp, v); 15640Sbill while (--npf != 0) { 15740Sbill if (pte->pg_pfnum == 0) 15840Sbill panic("uba zero uentry"); 15940Sbill *(int *)io++ = pte++->pg_pfnum | temp; 16040Sbill } 16140Sbill } 16240Sbill *(int *)io++ = 0; 16340Sbill return (ubinfo); 16440Sbill } 16540Sbill 16640Sbill /* 1672570Swnj * Non buffer setup interface... set up a buffer and call ubasetup. 16840Sbill */ 1692395Swnj uballoc(uban, addr, bcnt, flags) 17040Sbill caddr_t addr; 17140Sbill unsigned short bcnt; 17240Sbill { 173883Sbill struct buf ubabuf; 17440Sbill 17540Sbill ubabuf.b_un.b_addr = addr; 17640Sbill ubabuf.b_flags = B_BUSY; 17740Sbill ubabuf.b_bcount = bcnt; 178883Sbill /* that's all the fields ubasetup() needs */ 1792395Swnj return (ubasetup(uban, &ubabuf, flags)); 18040Sbill } 18140Sbill 1822053Swnj /* 1832570Swnj * Release resources on uba uban, and then unblock resource waiters. 1842570Swnj * The map register parameter is by value since we need to block 1852570Swnj * against uba resets on 11/780's. 1862053Swnj */ 1872395Swnj ubarelse(uban, amr) 1882053Swnj int *amr; 18940Sbill { 1902395Swnj register struct uba_hd *uh = &uba_hd[uban]; 1912570Swnj register int bdp, reg, npf, s; 1922053Swnj int mr; 19340Sbill 1942570Swnj /* 1952570Swnj * Carefully see if we should release the space, since 1962570Swnj * it may be released asynchronously at uba reset time. 1972570Swnj */ 1982570Swnj s = spl6(); 1992053Swnj mr = *amr; 2002053Swnj if (mr == 0) { 2012570Swnj /* 2022570Swnj * A ubareset() occurred before we got around 2032570Swnj * to releasing the space... no need to bother. 2042570Swnj */ 2052570Swnj splx(s); 2062053Swnj return; 2072053Swnj } 2082067Swnj *amr = 0; 2092570Swnj splx(s); /* let interrupts in, we're safe for a while */ 21040Sbill bdp = (mr >> 28) & 0x0f; 21140Sbill if (bdp) { 212*2729Swnj switch (cpu) { 2132423Skre #if VAX780 2142423Skre case VAX_780: 2152423Skre uh->uh_uba->uba_dpr[bdp] |= UBA_BNE; 2162423Skre break; 2172423Skre #endif 2182423Skre #if VAX750 2192423Skre case VAX_750: 2202423Skre uh->uh_uba->uba_dpr[bdp] |= UBA_PURGE|UBA_NXM|UBA_UCE; 2212423Skre break; 2222423Skre #endif 2232423Skre } 2242570Swnj uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */ 2252395Swnj if (uh->uh_bdpwant) { 2262395Swnj uh->uh_bdpwant = 0; 2272395Swnj wakeup((caddr_t)uh->uh_map); 22840Sbill } 22940Sbill } 2302570Swnj /* 2312570Swnj * Put back the registers in the resource map. 2322570Swnj * The map code must not be reentered, so we do this 2332570Swnj * at high ipl. 2342570Swnj */ 23540Sbill npf = (mr >> 18) & 0x3ff; 23640Sbill reg = ((mr >> 9) & 0x1ff) + 1; 2372570Swnj s = spl6(); 2382395Swnj mfree(uh->uh_map, npf, reg); 2392570Swnj splx(s); 2402570Swnj 2412570Swnj /* 2422570Swnj * Wakeup sleepers for map registers, 2432570Swnj * and also, if there are processes blocked in dgo(), 2442570Swnj * give them a chance at the UNIBUS. 2452570Swnj */ 2462395Swnj if (uh->uh_mrwant) { 2472395Swnj uh->uh_mrwant = 0; 2482395Swnj wakeup((caddr_t)uh->uh_map); 24940Sbill } 2502570Swnj while (uh->uh_actf && ubago(uh->uh_actf)) 2512570Swnj ; 25240Sbill } 25340Sbill 254*2729Swnj ubapurge(um) 255*2729Swnj register struct uba_minfo *um; 256*2729Swnj { 257*2729Swnj register struct uba_hd *uh = um->um_hd; 258*2729Swnj register int bdp = (um->um_ubinfo >> 28) & 0x0f; 259*2729Swnj 260*2729Swnj switch (cpu) { 261*2729Swnj #if VAX780 262*2729Swnj case VAX_780: 263*2729Swnj uh->uh_uba->uba_dpr[bdp] |= UBA_BNE; 264*2729Swnj break; 265*2729Swnj #endif 266*2729Swnj #if VAX750 267*2729Swnj case VAX_750: 268*2729Swnj uh->uh_uba->uba_dpr[bdp] |= UBA_PURGE|UBA_NXM|UBA_UCE; 269*2729Swnj break; 270*2729Swnj #endif 271*2729Swnj } 272*2729Swnj } 273*2729Swnj 2742570Swnj /* 2752570Swnj * Generate a reset on uba number uban. Then 2762570Swnj * call each device in the character device table, 2772570Swnj * giving it a chance to clean up so as to be able to continue. 2782570Swnj */ 2792395Swnj ubareset(uban) 2802570Swnj int uban; 281284Sbill { 282284Sbill register struct cdevsw *cdp; 2832646Swnj register struct uba_hd *uh = &uba_hd[uban]; 2841781Sbill int s; 285284Sbill 286302Sbill s = spl6(); 2872646Swnj uh->uh_users = 0; 2882646Swnj uh->uh_zvcnt = 0; 2892646Swnj uh->uh_xclu = 0; 2902646Swnj uh->uh_hangcnt = 0; 2912646Swnj uh->uh_actf = uh->uh_actl = 0; 2922646Swnj uh->uh_bdpwant = 0; 2932646Swnj uh->uh_mrwant = 0; 2942646Swnj wakeup((caddr_t)&uh->uh_bdpwant); 2952646Swnj wakeup((caddr_t)&uh->uh_mrwant); 2962395Swnj switch (cpu) { 2972692Swnj #if VAX780 2982395Swnj case VAX_780: 2992395Swnj printf("UBA RESET %d:", uban); 3002646Swnj ubainit(uh->uh_uba); 3012395Swnj break; 3021901Swnj #endif 3032692Swnj #if VAX750 3042395Swnj case VAX_750: 3052395Swnj printf("UNIBUS INIT:"); 3062395Swnj mtpr(IUR, 1); 3072395Swnj DELAY(100000); 3082395Swnj break; 3091901Swnj #endif 3102395Swnj } 311284Sbill for (cdp = cdevsw; cdp->d_open; cdp++) 3122395Swnj (*cdp->d_reset)(uban); 313284Sbill printf("\n"); 314302Sbill splx(s); 315284Sbill } 3162395Swnj 317*2729Swnj #if VAX780 3182570Swnj /* 3192570Swnj * Init a uba. This is called with a pointer 3202570Swnj * rather than a virtual address since it is called 3212570Swnj * by code which runs with memory mapping disabled. 3222570Swnj * In these cases we really don't need the interrupts 3232570Swnj * enabled, but since we run with ipl high, we don't care 3242570Swnj * if they are, they will never happen anyways. 3252570Swnj */ 3262423Skre ubainit(uba) 3272423Skre register struct uba_regs *uba; 3282395Swnj { 3292395Swnj 3302423Skre uba->uba_cr = UBA_ADINIT; 3312423Skre uba->uba_cr = UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE; 3322423Skre while ((uba->uba_cnfgr & UBA_UBIC) == 0) 3332395Swnj ; 3342395Swnj } 3352395Swnj 3362570Swnj /* 3372570Swnj * Check to make sure the UNIBUS adaptor is not hung, 3382570Swnj * with an interrupt in the register to be presented, 3392570Swnj * but not presenting it for an extended period (5 seconds). 3402570Swnj */ 3412395Swnj unhang() 3422395Swnj { 3432395Swnj register int uban; 3442395Swnj 3452395Swnj for (uban = 0; uban < numuba; uban++) { 3462395Swnj register struct uba_hd *uh = &uba_hd[uban]; 3472395Swnj register struct uba_regs *up = uh->uh_uba; 3482395Swnj 3492395Swnj if (up->uba_sr == 0) 3502395Swnj return; 3512395Swnj uh->uh_hangcnt++; 3522395Swnj if (uh->uh_hangcnt > 5*HZ) { 3532395Swnj uh->uh_hangcnt = 0; 3542395Swnj printf("HANG "); 3552395Swnj ubareset(uban); 3562395Swnj } 3572395Swnj } 3582395Swnj } 3592395Swnj 3602570Swnj /* 3612570Swnj * This is a timeout routine which decrements the ``i forgot to 3622570Swnj * interrupt'' counts, on an 11/780. This prevents slowly growing 3632570Swnj * counts from causing a UBA reset since we are interested only 3642570Swnj * in hang situations. 3652570Swnj */ 3662395Swnj ubawatch() 3672395Swnj { 3682395Swnj register struct uba_hd *uh; 3692395Swnj register int uban; 3702395Swnj 3712395Swnj for (uban = 0; uban < numuba; uban++) { 3722395Swnj uh = &uba_hd[uban]; 3732395Swnj if (uh->uh_hangcnt) 3742395Swnj uh->uh_hangcnt--; 3752395Swnj } 3762395Swnj } 3772395Swnj 3782570Swnj /* 3792570Swnj * This routine is called by the locore code to 3802570Swnj * process a UBA error on an 11/780. The arguments are passed 3812570Swnj * on the stack, and value-result (through some trickery). 3822570Swnj * In particular, the uvec argument is used for further 3832570Swnj * uba processing so the result aspect of it is very important. 3842570Swnj * It must not be declared register. 3852570Swnj */ 3862423Skre /*ARGSUSED*/ 3872395Swnj ubaerror(uban, uh, xx, uvec, uba) 3882395Swnj register int uban; 3892395Swnj register struct uba_hd *uh; 3902395Swnj int uvec; 3912395Swnj register struct uba_regs *uba; 3922395Swnj { 3932395Swnj register sr, s; 3942395Swnj 3952395Swnj if (uvec == 0) { 3962395Swnj uh->uh_zvcnt++; 3972395Swnj if (uh->uh_zvcnt > 250000) { 3982395Swnj printf("ZERO VECTOR "); 3992395Swnj ubareset(uban); 4002395Swnj } 4012395Swnj uvec = 0; 4022395Swnj return; 4032395Swnj } 4042395Swnj if (uba->uba_cnfgr & NEX_CFGFLT) { 4052395Swnj printf("UBA%d SBI FAULT sr %x cnfgr %x\n", 4062395Swnj uban, uba->uba_sr, uba->uba_cnfgr); 4072395Swnj ubareset(uban); 4082395Swnj uvec = 0; 4092395Swnj return; 4102395Swnj } 4112395Swnj sr = uba->uba_sr; 4122395Swnj s = spl7(); 4132395Swnj printf("UBA%d ERROR SR %x FMER %x FUBAR %o\n", 4142470Swnj uban, uba->uba_sr, uba->uba_fmer, 4*uba->uba_fubar); 4152395Swnj splx(s); 4162395Swnj uba->uba_sr = sr; 4172395Swnj uvec &= UBA_DIV; 4182395Swnj return; 4192395Swnj } 4202395Swnj #endif 421