📄 uba.c
字号:
* field in the configuration register. Beware * of callers that request memory ``out of order''. */ if (uh->uba_type & UBA780) { int cr = uh->uh_uba->uba_cr; i = (addr + npg * 512 + 8191) / 8192; if (i > (cr >> 26)) uh->uh_uba->uba_cr |= i << 26; } } return (a);}#ifdef vax#include "ik.h"#if NIK > 0/* * Map a virtual address into users address space. Actually all we * do is turn on the user mode write protection bits for the particular * page of memory involved. */maptouser(vaddress) caddr_t vaddress;{ Sysmap[(((unsigned)(vaddress))-0x80000000) >> 9].pg_prot = (PG_UW>>27);}unmaptouser(vaddress) caddr_t vaddress;{ Sysmap[(((unsigned)(vaddress))-0x80000000) >> 9].pg_prot = (PG_KW>>27);}#endif#endif vax/* * Check the number of zero vectors and report if we get too many of them. * Always reset the zero vector count and the zero vector timer flag. */ubatimer(uban)int uban;{ struct uba_hd *uh; uh = &uba_hd[uban]; if(uh->uh_zvcnt > zvthresh) mprintf("ubatimer: uba%d -- %d zero vectors in %d minutes\n", uban, uh->uh_zvcnt, zvintvl/60); uh->uh_zvcnt = 0; uh->uh_zvflg = 0;}#ifdef vax/* * vs_bufctl is the locking mechanism that allows the VAXSTAR disk * tape controllers to share a common I/O buffer. * * This routine MUST be called from spl5. */struct vsbuf vsbuf = { 0, 0, 0 };vs_bufctl(vsdev)struct vsdev *vsdev;{ register struct vsbuf *vs = &vsbuf; register int rval; struct vsdev *temp; int action; int s; action = vsdev->vsd_action; for (;;) { switch (action) { case VS_DEALLOC: if (vs->vs_active == 0) panic("vs_bufctl: VS_DEALLOC: no owner"); if (vs->vs_wants) { if (vs->vs_wants->vsd_id != vs->vs_active->vsd_id) { vs->vs_active = vs->vs_wants; vs->vs_status = vs->vs_active->vsd_id; vs->vs_wants = VS_IDLE; } else { panic("vs_bufctl: VS_DEALLOC: wanted by owner"); return; } } else { vs->vs_active = VS_IDLE; vs->vs_status = VS_IDLE; return; } break; case VS_ALLOC: if (vs->vs_active == 0) { vs->vs_active = vsdev; vs->vs_status = vsdev->vsd_id; } else { vs->vs_wants = vsdev; return; } break; case VS_KEEP: return; break; case VS_WANTBACK: if (vs->vs_wants) { if(vs->vs_active == 0) { panic("vs_bufctl: VS_WANTBACK: not active"); } temp = vs->vs_active; vs->vs_active = vs->vs_wants; vs->vs_status = vs->vs_active->vsd_id; vs->vs_wants = temp; vs->vs_wants->vsd_action = VS_ALLOC; } break; default: panic("vs_bufctl: unknown action"); break; } if (vs->vs_active != 0) { action = (*vs->vs_active->vsd_funcptr)(); /* call to stc or sdc driver */ if(action == VS_ALLOC) { panic("vs_bufctl: illegal VS_ALLOC returned"); } vs->vs_active->vsd_action = action; } else { panic("vsbufctl: active pointer null"); return; } } /* forever */}#endif vax/* * Allocate and setup Q-BUS map registers, and bdp's * Flags says whether bdp is needed, whether the caller can't * wait (e.g. if the caller is at interrupt level). * * Return value: * Bits 0-8 Byte offset 512 number of bytes * Bits 9-21 Start map reg. no. all the 8192 regs * Bits 22-31 No. mapping reg's allocated, divided by 8 */qbasetup(uban, bp, flags) struct buf *bp;{ register struct uba_hd *uh = &uba_hd[uban]; int npf, reg, fake_npf; unsigned v; register struct pte *pte, *io; struct proc *rp; int a, o, ubinfo, vax_pfn; static int first_time = 0; int user_addr = 0;#ifdef mips int mips_of; /* offset within a mips page */ int mips_pfn; /* PFN of a mips pte */#endif mips flags &= ~UBA_NEEDBDP; /* The first time through to get map registers allocate 512 of them * and never use them or give them back. This will allow any calls * from a users driver to uballoc to get these without conflicts with * the ones this routine controls. * This is done for backward compatability. */ if( first_time == 0) { first_time = 1; rmalloc(uh->uq_map, (long)(btoc(QBNOTUB * NBPG) + 1)); } /* Find the page, offset into the page and the number of vax * page frames that will be needed. This code will work for mips * also because we will simulate vax pfn's when infact one mips * pfn is equal to eight (8) vax pfn's. */ v = btop(bp->b_un.b_addr); o = (int)bp->b_un.b_addr & 0x1ff; /* offset within a VAX page */#ifdef mips /* offset within a mips page */ mips_of = (int)bp->b_un.b_addr & PGOFSET;#endif mips /* * Number of VAX pages spanned by the buffer + 1(hence number of * map registers needed since we need one guard page) */ npf = (((unsigned)(bp->b_bcount + o)+0x1ff) >> 9) + 1; /* get regs in groups of 8 to allow the ubinfo word to * hold all the information. This may be a waste of maps but * it gets us closer to using all 8K maps on a Q22 bus, we need * to do this because we can't get all the information into * the returned integer. Sigh! * * Also MIPS uses 1 map where VAX looks for 8 so if its on * a MIPS system fake_npf is really the vax maps needed. * */ fake_npf = (npf + (8 - (npf % 8))); /* Allocate the map registers for use by calling rmalloc */ a = spl6(); while ((reg = rmalloc(uh->uq_map, (long)fake_npf)) == 0) { if (flags & UBA_CANTWAIT) { splx(a); return (0); } uh->uh_mrwant++; sleep((caddr_t)&uh->uh_mrwant, PSWP); } splx(a); /* Setup the return value which holds the map register number * and related info. */ reg--; ubinfo = ((reg & 0x1fff) << 9) | o; ubinfo |= ((fake_npf /8) << 22); /* Now load the map registers with the pfn data. This is not a * straight forward task. The pfn data is different on the vax and * mips systems AND the mips sometimes uses its pfn's and othertimes * it uses physical. The following code fragment will set up the * map register based on this data. */ /* running process */ rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; pte = 0; if ((bp->b_flags & B_PHYS) == 0) { /* Not Physical */#ifdef vax pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)];#else /* mips KSEG Addressing */ if(IS_KSEG0(bp->b_un.b_addr)){ /* unmapped KSEG areas */ mips_pfn = btop(K0_TO_PHYS(bp->b_un.b_addr)); } else if(IS_KSEG1(bp->b_un.b_addr)){ /* unmapped KSEG areas */ mips_pfn = btop(K1_TO_PHYS(bp->b_un.b_addr)); } else if(IS_KSEG2(bp->b_un.b_addr)){ /* mapped KSEG areas */ pte = &Sysmap[btop(bp->b_un.b_addr - K2BASE)]; }#endif vax } else if (bp->b_flags & B_UAREA) /* User area */ pte = &rp->p_addr[v]; else if (bp->b_flags & B_PAGET) /* Page Table */ pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; else if ((bp->b_flags & B_SMEM) && /* SHMEM */ ((bp->b_flags & B_DIRTY) == 0)) pte = ((struct smem *)rp)->sm_ptaddr + v; else { pte = vtopte(rp, v); user_addr++; } if ((uh->uba_type & UBAUVI) ==0 || (flags&UBA_MAPANYWAY)) { /* get address of starting UNIBUS map register */ io = &uh->uh_uba->uba_map[reg]; /* Loop to load all the map registers with pte information. * For a mips we need to simulate vax pte structures. * * On a VAX, we have npf map registers to fill, each * map register is to be filled by a VAX pte. * * On a mips, we have npf map registers to fill, but * each mips page is 4KB, so we have fewer mips ptes * to use. * * The following loop iterates for each map register. */ while (--npf != 0) {#ifdef mips if(pte != 0) { /* pte points to the mips pte */ if (pte->pg_pfnum == 0) panic("uba zero uentry"); vax_pfn = (pte->pg_pfnum << 3) + (mips_of / 0x200); } else { /* There are no pte's, use pfn's */ vax_pfn = (mips_pfn << 3) + (mips_of / 0x200); } *(int *)io++ = vax_pfn | UBAMR_MRV; mips_of += 0x200; /* next vax page */ if (mips_of >= 0x1000) { /* Crossing mips page boundary */ /* Go on to next mips page */ mips_of -= 0x1000; if (pte) pte++; else mips_pfn++; }#else if (user_addr && (((int)pte & PGOFSET) < CLSIZE*sizeof(struct pte) || pte->pg_pfnum == 0)) pte = vtopte(rp, v); if (pte->pg_pfnum == 0) panic("uba zero uentry"); *(int *)io++ = pte++->pg_pfnum | UBAMR_MRV; v++;#endif mips } *(int *)io++ = 0; WBFLUSH; } else { ubinfo = contigphys( ubinfo, bp->b_bcount, pte); ++reg; a = spl6(); rmfree( uh->uq_map, (long)fake_npf, (long)reg); splx(a); } return (ubinfo);}/* * Non buffer setup interface... set up a buffer and call ubasetup. */qballoc(uban, addr, bcnt, flags) int uban; caddr_t addr; int bcnt, flags;{ struct buf qbbuf; qbbuf.b_un.b_addr = addr; qbbuf.b_flags = B_BUSY; qbbuf.b_bcount = bcnt; /* that's all the fields qbasetup() needs */ return (qbasetup(uban, &qbbuf, flags));} /* * Release resources on uba uban, and then unblock resource waiters. * The map register parameter is by value since we need to block * against uba resets on 11/780's. */qbarelse(uban, amr) unsigned *amr;{ register struct uba_hd *uh = &uba_hd[uban]; register int reg, npf, s; unsigned mr; /* * Carefully see if we should release the space, since * it may be released asynchronously at uba reset time. */ s = spl6(); mr = *amr; if (mr == 0) { /* * A ubareset() occurred before we got around * to releasing the space... no need to bother. */ splx(s); return; } *amr = 0; splx(s); /* let interrupts in, we're safe for a while */ /* * Put back the registers in the resource map. * The map code must not be reentered, so we do this * at high ipl. */ npf = (mr >> 22) * 8; reg = (((mr >> 9) & QBREGMASK) + 1); s = spl6(); rmfree(uh->uq_map, (long)npf , (long)reg); splx(s); /* * Wakeup sleepers for map registers, * and also, if there are processes blocked in dgo(), * give them a chance at the UNIBUS. */ if (uh->uh_mrwant) { uh->uh_mrwant = 0; wakeup((caddr_t)&uh->uh_mrwant); } while (uh->uh_actf && ubago(uh->uh_actf)) ;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -