Coherent4.2.10/i386/ff.c

/* $Header: /ker/i386/RCS/ff.c,v 2.4 93/10/29 00:56:45 nigel Exp Locker: nigel $ */
/*
 * Simulate all the calls for far memory access from COH 286.
 * Far pointers are simulated with virtual addresses.
 *
 * Add __ptov() for debugging.  94/02/19.  hal
 *
 * $Log:	ff.c,v $
 * Revision 2.4  93/10/29  00:56:45  nigel
 * R98 (aka 4.2 Beta) prior to removing System Global memory
 * 
 * Revision 2.3  93/08/19  03:40:03  nigel
 * Nigel's R83
 * 
 */

#include <sys/types.h>

#define	_KERNEL		1

#include <kernel/fakeff.h>
#include <kernel/reg.h>
#include <sys/mmu.h>
#include <sys/seg.h>
#include <sys/cmn_err.h>

MAKESR(allocp, _allocp);

/*
 * P2P used to do the following as a macro but it is feeding a bad
 * physical address to __PTOV() so here is a diagnostic version.
 * Convert system global address to physical address.
 */
#if	__USE_PROTO__
__paddr_t __sg_to_p(__sg_addr_t sys_gl)
#else
__paddr_t
__sg_to_p(sys_gl)
__sg_addr_t	sys_gl;
#endif
{
	__paddr_t	retval;

	retval = ((sysmem.u.pbase[btocrd(sys_gl)]&~(NBPC-1))
	  |(sys_gl&(NBPC-1)));

	/* Range check the result. */
	if (retval >= (__paddr_t) __PHYSICAL_MAP_LEN) {
		cmn_err(CE_WARN, "P2P(%x) ", sys_gl);
		backtrace();
	}

	return retval;
}

/*
 * __PTOV used to do the following as a macro but the -1 return is just
 * a time bomb for the kernel, so the following is a first step at tracking
 * down the problem.
 */
#if	__USE_PROTO__
__caddr_t __ptov(__paddr_t phys)
#else
__caddr_t
__ptov(phys)
__paddr_t	phys;
#endif
{
	if (phys < (__paddr_t) __PHYSICAL_MAP_LEN)
		return (__caddr_t) (phys) + __PHYSICAL_MAP_BASE;
	else {
		cmn_err(CE_WARN, "__PTOV(%x) ", phys);
		backtrace();
		return (__caddr_t) -1;
	}
}

/*
 * Initialize a virtual address to access physical memory at location
 * 'paddr', of size 'len' bytes.  It provides read and write (but not
 * execute) access.  When no longer required, a virtual address should be
 * released by vrelse.
 *
 * 486 CPU's need PCD bit set to 1 since this routine will typically
 * be used by a driver to reserve virtual space for memory mapped i/o.
 */

faddr_t
map_pv(paddr, len)
__paddr_t paddr;
fsize_t len;
{
	int s;			/* Return value of sphi().  */
	int npage;		/* Number of pages we must allocate.  */
	faddr_t	chunk_start;	/* Start of allocated segment in vmem.  */
	faddr_t retval;		/* Address of desired physical memory in vmem.  */
	int base1;		/* Offset into ptable1_v[].  */
	cseg_t	pte;		/* Build page table entries here.  */

	/* Figure out how many clicks we need to map.
	 *	   [		    ]		What we want.
	 *	[	|	|	]	What we get.
	 * Total number of clicks is:
	 *	(click up from (paddr+len)) - (click down from paddr)
	 */
		
	npage = btocru (paddr + len) - btocrd (paddr);

	/* Note that sysmem.vaddre is ALWAYS click aligned.  */
	
	/*
	 * Allocate the required chunk of virtual memory space.
	 * This could be a lot more sophisticated.  For expedience,
	 * there is no way to free this after it has been allocated,
	 * and there are no checks to see if we ran out of virtual space.
	 */

	s = sphi ();
	chunk_start = (faddr_t) sysmem.vaddre;
	sysmem.vaddre += ctob (npage);
	spl (s);

	/*
	 * Figure out where the desired physical address ends up in vmem.
	 */

	retval = chunk_start + (paddr - ctob (btocru (paddr)));
	
	/*
	 * Load the page table.
	 */

	base1 = btocrd (chunk_start);
	pte = ctob (btocrd (paddr));
	do {
		ptable1_v [base1] = pte | SEG_SRW | SEG_PCD;
		base1 ++;
		pte += ctob (1);	/* Bump up to next physical click.  */
	} while (-- npage > 0);
	mmuupd ();	/* Tell the mmu about the new map.  */

	return retval;
}


/*
 * Release a virtual address that we previously obtained with function
 * map_pv().
 */
void
unmap_pv(faddr)
faddr_t faddr;
{
	/* For the moment, this function does nothing.  */
}		


/*
 * Translate virtual address to physical address.
 * Returns the current physical address associated with virtual address 'vaddr'.
 * Returns 0 if that portion of virtual address space is not associated with
 * any physical memory.
 */

__paddr_t
__coh_vtop (vaddr)
__caddr_t vaddr;
{
	paddr_t	retval;
	unsigned int ptable_idx;	/* Index into ptable1_v[].  */

	ptable_idx = btocrd (vaddr);

	/*
	 * There is a 4Mbyte virtual page table ptable1_v[] which is
	 * all the bottom level page tables appended into a big array.
	 * Note that there are huge holes in this data structure, for
	 * unmapped virtual address space.
	 *
	 * We are going to look up 'vaddr' in the virtual page table
	 * ptable1_v[].
	 *
	 * But first, we have to see if the portion of page table we are
	 * going to look at exists.  We do this by looking at the one click
	 * long page table that maps the virtual page table, PPTABLE1_V[].
	 */

	retval = 0;	/* Assume entry not found.  */

	if (ptable0_v [btosrd (vaddr)] & SEG_SRO) {
		/*
		 * ASSERTION:  The portion of ptable1_v[] we want is valid.
		 */
		if (ptable1_v [ptable_idx] & SEG_SRO) {

			/*
			 * ASSERTION:  'vaddr' corresponds to some
			 * physical memory.
			 *
			 * Note that the address of a physical click is
			 * all above bit 11 in the PTE.
			 */
			retval = (ptable1_v[ptable_idx] & ~(NBPC - 1));
			retval += ((long) vaddr & (NBPC - 1));
		}
	}

	return retval;
}


/*
 * Translate system global address 'vpaddr' to physical address.
 *
 * May cause a panic if 'vpaddr' does not correspond to a real physical
 * address.
 */

paddr_t
vptop(vpaddr)
paddr_t vpaddr;
{
	paddr_t	retval;
	cseg_t pte;	/* Page table entry from sysmem.u.pbase[].  */

	pte = sysmem.u.pbase [btocrd (vpaddr)];
	pte &= ~ (NBPC - 1);	/* Strip off the non-address information.  */

	retval = pte | (vpaddr & (NBPC - 1));

	return retval;
}


/*
 * Convert from virtual address to system global address.  Similar to MAPIO(),
 * but does not require separate segment and offset.
 *
 * Only works for Kernel Space virtual addresses.
 */

paddr_t
vtovp(vaddr)
__caddr_t vaddr;
{
	return MAPIO (allocp.sr_segp->s_vmem, vaddr - allocp.sr_base);
}