File:  [MW Coherent from dump] / coherent / b / kernel / i386 / fakedma.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * these routines are written in C until the 386 compiler/assembler
 * are available
 *
 * Copyright (c) Ciaran O'Donnell, Bievres (FRANCE), 1991
 */

#include <sys/coherent.h>
#include <sys/reg.h>
#include <sys/clist.h>
#include <errno.h>
#include <sys/inode.h>
#include <sys/proc.h>
#include <sys/seg.h>
#include <signal.h>
#include <sys/uproc.h>
#include <sys/buf.h>

#define	min(a, b)	((a) < (b) ? (a) : (b))

/*
 * dmacopy()
 *
 * Copy "npage" 4 kbyte pages from phys addr "from" to phys addr "to".
 */
dmacopy(npage, from, to) 
long	npage;
cseg_t	*from, *to;
{
	int save = setspace(SEG_386_KD);

	while (npage--) {
		int work = workAlloc();	/* Get a virtual click pair. */
		ptable1_v[work] = *from++ | SEG_SRW;
		ptable1_v[work + 1] = *to++ | SEG_SRW;
		mmuupd();
		copyseg_d(NBPC, ctob(work), ctob(work + 1));
		workFree(work);
	}
	setspace(save);
}

/*
 * dmaclear()
 *
 * Given a byte count, a system global address, and a fill value,
 * write the fill value through the given range of memory.
 */
dmaclear(nbytes, to, fill)
long	nbytes, fill;
paddr_t	to;
{
	unsigned off;
	int	n;
	cseg_t *base;
	int save = setspace(SEG_386_KD);
	int work = workAlloc();	/* Get a virtual click pair. */

	off = to & (NBPC-1);
	base = &sysmem.u.pbase[btocrd(to)];
	n = min(nbytes, NBPC-off);
	ptable1_v[work] = *base++ | SEG_SRW;
	mmuupd();
	
	clearseg_d(n, ctob(work)+off, fill);
	nbytes -= n;

	while (nbytes >= NBPC) {
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
		clearseg_d(NBPC, ctob(work), fill);
		nbytes -= NBPC;
	}

	if (nbytes) {
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
		clearseg_d(nbytes, ctob(work), fill);
	}
	setspace(save);
	workFree(work);
}

/*
 * dmain()
 * 
 * Copy in "nbytes" from system global address "to" to kernel address
 * "vaddr".
 */
dmain(nbytes, to, vaddr)
long	nbytes;
paddr_t	to;
caddr_t	vaddr;
{
	unsigned off;
	unsigned	n, n1;
	cseg_t* base;
	int work = workAlloc();	/* Get a virtual click pair. */
	int save = setspace(SEG_386_KD);

	off = to & (NBPC-1);
	base = &sysmem.u.pbase[btocrd(to)];

	n = min(nbytes, NBPC-off);
	ptable1_v[work] = *base++ | SEG_SRW;
	mmuupd();

	if (nbytes==n) {
		/*
		 * only one page
		 * n = min(n & (sizeof(long)-1), n)
		 * copy n bytes; nbytes -= n;
		 * copy (nbytes >> 2) long words; nbytes &= sizeof(long)-1
		 * copy nbytes bytes
		 */
		if (n >= sizeof(long))
			n &= sizeof(long)-1;
		if (n)
			copyseg_b(n, ctob(work)+off, vaddr);
		off += n;
		vaddr += n;
		nbytes -= n;
		if (n = nbytes & ~(sizeof(long)-1)) {
			copyseg_d(n, ctob(work)+off, vaddr);
			off += n;
			vaddr += n;
			nbytes -= n;
		}
	} else {
		/*
		 * more than one page
		 * copy n&3 bytes
		 * copy n >> 2 long words
		 * in the first page
		 */			
		if (n1 = n & 3)
			copyseg_b(n1, ctob(work)+off, vaddr);
		off += n1;
		vaddr += n1;
		nbytes -= n1;
		if (n = n & ~(sizeof(long)-1)) {
			copyseg_d(n, ctob(work)+off, vaddr);
			off += n;
			vaddr += n;
			nbytes -= n;
		}

		/*
		 * copy nbytes>>BPCSHIFT full pages
		 */
		while (nbytes >= NBPC) {
			ptable1_v[work] = *base++ | SEG_SRW;
			mmuupd();
	
			copyseg_d(NBPC, ctob(work), vaddr);
			vaddr += NBPC;
			nbytes -= NBPC;
		}
		/*
		 * page n-1 (last one)
		 *
		 * copy nbytes>>2 long words
		 * copy nbytes & 3 bytes
		 */
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
	
		if (n = nbytes & ~(sizeof(long)-1)) {
			copyseg_d(n, ctob(work), vaddr);
			vaddr += n;
			nbytes -= n;
		}
		if (nbytes)
			copyseg_b(nbytes, ctob(work)+n, vaddr);
	}

	setspace(save);
	workFree(work);
}

/*
 * dmaout()
 * 
 * Copy out "nbytes" from kernel address "vaddr" to system global address
 * "to".
 */
dmaout(nbytes, to, vaddr)
long	nbytes;
paddr_t	to;
caddr_t	vaddr;
{
	unsigned off;
	unsigned	n, n1;
	cseg_t *base;
	int work = workAlloc();	/* Get a virtual click pair. */
	int save = setspace(SEG_386_KD);

	off = to & (NBPC-1);
	base = &sysmem.u.pbase[btocrd(to)];

	n = min(nbytes, NBPC-off);
	ptable1_v[work] = *base++ | SEG_SRW;
	mmuupd();

	if (nbytes==n) {
		/*
		 * only one page
		 * n = min(n & (sizeof(long)-1), n)
		 * copy n bytes; nbytes -= n;
		 * copy (nbytes >> 2) long words; nbytes &= sizeof(long)-1
		 * copy nbytes bytes
		 */
		if (n1 = n & (sizeof(long)-1))
			copyseg_b(n1, vaddr, ctob(work)+off);
		off += n1;
		vaddr += n1;
		nbytes -= n1;
		if (n = nbytes & ~(sizeof(long)-1)) {
			copyseg_d(n, vaddr, ctob(work)+off);
			off += n;
			vaddr += n;
			nbytes -= n;
		}
	} else {
		/*
		 * more than one page
		 * copy n&3 bytes
		 * copy n >> 2 long words
		 * in the first page
		 */			
		if (n1 = n & (sizeof(long)-1))
			copyseg_b(n1, vaddr, ctob(work)+off);
		off += n1;
		vaddr += n1;
		nbytes -= n1;
		if (n = n & ~(sizeof(long)-1)) {
			copyseg_d(n, vaddr, ctob(work)+off);
			off += n;
			vaddr += n;
			nbytes -= n;
		}

		/*
		 * copy nbytes>>BPCSHIFT full pages
		 */
		while (nbytes >= NBPC) {
			ptable1_v[work] = *base++ | SEG_SRW;
			mmuupd();
			copyseg_d(NBPC, vaddr, ctob(work));
			vaddr += NBPC;
			nbytes -= NBPC;
		}

		/* now the transfer to memory is click-aligned */
		off = 0;

		/*
		 * page n-1 (last one)
		 *
		 * copy nbytes>>2 long words
		 * copy nbytes & 3 bytes
		 */
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
	
		if (n = nbytes & ~(sizeof(long)-1)) {
			copyseg_d(n, vaddr, ctob(work));
			vaddr += n;
			off += n;
			nbytes -= n;
		}
		if (nbytes)
			copyseg_b(nbytes, vaddr, ctob(work)+off);
	}

	setspace(save);
	workFree(work);
}

/*
 * dmaio2()
 * 
 * Copy in "nbytes" from an I/O port "port" to the system global address
 * "to".
 */
dmaio2(nbytes, to, port)
long	nbytes, port;
paddr_t	to;
{
	unsigned off;
	int	n;
	cseg_t *base;
	int save = setspace(SEG_386_KD);
	int work = workAlloc();	/* Get a virtual click pair. */

	off = to & (NBPC-1);
	base = &sysmem.u.pbase[btocrd(to)];

	n = min(nbytes, NBPC-off);
	ptable1_v[work] = *base++ | SEG_SRW;
	mmuupd();
	
	io2seg(n, ctob(work)+off, port);
	nbytes -= n;

	while (nbytes >= NBPC) {
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
		io2seg(NBPC, ctob(work), port);
		nbytes -= NBPC;
	}

	if (nbytes) {
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
		io2seg(nbytes, ctob(work), port);
	}
	setspace(save);
	workFree(work);
}

/*
 * dma2io()
 * 
 * Copy out "nbytes" from the system global address "from" to an I/O port
 * "port".
 */
dma2io(nbytes, to, port)
long	nbytes, port;
paddr_t	to;
{
	unsigned off;
	int	n;
	cseg_t *base;
	int save = setspace(SEG_386_KD);
	int work = workAlloc();	/* Get a virtual click pair. */

	off = to & (NBPC-1);
	base = &sysmem.u.pbase[btocrd(to)];

	n = min(nbytes, NBPC-off);
	ptable1_v[work] = *base++ | SEG_SRW;
	mmuupd();
	
	seg2io(n, ctob(work)+off, port);
	nbytes -= n;

	while (nbytes >= NBPC) {
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
		seg2io(NBPC, ctob(work), port);
		nbytes -= NBPC;
	}

	if (nbytes) {
		ptable1_v[work] = *base++ | SEG_SRW;
		mmuupd();
		seg2io(nbytes, ctob(work), port);
	}
	setspace(save);
	workFree(work);
}

/*
 * pxcopy()
 *
 * copy "n" bytes of data at kernel address "v" from address "uo" in:
 * 	system global address space		(space&SEG_VIRT)
 * 	physical memory				!(space&SEG_VIRT)
 * Rights are determined by (space&~SEG_VIRT):
 * 	"v" can be anywhere in kernel address space	SEG_386_KD
 * 	"v" must be an address accessible to the user	SEG_386_UD
 * Up to one click of data can be copied. No alignment restrictions
 * on "uo" apply.
 */
pxcopy(uo, v, n, space)
unsigned	uo;
char	*v;
register int n;
{
	cseg_t *base;
	register	int save, err;
	int work;

	if (n > NBPC)
		return 0;

	work = workAlloc();
	if (space & SEG_VIRT) {
		space &= ~SEG_VIRT;
		base = &sysmem.u.pbase[btocrd(uo)];
		ptable1_v[work] = *base++ | SEG_SRW;
		ptable1_v[work + 1] = *base++ | SEG_SRW;
	} else {
		ptable1_v[work] = (uo&~(NBPC-1)) + SEG_SRW;
		ptable1_v[work + 1] = (uo&~(NBPC-1)) + NBPC + SEG_SRW;
	}
	mmuupd();
	save = setspace(space);

	err = ukcopy(ctob(work) + (uo&(NBPC-1)), v, n);
	setspace(save);
	workFree(work);
	return err;
}

/*
 * xpcopy()
 * 
 * copy "n" bytes of data from kernel address "v" to address "uo" in:
 *      system global address space                      (space&SEG_VIRT)
 *      physical memory                                 !(space&SEG_VIRT)
 * Rights are determined by (space&~SEG_VIRT):
 *      "v" can be anywhere in kernel address space      SEG_386_KD
 *      "v" must be an address accessible to the user    SEG_386_UD
 * Up to one click of data can be copied. No alignment restrictions on "uo"
 * apply.
 */
xpcopy(v, uo, n, space)
char	*v;
unsigned uo;
register int n;
{
	register cseg_t *base;
	register	int save, err;
	int work;

	if (n > NBPC)
		return 0;

	work = workAlloc();
	if (space & SEG_VIRT) {
		space &= ~SEG_VIRT;
		base = &sysmem.u.pbase[btocrd(uo)];
		ptable1_v[work] = *base++ | SEG_SRW;
		ptable1_v[work + 1] = *base++ | SEG_SRW;
	} else {
		ptable1_v[work] = (uo&~(NBPC-1)) + SEG_SRW;
		ptable1_v[work + 1] = (uo&~(NBPC-1)) + NBPC + SEG_SRW;
	}
	mmuupd();
	save = setspace(space);

	err = kucopy(v, ctob(work) + (uo&(NBPC-1)), n);
	setspace(save);
	workFree(work);
	return err;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.