1*6518Sfeldman /* uba.c 4.43 82/04/11 */ 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; 596348Swnj dk_xfer[unit]++; 606348Swnj dk_wds[unit] += um->um_tab.b_actf->b_actf->b_bcount>>6; 612570Swnj } 622570Swnj if (uh->uh_actf == ui) 632570Swnj uh->uh_actf = ui->ui_forw; 642570Swnj (*um->um_driver->ud_dgo)(um); 652570Swnj return (1); 662616Swnj rwait: 672616Swnj if (uh->uh_actf != ui) { 682616Swnj ui->ui_forw = NULL; 692616Swnj if (uh->uh_actf == NULL) 702616Swnj uh->uh_actf = ui; 712616Swnj else 722616Swnj uh->uh_actl->ui_forw = ui; 732616Swnj uh->uh_actl = ui; 742616Swnj } 752616Swnj splx(s); 762616Swnj return (0); 772570Swnj } 782570Swnj 792616Swnj ubadone(um) 802958Swnj register struct uba_ctlr *um; 812616Swnj { 822616Swnj register struct uba_hd *uh = &uba_hd[um->um_ubanum]; 832616Swnj 842628Swnj if (um->um_driver->ud_xclu) 852616Swnj uh->uh_xclu = 0; 862616Swnj uh->uh_users--; 872616Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 882616Swnj } 892616Swnj 902570Swnj /* 912395Swnj * Allocate and setup UBA map registers, and bdp's 922395Swnj * Flags says whether bdp is needed, whether the caller can't 932395Swnj * wait (e.g. if the caller is at interrupt level). 9440Sbill * 952570Swnj * Return value: 9640Sbill * Bits 0-8 Byte offset 9740Sbill * Bits 9-17 Start map reg. no. 9840Sbill * Bits 18-27 No. mapping reg's 9940Sbill * Bits 28-31 BDP no. 10040Sbill */ 1012395Swnj ubasetup(uban, bp, flags) 1022395Swnj struct buf *bp; 10340Sbill { 1042395Swnj register struct uba_hd *uh = &uba_hd[uban]; 10540Sbill register int temp, i; 10640Sbill int npf, reg, bdp; 10740Sbill unsigned v; 10840Sbill register struct pte *pte, *io; 10940Sbill struct proc *rp; 11040Sbill int a, o, ubinfo; 11140Sbill 1123498Swnj #if VAX7ZZ 1133498Swnj if (cpu == VAX_7ZZ) 1143332Swnj flags &= ~UBA_NEEDBDP; 1153332Swnj #endif 11640Sbill v = btop(bp->b_un.b_addr); 11740Sbill o = (int)bp->b_un.b_addr & PGOFSET; 11840Sbill npf = btoc(bp->b_bcount + o) + 1; 11940Sbill a = spl6(); 1202784Swnj while ((reg = rmalloc(uh->uh_map, npf)) == 0) { 1213913Swnj if (flags & UBA_CANTWAIT) { 1223913Swnj splx(a); 1232395Swnj return (0); 1243913Swnj } 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); 1333913Swnj splx(a); 1342395Swnj return (0); 1352395Swnj } 1362395Swnj uh->uh_bdpwant++; 1372395Swnj sleep((caddr_t)uh->uh_map, PSWP); 13840Sbill } 1392463Swnj uh->uh_bdpfree &= ~(1 << (bdp-1)); 1404758Swnj } else if (flags & UBA_HAVEBDP) 1414758Swnj bdp = (flags >> 28) & 0xf; 14240Sbill splx(a); 1432463Swnj reg--; 14440Sbill ubinfo = (bdp << 28) | (npf << 18) | (reg << 9) | o; 1452958Swnj temp = (bdp << 21) | UBAMR_MRV; 14640Sbill if (bdp && (o & 01)) 1472958Swnj temp |= UBAMR_BO; 1486382Swnj rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; 1496382Swnj if ((bp->b_flags & B_PHYS) == 0) 150728Sbill pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)]; 1516382Swnj else if (bp->b_flags & B_UAREA) 1526382Swnj pte = &rp->p_addr[v]; 1536382Swnj else if (bp->b_flags & B_PAGET) 1546382Swnj pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 1556382Swnj else 1566382Swnj pte = vtopte(rp, v); 1576382Swnj io = &uh->uh_uba->uba_map[reg]; 1586382Swnj while (--npf != 0) { 1596382Swnj if (pte->pg_pfnum == 0) 1606382Swnj panic("uba zero uentry"); 1616382Swnj *(int *)io++ = pte++->pg_pfnum | temp; 16240Sbill } 16340Sbill *(int *)io++ = 0; 16440Sbill return (ubinfo); 16540Sbill } 16640Sbill 16740Sbill /* 1682570Swnj * Non buffer setup interface... set up a buffer and call ubasetup. 16940Sbill */ 1702395Swnj uballoc(uban, addr, bcnt, flags) 1713107Swnj int uban; 17240Sbill caddr_t addr; 1733107Swnj int bcnt, flags; 17440Sbill { 175883Sbill struct buf ubabuf; 17640Sbill 17740Sbill ubabuf.b_un.b_addr = addr; 17840Sbill ubabuf.b_flags = B_BUSY; 17940Sbill ubabuf.b_bcount = bcnt; 180883Sbill /* that's all the fields ubasetup() needs */ 1812395Swnj return (ubasetup(uban, &ubabuf, flags)); 18240Sbill } 18340Sbill 1842053Swnj /* 1852570Swnj * Release resources on uba uban, and then unblock resource waiters. 1862570Swnj * The map register parameter is by value since we need to block 1872570Swnj * against uba resets on 11/780's. 1882053Swnj */ 1892395Swnj ubarelse(uban, amr) 1902053Swnj int *amr; 19140Sbill { 1922395Swnj register struct uba_hd *uh = &uba_hd[uban]; 1932570Swnj register int bdp, reg, npf, s; 1942053Swnj int mr; 19540Sbill 1962570Swnj /* 1972570Swnj * Carefully see if we should release the space, since 1982570Swnj * it may be released asynchronously at uba reset time. 1992570Swnj */ 2002570Swnj s = spl6(); 2012053Swnj mr = *amr; 2022053Swnj if (mr == 0) { 2032570Swnj /* 2042570Swnj * A ubareset() occurred before we got around 2052570Swnj * to releasing the space... no need to bother. 2062570Swnj */ 2072570Swnj splx(s); 2082053Swnj return; 2092053Swnj } 2102067Swnj *amr = 0; 2112570Swnj splx(s); /* let interrupts in, we're safe for a while */ 21240Sbill bdp = (mr >> 28) & 0x0f; 21340Sbill if (bdp) { 2142729Swnj switch (cpu) { 2152423Skre #if VAX780 2162423Skre case VAX_780: 2172958Swnj uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; 2182423Skre break; 2192423Skre #endif 2202423Skre #if VAX750 2212423Skre case VAX_750: 2222958Swnj uh->uh_uba->uba_dpr[bdp] |= 2232958Swnj UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; 2242423Skre break; 2252423Skre #endif 2262423Skre } 2272570Swnj uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */ 2282395Swnj if (uh->uh_bdpwant) { 2292395Swnj uh->uh_bdpwant = 0; 2302395Swnj wakeup((caddr_t)uh->uh_map); 23140Sbill } 23240Sbill } 2332570Swnj /* 2342570Swnj * Put back the registers in the resource map. 2352570Swnj * The map code must not be reentered, so we do this 2362570Swnj * at high ipl. 2372570Swnj */ 23840Sbill npf = (mr >> 18) & 0x3ff; 23940Sbill reg = ((mr >> 9) & 0x1ff) + 1; 2402570Swnj s = spl6(); 2412784Swnj rmfree(uh->uh_map, npf, reg); 2422570Swnj splx(s); 2432570Swnj 2442570Swnj /* 2452570Swnj * Wakeup sleepers for map registers, 2462570Swnj * and also, if there are processes blocked in dgo(), 2472570Swnj * give them a chance at the UNIBUS. 2482570Swnj */ 2492395Swnj if (uh->uh_mrwant) { 2502395Swnj uh->uh_mrwant = 0; 2512395Swnj wakeup((caddr_t)uh->uh_map); 25240Sbill } 2532570Swnj while (uh->uh_actf && ubago(uh->uh_actf)) 2542570Swnj ; 25540Sbill } 25640Sbill 2572729Swnj ubapurge(um) 2582958Swnj register struct uba_ctlr *um; 2592729Swnj { 2602729Swnj register struct uba_hd *uh = um->um_hd; 2612729Swnj register int bdp = (um->um_ubinfo >> 28) & 0x0f; 2622729Swnj 2632729Swnj switch (cpu) { 2642729Swnj #if VAX780 2652729Swnj case VAX_780: 2662958Swnj uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; 2672729Swnj break; 2682729Swnj #endif 2692729Swnj #if VAX750 2702729Swnj case VAX_750: 2712958Swnj uh->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; 2722729Swnj break; 2732729Swnj #endif 2742729Swnj } 2752729Swnj } 2762729Swnj 2772570Swnj /* 2782570Swnj * Generate a reset on uba number uban. Then 2792570Swnj * call each device in the character device table, 2802570Swnj * giving it a chance to clean up so as to be able to continue. 2812570Swnj */ 2822395Swnj ubareset(uban) 2832570Swnj int uban; 284284Sbill { 285284Sbill register struct cdevsw *cdp; 2862646Swnj register struct uba_hd *uh = &uba_hd[uban]; 2871781Sbill int s; 288284Sbill 289302Sbill s = spl6(); 2902646Swnj uh->uh_users = 0; 2912646Swnj uh->uh_zvcnt = 0; 2922646Swnj uh->uh_xclu = 0; 2932646Swnj uh->uh_hangcnt = 0; 2942646Swnj uh->uh_actf = uh->uh_actl = 0; 2952646Swnj uh->uh_bdpwant = 0; 2962646Swnj uh->uh_mrwant = 0; 2972646Swnj wakeup((caddr_t)&uh->uh_bdpwant); 2982646Swnj wakeup((caddr_t)&uh->uh_mrwant); 2992958Swnj printf("uba%d: reset", uban); 3002958Swnj ubainit(uh->uh_uba); 301284Sbill for (cdp = cdevsw; cdp->d_open; cdp++) 3022395Swnj (*cdp->d_reset)(uban); 3035221Swnj #ifdef INET 3045221Swnj ifubareset(uban); 3055221Swnj #endif 306284Sbill printf("\n"); 307302Sbill splx(s); 308284Sbill } 3092395Swnj 3102570Swnj /* 3112570Swnj * Init a uba. This is called with a pointer 3122570Swnj * rather than a virtual address since it is called 3132570Swnj * by code which runs with memory mapping disabled. 3142570Swnj * In these cases we really don't need the interrupts 3152570Swnj * enabled, but since we run with ipl high, we don't care 3162570Swnj * if they are, they will never happen anyways. 3172570Swnj */ 3182423Skre ubainit(uba) 3192423Skre register struct uba_regs *uba; 3202395Swnj { 3212395Swnj 3222958Swnj switch (cpu) { 3232958Swnj #if VAX780 3243248Swnj case VAX_780: 3252958Swnj uba->uba_cr = UBACR_ADINIT; 3262958Swnj uba->uba_cr = UBACR_IFS|UBACR_BRIE|UBACR_USEFIE|UBACR_SUEFIE; 3272958Swnj while ((uba->uba_cnfgr & UBACNFGR_UBIC) == 0) 3282958Swnj ; 3292958Swnj break; 3302958Swnj #endif 3312958Swnj #if VAX750 3323248Swnj case VAX_750: 3333352Swnj #endif 3343498Swnj #if VAX7ZZ 3353498Swnj case VAX_7ZZ: 3363352Swnj #endif 3373498Swnj #if defined(VAX750) || defined(VAX7ZZ) 3383352Swnj mtpr(IUR, 0); 3392958Swnj /* give devices time to recover from power fail */ 3403332Swnj /* THIS IS PROBABLY UNNECESSARY */ 3413352Swnj DELAY(500000); 3423332Swnj /* END PROBABLY UNNECESSARY */ 3432958Swnj break; 3442958Swnj #endif 3452958Swnj } 3462395Swnj } 3472395Swnj 3482958Swnj #if VAX780 3492570Swnj /* 3502570Swnj * Check to make sure the UNIBUS adaptor is not hung, 3512570Swnj * with an interrupt in the register to be presented, 3522570Swnj * but not presenting it for an extended period (5 seconds). 3532570Swnj */ 3542395Swnj unhang() 3552395Swnj { 3562395Swnj register int uban; 3572395Swnj 3582395Swnj for (uban = 0; uban < numuba; uban++) { 3592395Swnj register struct uba_hd *uh = &uba_hd[uban]; 3602395Swnj register struct uba_regs *up = uh->uh_uba; 3612395Swnj 3622395Swnj if (up->uba_sr == 0) 3632395Swnj return; 3643945Sroot up->uba_sr = UBASR_CRD|UBASR_LEB; 3652395Swnj uh->uh_hangcnt++; 3662759Swnj if (uh->uh_hangcnt > 5*hz) { 3672395Swnj uh->uh_hangcnt = 0; 3682929Swnj printf("uba%d: hung\n", uban); 3692395Swnj ubareset(uban); 3702395Swnj } 3712395Swnj } 3722395Swnj } 3732395Swnj 3742570Swnj /* 3752570Swnj * This is a timeout routine which decrements the ``i forgot to 3762570Swnj * interrupt'' counts, on an 11/780. This prevents slowly growing 3772570Swnj * counts from causing a UBA reset since we are interested only 3782570Swnj * in hang situations. 3792570Swnj */ 3802395Swnj ubawatch() 3812395Swnj { 3822395Swnj register struct uba_hd *uh; 3832395Swnj register int uban; 3842395Swnj 3852784Swnj if (panicstr) 3862784Swnj return; 3872395Swnj for (uban = 0; uban < numuba; uban++) { 3882395Swnj uh = &uba_hd[uban]; 3892395Swnj if (uh->uh_hangcnt) 3902395Swnj uh->uh_hangcnt--; 3912395Swnj } 3922395Swnj } 3932395Swnj 3944024Swnj int ubawedgecnt = 10; 3954024Swnj int ubacrazy = 500; 3962570Swnj /* 3972570Swnj * This routine is called by the locore code to 3982570Swnj * process a UBA error on an 11/780. The arguments are passed 3992570Swnj * on the stack, and value-result (through some trickery). 4002570Swnj * In particular, the uvec argument is used for further 4012570Swnj * uba processing so the result aspect of it is very important. 4022570Swnj * It must not be declared register. 4032570Swnj */ 4042423Skre /*ARGSUSED*/ 4052395Swnj ubaerror(uban, uh, xx, uvec, uba) 4062395Swnj register int uban; 4072395Swnj register struct uba_hd *uh; 4082395Swnj int uvec; 4092395Swnj register struct uba_regs *uba; 4102395Swnj { 4112395Swnj register sr, s; 4122395Swnj 4132395Swnj if (uvec == 0) { 4142395Swnj uh->uh_zvcnt++; 4152395Swnj if (uh->uh_zvcnt > 250000) { 4162929Swnj printf("uba%d: too many zero vectors\n"); 4172395Swnj ubareset(uban); 4182395Swnj } 4192395Swnj uvec = 0; 4202395Swnj return; 4212395Swnj } 4222395Swnj if (uba->uba_cnfgr & NEX_CFGFLT) { 4232929Swnj printf("uba%d: sbi fault sr=%b cnfgr=%b\n", 4242929Swnj uban, uba->uba_sr, ubasr_bits, 4253248Swnj uba->uba_cnfgr, NEXFLT_BITS); 4262395Swnj ubareset(uban); 4272395Swnj uvec = 0; 4282395Swnj return; 4292395Swnj } 4302395Swnj sr = uba->uba_sr; 4312395Swnj s = spl7(); 4323473Swnj printf("uba%d: uba error sr=%b fmer=%x fubar=%o\n", 4333473Swnj uban, uba->uba_sr, ubasr_bits, uba->uba_fmer, 4*uba->uba_fubar); 4342395Swnj splx(s); 4352395Swnj uba->uba_sr = sr; 4362958Swnj uvec &= UBABRRVR_DIV; 4374024Swnj if (++uh->uh_errcnt % ubawedgecnt == 0) { 4384024Swnj if (uh->uh_errcnt > ubacrazy) 4394024Swnj panic("uba crazy"); 4404024Swnj printf("ERROR LIMIT "); 4414024Swnj ubareset(uban); 4424024Swnj uvec = 0; 4434024Swnj return; 4444024Swnj } 4452395Swnj return; 4462395Swnj } 4472395Swnj #endif 4483745Sroot 4496348Swnj #ifdef notdef 4503745Sroot /* 4513745Sroot * This routine allows remapping of previously 4523745Sroot * allocated UNIBUS bdp and map resources 4533745Sroot * onto different memory addresses. 4543745Sroot * It should only be used by routines which need 4553745Sroot * small fixed length mappings for long periods of time 4563745Sroot * (like the ARPANET ACC IMP interface). 4573745Sroot * It only maps kernel addresses. 4583745Sroot */ 4593745Sroot ubaremap(uban, ubinfo, addr) 4603745Sroot int uban; 4613745Sroot register unsigned ubinfo; 4623745Sroot caddr_t addr; 4633745Sroot { 4643745Sroot register struct uba_hd *uh = &uba_hd[uban]; 4653745Sroot register struct pte *pte, *io; 4663745Sroot register int temp, bdp; 4673745Sroot int npf, o; 4683745Sroot 4693745Sroot o = (int)addr & PGOFSET; 4703745Sroot bdp = (ubinfo >> 28) & 0xf; 4713745Sroot npf = (ubinfo >> 18) & 0x3ff; 4723745Sroot io = &uh->uh_uba->uba_map[(ubinfo >> 9) & 0x1ff]; 4733745Sroot temp = (bdp << 21) | UBAMR_MRV; 4743745Sroot 4753745Sroot /* 4763745Sroot * If using buffered data path initiate purge 4773745Sroot * of old data and set byte offset bit if next 4783745Sroot * transfer will be from odd address. 4793745Sroot */ 4803745Sroot if (bdp) { 4813745Sroot switch (cpu) { 4823745Sroot #if VAX780 4833745Sroot case VAX_780: 4843745Sroot uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; 4853745Sroot break; 4863745Sroot #endif 4873745Sroot #if VAX750 4883745Sroot case VAX_750: 4893745Sroot uh->uh_uba->uba_dpr[bdp] |= 4903745Sroot UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; 4913745Sroot break; 4923745Sroot #endif 4933745Sroot } 4943745Sroot if (o & 1) 4953745Sroot temp |= UBAMR_BO; 4963745Sroot } 4973745Sroot 4983745Sroot /* 4993745Sroot * Set up the map registers, leaving an invalid reg 5003745Sroot * at the end to guard against wild unibus transfers. 5013745Sroot */ 5023745Sroot pte = &Sysmap[btop(((int)addr)&0x7fffffff)]; 5033745Sroot while (--npf != 0) 5043745Sroot *(int *)io++ = pte++->pg_pfnum | temp; 5053745Sroot *(int *)io = 0; 5063745Sroot 5073745Sroot /* 5083745Sroot * Return effective UNIBUS address. 5093745Sroot */ 5103745Sroot return (ubinfo | o); 5113745Sroot } 5124966Swnj #endif 513*6518Sfeldman 514*6518Sfeldman /* 515*6518Sfeldman * This routine is called by a driver for a device with on-board Unibus 516*6518Sfeldman * memory. It removes the memory block from the Unibus resource map 517*6518Sfeldman * and clears the map registers for the block. 518*6518Sfeldman * 519*6518Sfeldman * Arguments are the Unibus number, the Unibus address of the memory 520*6518Sfeldman * block, and its size in blocks of 512 bytes. 521*6518Sfeldman * 522*6518Sfeldman * Returns addr if successful, 0 if not. 523*6518Sfeldman */ 524*6518Sfeldman 525*6518Sfeldman ubamem(uban, addr, size) 526*6518Sfeldman { 527*6518Sfeldman register struct uba_hd *uh = &uba_hd[uban]; 528*6518Sfeldman register int *m; 529*6518Sfeldman register int i, a, s; 530*6518Sfeldman 531*6518Sfeldman s = spl6(); 532*6518Sfeldman a = rmget(uh->uh_map, size, addr>>9); 533*6518Sfeldman splx(s); 534*6518Sfeldman if (a) { 535*6518Sfeldman m = (int *) &uh->uh_uba->uba_map[a]; 536*6518Sfeldman for (i=0; i<size; i++) 537*6518Sfeldman *m++ = 0; /* All off, especially 'valid' */ 538*6518Sfeldman } 539*6518Sfeldman return(a); 540*6518Sfeldman } 541