1*3332Swnj /* uba.c 4.25 81/03/21 */ 240Sbill 340Sbill #include "../h/param.h" 42395Swnj #include "../h/systm.h" 52395Swnj #include "../h/cpu.h" 640Sbill #include "../h/map.h" 740Sbill #include "../h/pte.h" 82395Swnj #include "../h/buf.h" 92570Swnj #include "../h/vm.h" 102958Swnj #include "../h/ubareg.h" 112958Swnj #include "../h/ubavar.h" 1240Sbill #include "../h/dir.h" 1340Sbill #include "../h/user.h" 1440Sbill #include "../h/proc.h" 15284Sbill #include "../h/conf.h" 161901Swnj #include "../h/mtpr.h" 172395Swnj #include "../h/nexus.h" 182570Swnj #include "../h/dk.h" 1940Sbill 202929Swnj #if VAX780 212929Swnj char ubasr_bits[] = UBASR_BITS; 222929Swnj #endif 232929Swnj 2440Sbill /* 252570Swnj * Do transfer on device argument. The controller 262570Swnj * and uba involved are implied by the device. 272570Swnj * We queue for resource wait in the uba code if necessary. 282570Swnj * We return 1 if the transfer was started, 0 if it was not. 292570Swnj * If you call this routine with the head of the queue for a 302570Swnj * UBA, it will automatically remove the device from the UBA 312570Swnj * queue before it returns. If some other device is given 322570Swnj * as argument, it will be added to the request queue if the 332570Swnj * request cannot be started immediately. This means that 342570Swnj * passing a device which is on the queue but not at the head 352570Swnj * of the request queue is likely to be a disaster. 362570Swnj */ 372570Swnj ubago(ui) 382958Swnj register struct uba_device *ui; 392570Swnj { 402958Swnj register struct uba_ctlr *um = ui->ui_mi; 412570Swnj register struct uba_hd *uh; 422570Swnj register int s, unit; 432570Swnj 442570Swnj uh = &uba_hd[um->um_ubanum]; 452570Swnj s = spl6(); 462628Swnj if (um->um_driver->ud_xclu && uh->uh_users > 0 || uh->uh_xclu) 472616Swnj goto rwait; 482570Swnj um->um_ubinfo = ubasetup(um->um_ubanum, um->um_tab.b_actf->b_actf, 492570Swnj UBA_NEEDBDP|UBA_CANTWAIT); 502616Swnj if (um->um_ubinfo == 0) 512616Swnj goto rwait; 522616Swnj uh->uh_users++; 532628Swnj if (um->um_driver->ud_xclu) 542616Swnj uh->uh_xclu = 1; 552570Swnj splx(s); 562570Swnj if (ui->ui_dk >= 0) { 572570Swnj unit = ui->ui_dk; 582570Swnj dk_busy |= 1<<unit; 592570Swnj } 602570Swnj if (uh->uh_actf == ui) 612570Swnj uh->uh_actf = ui->ui_forw; 622570Swnj (*um->um_driver->ud_dgo)(um); 632570Swnj if (ui->ui_dk >= 0) { 642570Swnj dk_xfer[unit]++; 652570Swnj dk_wds[unit] += um->um_tab.b_actf->b_bcount>>6; 662570Swnj } 672570Swnj return (1); 682616Swnj rwait: 692616Swnj if (uh->uh_actf != ui) { 702616Swnj ui->ui_forw = NULL; 712616Swnj if (uh->uh_actf == NULL) 722616Swnj uh->uh_actf = ui; 732616Swnj else 742616Swnj uh->uh_actl->ui_forw = ui; 752616Swnj uh->uh_actl = ui; 762616Swnj } 772616Swnj splx(s); 782616Swnj return (0); 792570Swnj } 802570Swnj 812616Swnj ubadone(um) 822958Swnj register struct uba_ctlr *um; 832616Swnj { 842616Swnj register struct uba_hd *uh = &uba_hd[um->um_ubanum]; 852616Swnj 862628Swnj if (um->um_driver->ud_xclu) 872616Swnj uh->uh_xclu = 0; 882616Swnj uh->uh_users--; 892616Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 902616Swnj } 912616Swnj 922570Swnj /* 932395Swnj * Allocate and setup UBA map registers, and bdp's 942395Swnj * Flags says whether bdp is needed, whether the caller can't 952395Swnj * wait (e.g. if the caller is at interrupt level). 9640Sbill * 972570Swnj * Return value: 9840Sbill * Bits 0-8 Byte offset 9940Sbill * Bits 9-17 Start map reg. no. 10040Sbill * Bits 18-27 No. mapping reg's 10140Sbill * Bits 28-31 BDP no. 10240Sbill */ 1032395Swnj ubasetup(uban, bp, flags) 1042395Swnj struct buf *bp; 10540Sbill { 1062395Swnj register struct uba_hd *uh = &uba_hd[uban]; 10740Sbill register int temp, i; 10840Sbill int npf, reg, bdp; 10940Sbill unsigned v; 11040Sbill register struct pte *pte, *io; 11140Sbill struct proc *rp; 11240Sbill int a, o, ubinfo; 11340Sbill 114*3332Swnj #if VAX730 115*3332Swnj if (cpu == VAX_730) 116*3332Swnj flags &= ~UBA_NEEDBDP; 117*3332Swnj #endif 11840Sbill v = btop(bp->b_un.b_addr); 11940Sbill o = (int)bp->b_un.b_addr & PGOFSET; 12040Sbill npf = btoc(bp->b_bcount + o) + 1; 12140Sbill a = spl6(); 1222784Swnj while ((reg = rmalloc(uh->uh_map, npf)) == 0) { 1232395Swnj if (flags & UBA_CANTWAIT) 1242395Swnj return (0); 1252395Swnj uh->uh_mrwant++; 1262395Swnj sleep((caddr_t)uh->uh_map, PSWP); 12740Sbill } 12840Sbill bdp = 0; 1292395Swnj if (flags & UBA_NEEDBDP) { 1302395Swnj while ((bdp = ffs(uh->uh_bdpfree)) == 0) { 1312395Swnj if (flags & UBA_CANTWAIT) { 1322784Swnj rmfree(uh->uh_map, npf, reg); 1332395Swnj return (0); 1342395Swnj } 1352395Swnj uh->uh_bdpwant++; 1362395Swnj sleep((caddr_t)uh->uh_map, PSWP); 13740Sbill } 1382463Swnj uh->uh_bdpfree &= ~(1 << (bdp-1)); 1392395Swnj } 14040Sbill splx(a); 1412463Swnj reg--; 14240Sbill ubinfo = (bdp << 28) | (npf << 18) | (reg << 9) | o; 1432395Swnj io = &uh->uh_uba->uba_map[reg]; 1442958Swnj temp = (bdp << 21) | UBAMR_MRV; 14540Sbill rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; 14640Sbill if (bdp && (o & 01)) 1472958Swnj temp |= UBAMR_BO; 14840Sbill if (bp->b_flags & B_UAREA) { 14940Sbill for (i = UPAGES - bp->b_bcount / NBPG; i < UPAGES; i++) { 15040Sbill if (rp->p_addr[i].pg_pfnum == 0) 15140Sbill panic("uba: zero upage"); 15240Sbill *(int *)io++ = rp->p_addr[i].pg_pfnum | temp; 15340Sbill } 15440Sbill } else if ((bp->b_flags & B_PHYS) == 0) { 155728Sbill pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)]; 15640Sbill while (--npf != 0) 157728Sbill *(int *)io++ = pte++->pg_pfnum | temp; 15840Sbill } else { 15940Sbill if (bp->b_flags & B_PAGET) 16040Sbill pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 16140Sbill else 16240Sbill pte = vtopte(rp, v); 16340Sbill while (--npf != 0) { 16440Sbill if (pte->pg_pfnum == 0) 16540Sbill panic("uba zero uentry"); 16640Sbill *(int *)io++ = pte++->pg_pfnum | temp; 16740Sbill } 16840Sbill } 16940Sbill *(int *)io++ = 0; 17040Sbill return (ubinfo); 17140Sbill } 17240Sbill 17340Sbill /* 1742570Swnj * Non buffer setup interface... set up a buffer and call ubasetup. 17540Sbill */ 1762395Swnj uballoc(uban, addr, bcnt, flags) 1773107Swnj int uban; 17840Sbill caddr_t addr; 1793107Swnj int bcnt, flags; 18040Sbill { 181883Sbill struct buf ubabuf; 18240Sbill 18340Sbill ubabuf.b_un.b_addr = addr; 18440Sbill ubabuf.b_flags = B_BUSY; 18540Sbill ubabuf.b_bcount = bcnt; 186883Sbill /* that's all the fields ubasetup() needs */ 1872395Swnj return (ubasetup(uban, &ubabuf, flags)); 18840Sbill } 18940Sbill 1902053Swnj /* 1912570Swnj * Release resources on uba uban, and then unblock resource waiters. 1922570Swnj * The map register parameter is by value since we need to block 1932570Swnj * against uba resets on 11/780's. 1942053Swnj */ 1952395Swnj ubarelse(uban, amr) 1962053Swnj int *amr; 19740Sbill { 1982395Swnj register struct uba_hd *uh = &uba_hd[uban]; 1992570Swnj register int bdp, reg, npf, s; 2002053Swnj int mr; 20140Sbill 2022570Swnj /* 2032570Swnj * Carefully see if we should release the space, since 2042570Swnj * it may be released asynchronously at uba reset time. 2052570Swnj */ 2062570Swnj s = spl6(); 2072053Swnj mr = *amr; 2082053Swnj if (mr == 0) { 2092570Swnj /* 2102570Swnj * A ubareset() occurred before we got around 2112570Swnj * to releasing the space... no need to bother. 2122570Swnj */ 2132570Swnj splx(s); 2142053Swnj return; 2152053Swnj } 2162067Swnj *amr = 0; 2172570Swnj splx(s); /* let interrupts in, we're safe for a while */ 21840Sbill bdp = (mr >> 28) & 0x0f; 21940Sbill if (bdp) { 2202729Swnj switch (cpu) { 2212423Skre #if VAX780 2222423Skre case VAX_780: 2232958Swnj uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; 2242423Skre break; 2252423Skre #endif 2262423Skre #if VAX750 2272423Skre case VAX_750: 2282958Swnj uh->uh_uba->uba_dpr[bdp] |= 2292958Swnj UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; 2302423Skre break; 2312423Skre #endif 2322423Skre } 2332570Swnj uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */ 2342395Swnj if (uh->uh_bdpwant) { 2352395Swnj uh->uh_bdpwant = 0; 2362395Swnj wakeup((caddr_t)uh->uh_map); 23740Sbill } 23840Sbill } 2392570Swnj /* 2402570Swnj * Put back the registers in the resource map. 2412570Swnj * The map code must not be reentered, so we do this 2422570Swnj * at high ipl. 2432570Swnj */ 24440Sbill npf = (mr >> 18) & 0x3ff; 24540Sbill reg = ((mr >> 9) & 0x1ff) + 1; 2462570Swnj s = spl6(); 2472784Swnj rmfree(uh->uh_map, npf, reg); 2482570Swnj splx(s); 2492570Swnj 2502570Swnj /* 2512570Swnj * Wakeup sleepers for map registers, 2522570Swnj * and also, if there are processes blocked in dgo(), 2532570Swnj * give them a chance at the UNIBUS. 2542570Swnj */ 2552395Swnj if (uh->uh_mrwant) { 2562395Swnj uh->uh_mrwant = 0; 2572395Swnj wakeup((caddr_t)uh->uh_map); 25840Sbill } 2592570Swnj while (uh->uh_actf && ubago(uh->uh_actf)) 2602570Swnj ; 26140Sbill } 26240Sbill 2632729Swnj ubapurge(um) 2642958Swnj register struct uba_ctlr *um; 2652729Swnj { 2662729Swnj register struct uba_hd *uh = um->um_hd; 2672729Swnj register int bdp = (um->um_ubinfo >> 28) & 0x0f; 2682729Swnj 2692729Swnj switch (cpu) { 2702729Swnj #if VAX780 2712729Swnj case VAX_780: 2722958Swnj uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; 2732729Swnj break; 2742729Swnj #endif 2752729Swnj #if VAX750 2762729Swnj case VAX_750: 2772958Swnj uh->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; 2782729Swnj break; 2792729Swnj #endif 2802729Swnj } 2812729Swnj } 2822729Swnj 2832570Swnj /* 2842570Swnj * Generate a reset on uba number uban. Then 2852570Swnj * call each device in the character device table, 2862570Swnj * giving it a chance to clean up so as to be able to continue. 2872570Swnj */ 2882395Swnj ubareset(uban) 2892570Swnj int uban; 290284Sbill { 291284Sbill register struct cdevsw *cdp; 2922646Swnj register struct uba_hd *uh = &uba_hd[uban]; 2931781Sbill int s; 294284Sbill 295302Sbill s = spl6(); 2962646Swnj uh->uh_users = 0; 2972646Swnj uh->uh_zvcnt = 0; 2982646Swnj uh->uh_xclu = 0; 2992646Swnj uh->uh_hangcnt = 0; 3002646Swnj uh->uh_actf = uh->uh_actl = 0; 3012646Swnj uh->uh_bdpwant = 0; 3022646Swnj uh->uh_mrwant = 0; 3032646Swnj wakeup((caddr_t)&uh->uh_bdpwant); 3042646Swnj wakeup((caddr_t)&uh->uh_mrwant); 3052958Swnj printf("uba%d: reset", uban); 3062958Swnj ubainit(uh->uh_uba); 307284Sbill for (cdp = cdevsw; cdp->d_open; cdp++) 3082395Swnj (*cdp->d_reset)(uban); 309284Sbill printf("\n"); 310302Sbill splx(s); 311284Sbill } 3122395Swnj 3132570Swnj /* 3142570Swnj * Init a uba. This is called with a pointer 3152570Swnj * rather than a virtual address since it is called 3162570Swnj * by code which runs with memory mapping disabled. 3172570Swnj * In these cases we really don't need the interrupts 3182570Swnj * enabled, but since we run with ipl high, we don't care 3192570Swnj * if they are, they will never happen anyways. 3202570Swnj */ 3212423Skre ubainit(uba) 3222423Skre register struct uba_regs *uba; 3232395Swnj { 3242395Swnj 3252958Swnj switch (cpu) { 3262958Swnj #if VAX780 3273248Swnj case VAX_780: 3282958Swnj uba->uba_cr = UBACR_ADINIT; 3292958Swnj uba->uba_cr = UBACR_IFS|UBACR_BRIE|UBACR_USEFIE|UBACR_SUEFIE; 3302958Swnj while ((uba->uba_cnfgr & UBACNFGR_UBIC) == 0) 3312958Swnj ; 3322958Swnj break; 3332958Swnj #endif 3342958Swnj #if VAX750 3353248Swnj case VAX_750: 3362958Swnj mtpr(IUR, 1); 3372958Swnj /* give devices time to recover from power fail */ 338*3332Swnj /* THIS IS PROBABLY UNNECESSARY */ 3392958Swnj DELAY(5000000); 340*3332Swnj /* END PROBABLY UNNECESSARY */ 3412958Swnj break; 3422958Swnj #endif 343*3332Swnj #if VAX730 344*3332Swnj case VAX_730: 345*3332Swnj break; 346*3332Swnj #endif 3472958Swnj } 3482395Swnj } 3492395Swnj 3502958Swnj #if VAX780 3512570Swnj /* 3522570Swnj * Check to make sure the UNIBUS adaptor is not hung, 3532570Swnj * with an interrupt in the register to be presented, 3542570Swnj * but not presenting it for an extended period (5 seconds). 3552570Swnj */ 3562395Swnj unhang() 3572395Swnj { 3582395Swnj register int uban; 3592395Swnj 3602395Swnj for (uban = 0; uban < numuba; uban++) { 3612395Swnj register struct uba_hd *uh = &uba_hd[uban]; 3622395Swnj register struct uba_regs *up = uh->uh_uba; 3632395Swnj 3642395Swnj if (up->uba_sr == 0) 3652395Swnj return; 3662395Swnj uh->uh_hangcnt++; 3672759Swnj if (uh->uh_hangcnt > 5*hz) { 3682395Swnj uh->uh_hangcnt = 0; 3692929Swnj printf("uba%d: hung\n", uban); 3702395Swnj ubareset(uban); 3712395Swnj } 3722395Swnj } 3732395Swnj } 3742395Swnj 3752570Swnj /* 3762570Swnj * This is a timeout routine which decrements the ``i forgot to 3772570Swnj * interrupt'' counts, on an 11/780. This prevents slowly growing 3782570Swnj * counts from causing a UBA reset since we are interested only 3792570Swnj * in hang situations. 3802570Swnj */ 3812395Swnj ubawatch() 3822395Swnj { 3832395Swnj register struct uba_hd *uh; 3842395Swnj register int uban; 3852395Swnj 3862784Swnj if (panicstr) 3872784Swnj return; 3882395Swnj for (uban = 0; uban < numuba; uban++) { 3892395Swnj uh = &uba_hd[uban]; 3902395Swnj if (uh->uh_hangcnt) 3912395Swnj uh->uh_hangcnt--; 3922395Swnj } 3932395Swnj } 3942395Swnj 3952570Swnj /* 3962570Swnj * This routine is called by the locore code to 3972570Swnj * process a UBA error on an 11/780. The arguments are passed 3982570Swnj * on the stack, and value-result (through some trickery). 3992570Swnj * In particular, the uvec argument is used for further 4002570Swnj * uba processing so the result aspect of it is very important. 4012570Swnj * It must not be declared register. 4022570Swnj */ 4032423Skre /*ARGSUSED*/ 4042395Swnj ubaerror(uban, uh, xx, uvec, uba) 4052395Swnj register int uban; 4062395Swnj register struct uba_hd *uh; 4072395Swnj int uvec; 4082395Swnj register struct uba_regs *uba; 4092395Swnj { 4102395Swnj register sr, s; 4112395Swnj 4122395Swnj if (uvec == 0) { 4132395Swnj uh->uh_zvcnt++; 4142395Swnj if (uh->uh_zvcnt > 250000) { 4152929Swnj printf("uba%d: too many zero vectors\n"); 4162395Swnj ubareset(uban); 4172395Swnj } 4182395Swnj uvec = 0; 4192395Swnj return; 4202395Swnj } 4212395Swnj if (uba->uba_cnfgr & NEX_CFGFLT) { 4222929Swnj printf("uba%d: sbi fault sr=%b cnfgr=%b\n", 4232929Swnj uban, uba->uba_sr, ubasr_bits, 4243248Swnj uba->uba_cnfgr, NEXFLT_BITS); 4252395Swnj ubareset(uban); 4262395Swnj uvec = 0; 4272395Swnj return; 4282395Swnj } 4292395Swnj sr = uba->uba_sr; 4302395Swnj s = spl7(); 4312929Swnj printf("uba%d: uba error sr=%x fmer=%x fubar=%o\n", 4322470Swnj uban, uba->uba_sr, uba->uba_fmer, 4*uba->uba_fubar); 4332395Swnj splx(s); 4342395Swnj uba->uba_sr = sr; 4352958Swnj uvec &= UBABRRVR_DIV; 4362395Swnj return; 4372395Swnj } 4382395Swnj #endif 439