⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vmeuniverse.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: vmeUniverse.c,v 1.1.4.4 2004/11/16 23:00:27 joel Exp $ *//* Routines to configure the VME interface * Author: Till Straumann <strauman@slac.stanford.edu> *         Nov 2000, Oct 2001, Jan 2002 */#include <stdio.h>#include <stdarg.h>#include "vmeUniverse.h"#define UNIV_NUM_MPORTS		8 /* number of master ports */#define UNIV_NUM_SPORTS		8 /* number of slave ports */#define PCI_VENDOR_TUNDRA	0x10e3#define PCI_DEVICE_UNIVERSEII	0#define PCI_UNIVERSE_BASE0	0x10#define PCI_UNIVERSE_BASE1	0x14#define UNIV_REGOFF_PCITGT0_CTRL 0x100#define UNIV_REGOFF_PCITGT4_CTRL 0x1a0#define UNIV_REGOFF_VMESLV0_CTRL 0xf00#define UNIV_REGOFF_VMESLV4_CTRL 0xf90#define UNIV_CTL_VAS16		(0x00000000)#define UNIV_CTL_VAS24		(0x00010000)#define UNIV_CTL_VAS32		(0x00020000)#define UNIV_CTL_VAS		(0x00070000)#define UNIV_MCTL_EN		(0x80000000)#define UNIV_MCTL_PWEN		(0x40000000)#define UNIV_MCTL_PGM		(0x00004000)#define UNIV_MCTL_VCT		(0x00000100)#define UNIV_MCTL_SUPER		(0x00001000)#define UNIV_MCTL_VDW32		(0x00800000)#define UNIV_MCTL_VDW64		(0x00c00000)#define UNIV_MCTL_AM_MASK	(UNIV_CTL_VAS | UNIV_MCTL_PGM | UNIV_MCTL_SUPER)#define UNIV_SCTL_EN		(0x80000000)#define UNIV_SCTL_PWEN		(0x40000000)#define UNIV_SCTL_PREN		(0x20000000)#define UNIV_SCTL_PGM		(0x00800000)#define UNIV_SCTL_DAT		(0x00400000)#define UNIV_SCTL_SUPER		(0x00200000)#define UNIV_SCTL_USER		(0x00100000)#define UNIV_SCTL_AM_MASK	(UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)/* we rely on a vxWorks definition here */#define VX_AM_SUP		4#ifdef __rtems__#include <stdlib.h>#include <rtems/bspIo.h>	/* printk */#include <bsp/pci.h>#include <bsp.h>/* allow the BSP to override the default routines */#ifndef BSP_PCI_FIND_DEVICE#define BSP_PCI_FIND_DEVICE		BSP_pciFindDevice#endif#ifndef BSP_PCI_CONFIG_IN_LONG#define BSP_PCI_CONFIG_IN_LONG	pci_read_config_dword#endif#ifndef BSP_PCI_CONFIG_IN_BYTE#define BSP_PCI_CONFIG_IN_BYTE	pci_read_config_byte#endiftypedef unsigned int pci_ulong;#define PCI_TO_LOCAL_ADDR(memaddr) \    ((pci_ulong)(memaddr) + PCI_MEM_BASE_ADJUSTMENT)#elif defined(__vxworks)typedef unsigned long pci_ulong;#define PCI_TO_LOCAL_ADDR(memaddr) (memaddr)#define BSP_PCI_FIND_DEVICE		pciFindDevice#define BSP_PCI_CONFIG_IN_LONG	pciConfigInLong#define BSP_PCI_CONFIG_IN_BYTE	pciConfigInByte#else#error "vmeUniverse not ported to this architecture yet"#endif#ifndef PCI_INTERRUPT_LINE#define PCI_INTERRUPT_LINE		0x3c#endifvolatile LERegister *vmeUniverse0BaseAddr=0;int vmeUniverse0PciIrqLine=-1;#if 0/* public access functions */volatile LERegister *vmeUniverseBaseAddr(void){	if (!vmeUniverse0BaseAddr) vmeUniverseInit();	return vmeUniverse0BaseAddr;}intvmeUniversePciIrqLine(void){	if (vmeUniverse0PciIrqLine<0) vmeUniverseInit();	return vmeUniverse0PciIrqLine;}#endifstatic inline voidWRITE_LE(	unsigned long val,	volatile LERegister    *adrs,	unsigned long off){#if (__LITTLE_ENDIAN__ == 1)	*(volatile unsigned long*)(((unsigned long)adrs)+off)=val;#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)	/* offset is in bytes and MUST not end up in r0 */	__asm__ __volatile__("stwbrx %1, %0, %2" :: "b"(off),"r"(val),"r"(adrs));#elif defined(__rtems__)	st_le32((volatile unsigned long*)(((unsigned long)adrs)+off), val);#else#error "little endian register writing not implemented"#endif}#if defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)#define SYNC __asm__ __volatile__("sync")#else#define SYNC#warning "SYNC instruction unknown for this architecture"#endif/* registers should be mapped to guarded, non-cached memory; hence  * subsequent stores are ordered. eieio is only needed to enforce * ordering of loads with respect to stores. */#define EIEIO_REGstatic inline unsigned longREAD_LE0(volatile LERegister *adrs){#if (__LITTLE_ENDIAN__ == 1)	return *(volatile unsigned long *)adrs;#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)register unsigned long rval;__asm__ __volatile__("lwbrx %0, 0, %1":"=r"(rval):"r"(adrs));	return rval;#elif defined(__rtems__)	return ld_le32((volatile unsigned long*)adrs);#else#error "little endian register reading not implemented"#endif}static inline unsigned longREAD_LE(volatile LERegister *adrs, unsigned long off){#if (__LITTLE_ENDIAN__ == 1)	return  *((volatile LERegister *)(((unsigned long)adrs)+off));#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1)register unsigned long rval;	/* offset is in bytes and MUST not end up in r0 */__asm__ __volatile__("lwbrx %0, %2, %1"				: "=r"(rval)				: "r"(adrs), "b"(off));#if 0__asm__ __volatile__("eieio");#endifreturn rval;#elsereturn READ_LE0((volatile LERegister *)(((unsigned long)adrs)+off));#endif}#define PORT_UNALIGNED(addr,port) \	( (port)%4 ? ((addr) & 0xffff) : ((addr) & 4095) ) #define UNIV_REV(base) (READ_LE(base,2*sizeof(LERegister)) & 0xff)	#if defined(__rtems__) && 0static intuprintk(char *fmt, va_list ap){int		rval;extern int k_vsprintf(char *, char *, va_list);/* during bsp init, there is no malloc and no stdio, * hence we assemble the message on the stack and revert * to printk */char	buf[200];	rval = k_vsprintf(buf,fmt,ap);	if (rval > sizeof(buf))			BSP_panic("vmeUniverse/uprintk: buffer overrun");	printk(buf);	return rval;}#endif/* private printing wrapper */static voiduprintf(FILE *f, char *fmt, ...){va_list	ap;	va_start(ap, fmt);#ifdef __rtems__	if (!f || !_impure_ptr->__sdidinit) {		/* Might be called at an early stage when		 * stdio is not yet initialized.		 * There is no vprintk, hence we must assemble		 * to a buffer.		 */		vprintk(fmt,ap);	} else #endif	{		vfprintf(f,fmt,ap);	}	va_end(ap);}intvmeUniverseFindPciBase(	int instance,	volatile LERegister **pbase	){int bus,dev,fun;pci_ulong busaddr;unsigned char irqline;	if (BSP_PCI_FIND_DEVICE(			PCI_VENDOR_TUNDRA,			PCI_DEVICE_UNIVERSEII,			instance,			&bus,			&dev,			&fun))		return -1;	if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE0,&busaddr))		return -1;	if ((unsigned long)(busaddr) & 1) {		/* it's IO space, try BASE1 */		if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE1,&busaddr)		   || ((unsigned long)(busaddr) & 1))			return -1;	}	*pbase=(volatile LERegister*)PCI_TO_LOCAL_ADDR(busaddr);	if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))		return -1;	else		vmeUniverse0PciIrqLine = irqline;	return 0;}/* convert an address space selector to a corresponding * universe control mode word */static intam2mode(int ismaster, unsigned long address_space, unsigned long *pmode){unsigned long mode=0;	if (!ismaster) {		mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM;		mode |= UNIV_SCTL_USER;	}	switch (address_space) {		case VME_AM_STD_SUP_PGM:		case VME_AM_STD_USR_PGM:			if (ismaster)				mode |= UNIV_MCTL_PGM ;			else {				mode &= ~UNIV_SCTL_DAT;			}			/* fall thru */		case VME_AM_STD_SUP_DATA:		case VME_AM_STD_USR_DATA:			mode |= UNIV_CTL_VAS24;			break;		case VME_AM_EXT_SUP_PGM:		case VME_AM_EXT_USR_PGM:			if (ismaster)				mode |= UNIV_MCTL_PGM ;			else {				mode &= ~UNIV_SCTL_DAT;			}			/* fall thru */		case VME_AM_EXT_SUP_DATA:		case VME_AM_EXT_USR_DATA:			mode |= UNIV_CTL_VAS32;			break;		case VME_AM_SUP_SHORT_IO:		case VME_AM_USR_SHORT_IO:			mode |= UNIV_CTL_VAS16;			break;		case 0: /* disable the port alltogether */			break;		default:			return -1;	}	if (address_space & VX_AM_SUP)		mode |= (ismaster ? UNIV_MCTL_SUPER : UNIV_SCTL_SUPER);	*pmode = mode;	return 0;}static intdisableUniversePort(int ismaster, int portno, volatile unsigned long *preg, void *param){unsigned long cntrl;	cntrl=READ_LE0(preg);	cntrl &= ~(ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN);	WRITE_LE(cntrl,preg,0);	SYNC; /* make sure this command completed */	return 0;}static intcfgUniversePort(	unsigned long	ismaster,	unsigned long	port,	unsigned long	address_space,	unsigned long	vme_address,	unsigned long	local_address,	unsigned long	length){#define base vmeUniverse0BaseAddrvolatile LERegister *preg;unsigned long	p=port;unsigned long	mode=0;	/* check parameters */	if (port >= (ismaster ? UNIV_NUM_MPORTS : UNIV_NUM_SPORTS)) {		uprintf(stderr,"invalid port\n");		return -1;	}	/* port start, bound addresses and offset must lie on 64k boundary	 * (4k for port 0 and 4)	 */	if ( PORT_UNALIGNED(local_address,port) ) {		uprintf(stderr,"local address misaligned\n");		return -1;	}	if ( PORT_UNALIGNED(vme_address,port) ) {		uprintf(stderr,"vme address misaligned\n");		return -1;	}	if ( PORT_UNALIGNED(length,port) ) {		uprintf(stderr,"length misaligned\n");		return -1;	}	/* check address space validity */	if (am2mode(ismaster,address_space,&mode)) {		uprintf(stderr,"invalid address space\n");		return -1;	}	/* get the universe base address */	if (!base && vmeUniverseInit()) {		return -1;	}	preg=base;	/* find out if we have a rev. II chip */	if ( UNIV_REV(base) < 2 ) {		if (port>3) {			uprintf(stderr,"Universe rev. < 2 has only 4 ports\n");			return -1;		}	}	/* finally, configure the port */	/* find the register set for our port */	if (port<4) {		preg += (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister);	} else {		preg += (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister);		p-=4;	}	preg += 5 * p;	/* temporarily disable the port */	disableUniversePort(ismaster,port,preg,0);	/* address_space == 0 means disable */	if (address_space != 0) {		unsigned long start,offst;		/* set the port starting address;		 * this is the local address for the master		 * and the VME address for the slave		 */		if (ismaster) {			start=local_address;			/* let it overflow / wrap around 0 */			offst=vme_address-local_address;		} else {			start=vme_address;			/* let it overflow / wrap around 0 */			offst=local_address-vme_address;		}#undef TSILL#ifdef TSILL		uprintf(stderr,"writing 0x%08x to 0x%08x + 4\n",start,preg);#else		WRITE_LE(start,preg,4);#endif		/* set bound address */		length+=start;#ifdef TSILL		uprintf(stderr,"writing 0x%08x to 0x%08x + 8\n",length,preg);#else		WRITE_LE(length,preg,8);#endif		/* set offset */#ifdef TSILL		uprintf(stderr,"writing 0x%08x to 0x%08x + 12\n",offst,preg);#else		WRITE_LE(offst,preg,12);#endif		/* calculate configuration word and enable the port */		/* NOTE: reading the CY961 (Echotek ECDR814) with VDW32		 *       generated bus errors when reading 32-bit words                 *       - very weird, because the registers are 16-bit                 *         AFAIK.		 *       - 32-bit accesses worked fine on vxWorks which                 *         has the port set to 64-bit.                 *       ????????                 */		if (ismaster)			mode |= UNIV_MCTL_EN | UNIV_MCTL_PWEN | UNIV_MCTL_VDW64 | UNIV_MCTL_VCT;		else 			mode |= UNIV_SCTL_EN | UNIV_SCTL_PWEN | UNIV_SCTL_PREN;#ifdef TSILL		uprintf(stderr,"writing 0x%08x to 0x%08x + 0\n",mode,preg);#else		EIEIO_REG;	/* make sure mode is written last */		WRITE_LE(mode,preg,0);		SYNC;		/* enforce completion */#endif#ifdef TSILL		uprintf(stderr,			"universe %s port %lu successfully configured\n",				ismaster ? "master" : "slave",				port);#endif#ifdef __vxworks		if (ismaster)			uprintf(stderr,			"WARNING: on the synergy, sysMasterPortsShow() may show incorrect settings (it uses cached values)\n");#endif	}	return 0;#undef base}static intshowUniversePort(		int		ismaster,		int		portno,		volatile LERegister *preg,		void		*parm){	FILE *f=parm ? (FILE *)parm : stdout;	unsigned long cntrl, start, bound, offst, mask;	cntrl = READ_LE0(preg++);#undef TSILL#ifdef TSILL	uprintf(stderr,"showUniversePort: *(0x%08x): 0x%08x\n",preg-1,cntrl);#endif#undef TSILL	/* skip this port if disabled */	if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN)))		return 0;	/* for the master `start' is the PCI address,	 * for the slave  `start' is the VME address	 */	mask = ~PORT_UNALIGNED(0xffffffff,portno);	start = READ_LE0(preg++)&mask;	bound = READ_LE0(preg++)&mask;	offst = READ_LE0(preg++)&mask;	offst+=start; /* calc start on the other bus */	if (ismaster) {		uprintf(f,"%d:    0x%08lx 0x%08lx 0x%08lx ",			portno,offst,bound-start,start);	} else {		uprintf(f,"%d:    0x%08lx 0x%08lx 0x%08lx ",			portno,start,bound-start,offst);	}	switch (cntrl & UNIV_CTL_VAS) {		case UNIV_CTL_VAS16: uprintf(f,"A16, "); break;		case UNIV_CTL_VAS24: uprintf(f,"A24, "); break;		case UNIV_CTL_VAS32: uprintf(f,"A32, "); break;		default: uprintf(f,"A??, "); break;	}	if (ismaster) {		uprintf(f,"%s, %s",			cntrl&UNIV_MCTL_PGM ?   "Pgm" : "Dat",			cntrl&UNIV_MCTL_SUPER ? "Sup" : "Usr");	} else {		uprintf(f,"%s %s %s %s", 			cntrl&UNIV_SCTL_PGM ?   "Pgm," : "    ",			cntrl&UNIV_SCTL_DAT ?   "Dat," : "    ",			cntrl&UNIV_SCTL_SUPER ? "Sup," : "    ",			cntrl&UNIV_SCTL_USER  ? "Usr" :  "");	}	uprintf(f,"\n");	return 0;}typedef struct XlatRec_ {	unsigned long	address;	unsigned long	aspace;	unsigned 		reverse; /* find reverse mapping of this port */} XlatRec, *Xlat;/* try to translate an address through the bridge * * IN:  l->address, l->aspace * OUT: l->address (translated address) * * RETURNS: -1: invalid space *           0: invalid address (not found in range) *           1: success */static intxlatePort(int ismaster, int port, volatile LERegister *preg, void *parm){Xlat	l=(Xlat)parm;unsigned long cntrl, start, bound, offst, mask, x;	cntrl = READ_LE0(preg++);	/* skip this port if disabled */	if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN)))		return 0;	/* check for correct address space */	if ( am2mode(ismaster,l->aspace,&offst) ) {		uprintf(stderr,"vmeUniverse WARNING: invalid adressing mode 0x%x\n",		               l->aspace);		return -1;	}	if ( (cntrl & (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK))	    != offst )		return 0; /* mode doesn't match requested AM */	/* OK, we found a matching mode, now we must check the address range */	mask = ~PORT_UNALIGNED(0xffffffff,port);	/* for the master `start' is the PCI address,	 * for the slave  `start' is the VME address	 */	start = READ_LE0(preg++) & mask;	bound = READ_LE0(preg++) & mask;	offst = READ_LE0(preg++) & mask;	/* translate address to the other bus */	if (l->reverse) {		/* reverse mapping, i.e. for master ports we map from		 * VME to PCI, for slave ports we map from VME to PCI		 */		if (l->address >= start && l->address < bound) {				l->address+=offst;				return 1;		}	} else {		x = l->address - offst;		if (x >= start && x < bound) {			/* valid address found */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -