📄 uba.c
字号:
/* * Copyright (c) 1982, 1986 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)uba.c 7.10 (Berkeley) 12/16/90 */#include "sys/param.h"#include "sys/systm.h"#include "sys/map.h"#include "sys/buf.h"#include "sys/vm.h"#include "sys/user.h"#include "sys/proc.h"#include "sys/conf.h"#include "sys/dkstat.h"#include "sys/kernel.h"#include "../include/pte.h"#include "../include/cpu.h"#include "../include/mtpr.h"#include "../vax/nexus.h"#include "ubareg.h"#include "ubavar.h"#ifdef DW780char ubasr_bits[] = UBASR_BITS;#endif#define spluba spl7 /* IPL 17 *//* * Do transfer on device argument. The controller * and uba involved are implied by the device. * We queue for resource wait in the uba code if necessary. * We return 1 if the transfer was started, 0 if it was not. * * The onq argument must be zero iff the device is not on the * queue for this UBA. If onq is set, the device must be at the * head of the queue. In any case, if the transfer is started, * the device will be off the queue, and if not, it will be on. * * Drivers that allocate one BDP and hold it for some time should * set ud_keepbdp. In this case um_bdp tells which BDP is allocated * to the controller, unless it is zero, indicating that the controller * does not now have a BDP. */ubaqueue(ui, onq) register struct uba_device *ui; int onq;{ register struct uba_ctlr *um = ui->ui_mi; register struct uba_hd *uh; register struct uba_driver *ud; register int s, unit; uh = &uba_hd[um->um_ubanum]; ud = um->um_driver; s = spluba(); /* * Honor exclusive BDP use requests. */ if (ud->ud_xclu && uh->uh_users > 0 || uh->uh_xclu) goto rwait; if (ud->ud_keepbdp) { /* * First get just a BDP (though in fact it comes with * one map register too). */ if (um->um_bdp == 0) { um->um_bdp = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP|UBA_CANTWAIT); if (um->um_bdp == 0) goto rwait; } /* now share it with this transfer */ um->um_ubinfo = ubasetup(um->um_ubanum, um->um_tab.b_actf->b_actf, um->um_bdp|UBA_HAVEBDP|UBA_CANTWAIT); } else um->um_ubinfo = ubasetup(um->um_ubanum, um->um_tab.b_actf->b_actf, UBA_NEEDBDP|UBA_CANTWAIT); if (um->um_ubinfo == 0) goto rwait; uh->uh_users++; if (ud->ud_xclu) uh->uh_xclu = 1; splx(s); if (ui->ui_dk >= 0) { unit = ui->ui_dk; dk_busy |= 1<<unit; dk_xfer[unit]++; dk_wds[unit] += um->um_tab.b_actf->b_actf->b_bcount>>6; } if (onq) uh->uh_actf = ui->ui_forw; (*ud->ud_dgo)(um); return (1);rwait: if (!onq) { ui->ui_forw = NULL; if (uh->uh_actf == NULL) uh->uh_actf = ui; else uh->uh_actl->ui_forw = ui; uh->uh_actl = ui; } splx(s); return (0);}ubadone(um) register struct uba_ctlr *um;{ register struct uba_hd *uh = &uba_hd[um->um_ubanum]; if (um->um_driver->ud_xclu) uh->uh_xclu = 0; uh->uh_users--; if (um->um_driver->ud_keepbdp) um->um_ubinfo &= ~BDPMASK; /* keep BDP for misers */ ubarelse(um->um_ubanum, &um->um_ubinfo);}/* * Allocate and setup UBA 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 encodes map register plus page offset, * bdp number and number of map registers. */ubasetup(uban, bp, flags) int uban; register struct buf *bp; register int flags;{ register struct uba_hd *uh = &uba_hd[uban]; register struct pte *pte, *io; register int npf; int pfnum, temp; int reg, bdp; unsigned v; struct proc *rp; int a, o, ubinfo;#ifdef DW730 if (uh->uh_type == DW730) flags &= ~UBA_NEEDBDP;#endif#ifdef QBA if (uh->uh_type == QBA) flags &= ~UBA_NEEDBDP;#endif o = (int)bp->b_un.b_addr & PGOFSET; npf = btoc(bp->b_bcount + o) + 1; if (npf > UBA_MAXNMR) panic("uba xfer too big"); a = spluba(); while ((reg = rmalloc(uh->uh_map, (long)npf)) == 0) { if (flags & UBA_CANTWAIT) { splx(a); return (0); } uh->uh_mrwant++; sleep((caddr_t)&uh->uh_mrwant, PSWP); } if ((flags & UBA_NEED16) && reg + npf > 128) { /* * Could hang around and try again (if we can ever succeed). * Won't help any current device... */ rmfree(uh->uh_map, (long)npf, (long)reg); splx(a); return (0); } bdp = 0; if (flags & UBA_NEEDBDP) { while ((bdp = ffs((long)uh->uh_bdpfree)) == 0) { if (flags & UBA_CANTWAIT) { rmfree(uh->uh_map, (long)npf, (long)reg); splx(a); return (0); } uh->uh_bdpwant++; sleep((caddr_t)&uh->uh_bdpwant, PSWP); } uh->uh_bdpfree &= ~(1 << (bdp-1)); } else if (flags & UBA_HAVEBDP) bdp = (flags >> 28) & 0xf; splx(a); reg--; ubinfo = UBAI_INFO(o, reg, npf, bdp); temp = (bdp << 21) | UBAMR_MRV; if (bdp && (o & 01)) temp |= UBAMR_BO; if ((bp->b_flags & B_PHYS) == 0) pte = kvtopte(bp->b_un.b_addr); else if (bp->b_flags & B_PAGET) pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; else { rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; v = btop(bp->b_un.b_addr); if (bp->b_flags & B_UAREA) pte = &rp->p_addr[v]; else pte = vtopte(rp, v); } io = &uh->uh_mr[reg]; while (--npf > 0) { pfnum = pte->pg_pfnum; if (pfnum == 0) panic("uba zero uentry"); pte++; *(int *)io++ = pfnum | temp; } *(int *)io = 0; return (ubinfo);}/* * Non buffer setup interface... set up a buffer and call ubasetup. */uballoc(uban, addr, bcnt, flags) int uban; caddr_t addr; int bcnt, flags;{ struct buf ubabuf; ubabuf.b_un.b_addr = addr; ubabuf.b_flags = B_BUSY; ubabuf.b_bcount = bcnt; /* that's all the fields ubasetup() needs */ return (ubasetup(uban, &ubabuf, 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. */ubarelse(uban, amr) int *amr;{ register struct uba_hd *uh = &uba_hd[uban]; register int bdp, reg, npf, s; int mr; /* * Carefully see if we should release the space, since * it may be released asynchronously at uba reset time. */ s = spluba(); 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; bdp = UBAI_BDP(mr); if (bdp) { switch (uh->uh_type) {#ifdef DWBUA case DWBUA: BUA(uh->uh_uba)->bua_dpr[bdp] |= BUADPR_PURGE; break;#endif#ifdef DW780 case DW780: uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; break;#endif#ifdef DW750 case DW750: uh->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; break;#endif default: break; } uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */ if (uh->uh_bdpwant) { uh->uh_bdpwant = 0; wakeup((caddr_t)&uh->uh_bdpwant); } } /* * Put back the registers in the resource map. * The map code must not be reentered, * nor can the registers be freed twice. * Unblock interrupts once this is done. */ npf = UBAI_NMR(mr); reg = UBAI_MR(mr) + 1; rmfree(uh->uh_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 && ubaqueue(uh->uh_actf, 1)) ;}ubapurge(um) register struct uba_ctlr *um;{ register struct uba_hd *uh = um->um_hd; register int bdp = UBAI_BDP(um->um_ubinfo); switch (uh->uh_type) {#ifdef DWBUA case DWBUA: BUA(uh->uh_uba)->bua_dpr[bdp] |= BUADPR_PURGE; break;#endif#ifdef DW780 case DW780: uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE; break;#endif#ifdef DW750 case DW750: uh->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE; break;#endif default: break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -