Ultrix-3.1/sys/sys/ubmap.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
/*
* SCCSID: @(#)ubmap.c 3.0 4/21/86
*/
/*
* File name:
*
* ubmap.c
*
* Source file description:
*
* This module contains the kernel routines needed to: initialize,
* allocate, and free the unibus map resource. These routines were
* moved from main.c and machdep.c to ubmap.c so that they can be
* optionally included in the kernel at sysgen time. This saves
* kernel space if the processor does not have a unibus map.
*
* Functions:
*
* mapinit Initialize the unibus mapping registers.
* mapalloc Allocates the unibus map for an I/O transfer.
* mapfree Frees the map after the I/O transfer completes.
*
* Usage:
*
* Called by the kernel and device drivers.
*
* Compile:
*
* cd /usr/sys/sys; make -k
* cd /usr/sys/ovsys; make -k
* (cc -c -O ubmap.c)
*
* Modification history:
*
* June 1985
* Modified to use malloc/mfree for keeping track
* of the mapping registers. This also has changes
* for mapping out the clists. -Dave Borman
* 30 December 1984
* File Created -- Fred Canter
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/seg.h>
#include <sys/buf.h>
#include <sys/uba.h>
#include <sys/map.h>
memaddr bpaddr; /* physical address of buffers (in 64 byte clicks) */
struct map ub_map[12] = { MAPDATA(12) };
/*
* Initialize the ub_map, and some of the mapping registers.
* The first register maps the stuff between &ub_start and &ub_end.
* This includes things like uda, hp_bads, hk_bads, and
* TS (cmdpkt, chrbuf, mesbuf). If the clists aren't mapped out,
* cfree is also included in this. If the clists are mapped out,
* then the second unibus register maps them. We then allocate
* enough registers to map the buffers, and free up the rest.
*/
mapinit()
{
register int i, lastbuf_reg;
long paddr = (long)bpaddr << 6;
extern int nclist;
if(!ubmaps)
return;
setubregno(0, (long)&cfree);
#ifdef UCB_CLIST
setubregno(CLIST_UBADDR/UBPAGE, clstaddr);
#endif UCB_CLIST
lastbuf_reg = nubreg(nbuf, BSIZE) + BUF_UBADDR/UBPAGE;
for (i = BUF_UBADDR/UBPAGE; i < lastbuf_reg; i++) {
setubregno(i, paddr);
paddr += (long)UBPAGE;
}
mfree(ub_map, 31 - lastbuf_reg, lastbuf_reg);
}
/*
* Unibus map allocation routine
*
* Unibus Map Registers are allocated as follows:
*
* UMBR 31 is not used.
*
* Map register 0 maps the fisrt 8K bytes of BSS space, this covers
* NPR access to: UDA comm. area, hp_bads & hk_bads.
* Map register 1 maps to the clist area.
* Map registers 2 thru ? map the I/O buffer cache.
* The rest of the registers are available for mapping raw I/O transfers.
*/
int maplock;
mapalloc(bp)
register struct buf *bp;
{
long paddr, ubaddr;
int s, ub_nregs;
register int ub_first;
register struct ubmap *ubp;
if(!ubmaps)
return;
paddr = (((long) ((unsigned) bp->b_xmem)) << 16 )
| ((long) ((unsigned) bp->b_un.b_addr));
if ((bp->b_flags & B_PHYS) == 0) {
/*
* Transfer in the buffer cache.
* Change the buffers's physical address
* into a UNIBUS address for the driver.
*/
ubaddr = paddr - (((ubadr_t) bpaddr) << 6) + BUF_UBADDR;
bp->b_un.b_addr = loint(ubaddr);
bp->b_xmem = hiint(ubaddr);
bp->b_flags |= B_MAP;
} else {
ub_nregs = (int)btoub(bp->b_bcount);
s = spl6();
while ((ub_first = malloc(ub_map, ub_nregs)) == NULL) {
maplock = 1;
sleep((caddr_t)&ub_map, PSWP+1);
}
splx(s);
ubp = &UBMAP[ub_first];
bp->b_xmem = ub_first >> 3;
bp->b_un.b_addr = (ub_first & 07) << 13;
bp->b_flags |= B_MAP;
while (ub_nregs--) {
ubp->ub_lo = loint(paddr);
ubp->ub_hi = hiint(paddr);
ubp++;
paddr += (long)UBPAGE;
}
}
}
/*
* ub_alloc(paddr, count)
* Given a physical address and a byte count, ub_alloc
* maps the given memory onto the unibus and returns
* this unibus address in clicks.
*/
ub_alloc(paddr, count)
long paddr;
int count;
{
register int ub_first, ub_nregs;
register struct ubmap *ubp;
int s;
ub_nregs = (int)btoub(count);
s = spl6();
while ((ub_first = malloc(ub_map, ub_nregs)) == NULL) {
maplock = 1;
sleep((caddr_t)&ub_map, PSWP+1);
}
splx(s);
for (ubp = &UBMAP[ub_first]; ub_nregs--; ubp++) {
ubp->ub_lo = loint(paddr);
ubp->ub_hi = hiint(paddr);
paddr += (long)UBPAGE;
}
return(ub_first<<7);
}
#ifdef notused
/*
* ub_free(ubaddr, count)
* Given a unibus address (in clicks) and a byte count, ub_free()
* releases that segment of the unibus map and wakes up anyone
* waiting for the unibus map.
*/
ub_free(ubaddr, count)
unsigned ubaddr;
unsigned count;
{
register int s = spl6();
mfree(ub_map, (int) btoub(count),
ubaddr>>7);
splx(s);
if (maplock) {
wakeup((caddr_t)ub_map);
maplock = 0;
}
}
#endif notused
mapfree(bp)
register struct buf *bp;
{
register int s;
if (bp->b_flags & B_PHYS) {
s = spl6();
mfree(ub_map, (int) btoub(bp->b_bcount),
(bp->b_xmem << 3) | (((int)bp->b_un.b_addr >> 13) & 07));
splx(s);
bp->b_flags &= ~B_MAP;
if (maplock) {
wakeup((caddr_t)ub_map);
maplock = 0;
}
} else {
long ubaddr, paddr;
/*
* Translate the UNIBUS virtual address of this buffer
* back to a physical memory address.
*/
ubaddr = (((long) ((unsigned) bp->b_xmem)) << 16)
| ((long) ((unsigned) bp->b_un.b_addr));
paddr = ubaddr - (long) BUF_UBADDR + (((long) bpaddr) << 6);
bp->b_un.b_addr = loint(paddr);
bp->b_xmem = hiint(paddr);
bp->b_flags &= ~B_MAP;
}
}