eni.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 667 行

C
667
字号
/* * * =================================== * HARP  |  Host ATM Research Platform * =================================== * * * This Host ATM Research Platform ("HARP") file (the "Software") is * made available by Network Computing Services, Inc. ("NetworkCS") * "AS IS".  NetworkCS does not provide maintenance, improvements or * support of any kind. * * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. * In no event shall NetworkCS be responsible for any damages, including * but not limited to consequential damages, arising from or relating to * any use of the Software or related support. * * Copyright 1994-1998 Network Computing Services, Inc. * * Copies of this Software may be made, however, the above copyright * notice must be reproduced on all copies. * *	@(#) $Id: eni.c,v 1.5 1998/12/14 06:37:01 dillon Exp $ * *//* * Efficient ENI adapter support * ----------------------------- * * Module supports PCI interface to ENI adapter * */#include <netatm/kern_include.h>#include <dev/hea/eni_stats.h>#include <dev/hea/eni.h>#include <dev/hea/eni_var.h>#ifndef	lint__RCSID("@(#) $Id: eni.c,v 1.5 1998/12/14 06:37:01 dillon Exp $");#endif/* * Typedef local functions */static const char	*eni_pci_probe __P((pcici_t, pcidi_t));static void	eni_pci_attach __P((pcici_t, int));static int 	eni_get_ack __P((Eni_unit *));static int	eni_get_sebyte __P((Eni_unit *));static void	eni_read_seeprom __P((Eni_unit *));#ifdef	__FreeBSD__#if BSD < 199506static int	eni_pci_shutdown __P((struct kern_devconf *, int));#elsestatic void	eni_pci_shutdown __P((int, void *));#endifstatic void	eni_pci_reset __P((Eni_unit *));#endif	/* __FreeBSD__ *//* * Used by kernel to return number of claimed devices */#ifdef	__FreeBSD__static u_long eni_nunits;static struct pci_device eni_pci_device = {	ENI_DEV_NAME,	eni_pci_probe,	eni_pci_attach,	&eni_nunits,#if BSD < 199506	eni_pci_shutdown#else	NULL#endif};DATA_SET ( pcidevice_set, eni_pci_device );#endif	/* __FreeBSD__ *//* * Called by kernel with PCI device_id which was read from the PCI * register set. If the identified vendor is Efficient, see if we * recognize the particular device. If so, return an identifying string, * if not, return null. * * Arguments: *	config_id	PCI config token *	device_id	contents of PCI device ID register * * Returns: *	string		Identifying string if we will handle this device *	NULL		unrecognized vendor/device * */static const char *eni_pci_probe ( pcici_t config_id, pcidi_t device_id ){	if ( (device_id & 0xFFFF) == EFF_VENDOR_ID ) {		switch ( (device_id >> 16) ) {			case EFF_DEV_ID:				return ( "Efficient ENI ATM Adapter" );/* NOTREACHED */				break;		}	}	return ( NULL );}/* * The ENI-155p adapter uses an ATMEL AT24C01 serial EEPROM to store * configuration information. The SEEPROM is accessed via two wires, * CLOCK and DATA, which are accessible via the PCI configuration * registers. The following macros manipulate the lines to access the * SEEPROM. See http://www.atmel.com/atmel/products/prod162.htm for * a description of the AT24C01 part. Value to be read/written is * part of the per unit structure. *//* * Write bits to SEEPROM */#define	WRITE_SEEPROM()	(						\    {									\	(void) pci_conf_write ( eup->eu_pcitag, SEEPROM,		\		eup->eu_sevar );					\	DELAY(SEPROM_DELAY);						\    }									\)/* * Stobe first the DATA, then the CLK lines high */#define	STROBE_HIGH()	(						\    {									\	eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM();			\	eup->eu_sevar |= SEPROM_CLK;  WRITE_SEEPROM();			\    }									\)/* * Strobe first the CLK, then the DATA lines high */#define	INV_STROBE_HIGH()	(					\    {									\	eup->eu_sevar |= SEPROM_CLK;  WRITE_SEEPROM();			\	eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM();			\    }									\)/* * Strobe first the CLK, then the DATA lines low - companion to * STROBE_HIGH() */#define	STROBE_LOW()	(						\    {									\	eup->eu_sevar &= ~SEPROM_CLK;  WRITE_SEEPROM();			\	eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM();			\    }									\)/* * Strobe first the DATA, then the CLK lines low - companion to * INV_STROBE_HIGH() */#define	INV_STROBE_LOW()	(					\    {									\	eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM();			\	eup->eu_sevar &= ~SEPROM_CLK;  WRITE_SEEPROM();			\    }									\)/* * Strobe the CLK line high, then low */#define	STROBE_CLK()	(						\    {									\	eup->eu_sevar |= SEPROM_CLK;   WRITE_SEEPROM();			\	eup->eu_sevar &= ~SEPROM_CLK;  WRITE_SEEPROM();			\    }									\)/* * Look for a positive ACK from the SEEPROM. Cycle begins by asserting * the DATA line, then the CLK line. The DATA line is then read to * retrieve the ACK status, and then the cycle is finished by deasserting * the CLK line, and asserting the DATA line. * * Arguments: *	eup		pointer to per unit structure * * Returns: *	0/1		value of ACK * */static inteni_get_ack ( eup )	Eni_unit	*eup;{	int		ack;	STROBE_HIGH();	/*	 * Read DATA line from SEPROM	 */	eup->eu_sevar = pci_conf_read ( eup->eu_pcitag, SEEPROM );	DELAY ( SEPROM_DELAY );	ack = eup->eu_sevar & SEPROM_DATA;	eup->eu_sevar &= ~SEPROM_CLK;	WRITE_SEEPROM ();	eup->eu_sevar |= SEPROM_DATA;	WRITE_SEEPROM ();	return ( ack );}/* * Read a byte from the SEEPROM. Data is read as 8 bits. There are two types * of read operations. The first is a single byte read, the second is * multiple sequential bytes read. Both cycles begin with a 'START' operation, * followed by a memory address word. Following the memory address, the * SEEPROM will send a data byte, followed by an ACK. If the host responds * with a 'STOP' operation, then a single byte cycle is performed. If the * host responds with an 'ACK', then the memory address is incremented, and * the next sequential memory byte is serialized. * * Arguments: *	eup		pointer to per unit structure * * Returns: *	val		value of byte read from SEEPROM * */static inteni_get_sebyte( eup )	Eni_unit	*eup;{	int	i;	int	data;	int	rval;	/* Initial value */	rval = 0;	/* Read 8 bits */	for ( i = 0; i < 8; i++ ) {		/* Shift bits to left so the next bit goes to position 0 */		rval <<= 1;		/* Indicate we're ready to read bit */		STROBE_HIGH();		/*		 * Read DATA line from SEPROM		 */		data = pci_conf_read ( eup->eu_pcitag, SEEPROM );		DELAY ( SEPROM_DELAY );		/* (Possibly) mask bit into accumulating value */		if ( data & SEPROM_DATA )			rval |= 1;		/* If DATA bit '1' */		/* Indicate we're done reading this bit */		STROBE_LOW();	}	/* Return acquired byte */	return ( rval );}/* * The AT24C01 is a 1024 bit part organized as 128 words by 8 bits. * We will read the entire contents into the per unit structure. Later, * we'll retrieve the MAC address and serial number from the data read. * * Arguments: *	eup		pointer to per unit structure * * Returns: *	none * */static voideni_read_seeprom ( eup )	Eni_unit	*eup;{	int	addr;	int	i, j;	/*	 * Set initial state	 */	eup->eu_sevar = SEPROM_DATA | SEPROM_CLK;	WRITE_SEEPROM ();	/* Loop for all bytes */	for ( i = 0; i < SEPROM_SIZE ; i++ ) {		/* Send START operation */		STROBE_HIGH();		INV_STROBE_LOW();		/*		 * Send address. Addresses are sent as 7 bits plus		 * last bit high.		 */		addr = ((i) << 1) + 1;		/*		 * Start with high order bit first working toward low		 * order bit.		 */		for ( j = 7; j >= 0; j-- ) {			/* Set current bit value */			eup->eu_sevar = ( addr >> j ) & 1 ?			    eup->eu_sevar | SEPROM_DATA :				eup->eu_sevar & ~SEPROM_DATA;			WRITE_SEEPROM ();			/* Indicate we've sent it */			STROBE_CLK();		}		/*		 * We expect a zero ACK after sending the address		 */		if ( !eni_get_ack ( eup ) ) {			/* Address okay - read data byte */			eup->eu_seeprom[i] = eni_get_sebyte ( eup );			/* Grab but ignore the ACK op */			(void) eni_get_ack ( eup );		} else {			/* Address ACK was bad - can't retrieve data byte */			eup->eu_seeprom[i] = 0xff;		}	}	return;}/* * The kernel has found a device which we are willing to support. * We are now being called to do any necessary work to make the * device initially usable. In our case, this means allocating * structure memory, configuring registers, mapping device * memory, setting pointers, registering with the core services, * and doing the initial PDU processing configuration. * * Arguments: *	config_id		PCI device token *	unit			instance of the unit * * Returns: *	none		 * */static voideni_pci_attach ( pcici_t config_id, int unit ){	vm_offset_t	va;	vm_offset_t	pa;	Eni_unit	*eup;	long		val;	/*	 * Just checking...	 */	if ( unit >= ENI_MAX_UNITS ) {		log ( LOG_ERR, "%s%d: too many devices\n",			ENI_DEV_NAME, unit );		return;	}	/*	 * Make sure this isn't a duplicate unit	 */	if ( eni_units[unit] != NULL )		return;	/*	 * Allocate a new unit structure	 */	eup = (Eni_unit *) atm_dev_alloc ( sizeof(Eni_unit), sizeof(int), 0 );	if ( eup == NULL )		return;	/*	 * Start initializing it	 */	eup->eu_unit = unit;	eup->eu_mtu = ENI_IFF_MTU;	eup->eu_pcitag = config_id;	eup->eu_ioctl = eni_atm_ioctl;	eup->eu_instvcc = eni_instvcc;	eup->eu_openvcc = eni_openvcc;	eup->eu_closevcc = eni_closevcc;	eup->eu_output = eni_output;	eup->eu_vcc_pool = &eni_vcc_pool;	eup->eu_nif_pool = &eni_nif_pool;	/*	 * Map in adapter RAM	 */	if ( ( pci_map_mem ( config_id, PCI_MAP_REG_START, &va, &pa ) ) == 0 )	{		/*		 * Nothing's happened yet that we need to undo.		 */		return;	}	/*	 * Map okay - retain address assigned	 */	eup->eu_base = (Eni_mem)va;	eup->eu_ram = (Eni_mem)(eup->eu_base + RAM_OFFSET);	/*	 * Map memory structures into adapter space	 */	eup->eu_suni = (Eni_mem)(eup->eu_base + SUNI_OFFSET);	eup->eu_midway = (Eni_mem)(eup->eu_base + MIDWAY_OFFSET);	eup->eu_vcitbl = (VCI_Table *)(eup->eu_base + VCITBL_OFFSET);	eup->eu_rxdma = (Eni_mem)(eup->eu_base + RXQUEUE_OFFSET);	eup->eu_txdma = (Eni_mem)(eup->eu_base + TXQUEUE_OFFSET);	eup->eu_svclist = (Eni_mem)(eup->eu_base + SVCLIST_OFFSET);	eup->eu_servread = 0;	/*	 * Reset the midway chip	 */	eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;	/*	 * Size and test adapter memory. Initialize our adapter memory	 * allocater.	 */	if ( eni_init_memory ( eup ) < 0 ) {		/*		 * Adapter memory test failed. Clean up and		 * return.		 */		/*		 * FreeBSD doesn't support unmapping PCI memory (yet?).		 */		return;	}	/*	 * Read the contents of the SEEPROM	 */	eni_read_seeprom ( eup );	/*	 * Copy MAC address to PIF and config structures	 */	KM_COPY ( (caddr_t)&eup->eu_seeprom[SEPROM_MAC_OFF],	    (caddr_t)&eup->eu_pif.pif_macaddr, sizeof(struct mac_addr) );	eup->eu_config.ac_macaddr = eup->eu_pif.pif_macaddr;	/*	 * Copy serial number into config space	 */	eup->eu_config.ac_serial =		ntohl(*(u_long *)&eup->eu_seeprom[SEPROM_SN_OFF]);	/*	 * Convert Endianess on DMA	 */	val = pci_conf_read ( config_id, PCI_CONTROL_REG );	val |= ENDIAN_SWAP_DMA;	pci_conf_write ( config_id, PCI_CONTROL_REG, val );	/*	 * Map interrupt in	 */	if ( !pci_map_int ( config_id, eni_intr, (void *)eup, &net_imask ) )	{		/*		 * Finish by unmapping memory, etc.		 */		log ( LOG_ERR, "eni_pci_attach: Unable to map interrupt\n" );		/*		 * Can't unmap PCI memory (yet).		 */		return;	}	/*	 * Setup some of the adapter configuration	 */	/*	 * Get MIDWAY ID	 */	val = eup->eu_midway[MIDWAY_ID];	eup->eu_config.ac_vendor = VENDOR_ENI;	eup->eu_config.ac_vendapi = VENDAPI_ENI_1;	eup->eu_config.ac_device = DEV_ENI_155P;	eup->eu_config.ac_media = val & MEDIA_MASK ? MEDIA_UTP155 : MEDIA_OC3C;	eup->eu_pif.pif_pcr = ATM_PCR_OC3C;	eup->eu_config.ac_bustype = BUS_PCI;	eup->eu_config.ac_busslot = config_id->bus << 8 | config_id->slot;	/*	 * Make a hw version number from the ID register values.	 * Format: {Midway ID}.{Mother board ID}.{Daughter board ID}	 */	snprintf ( eup->eu_config.ac_hard_vers,	    sizeof ( eup->eu_config.ac_hard_vers ),		"%ld/%ld/%ld",		(val >> ID_SHIFT) & ID_MASK,		(val >> MID_SHIFT) & MID_MASK,		(val >> DID_SHIFT) & DID_MASK );	/*	 * There is no software version number	 */	eup->eu_config.ac_firm_vers[0] = '\0';	/*	 * Save device ram info for user-level programs	 * NOTE: This really points to start of EEPROM	 * and includes all the device registers in the	 * lower 2 Megabytes.	 */	eup->eu_config.ac_ram = (long)eup->eu_base;	eup->eu_config.ac_ramsize = eup->eu_ramsize + ENI_REG_SIZE;	/*	 * Setup max VPI/VCI values	 */	eup->eu_pif.pif_maxvpi = ENI_MAX_VPI;	eup->eu_pif.pif_maxvci = ENI_MAX_VCI;	/*	 * Register this interface with ATM core services	 */	if ( atm_physif_register		( (Cmn_unit *)eup, ENI_DEV_NAME, eni_services ) != 0 )	{		/*		 * Registration failed - back everything out		 */		/*		 * Can't unmap PCI memory (yet).		 */		/*		 * Unmap PCI interrupt		 */		(void) pci_unmap_int ( config_id );		log ( LOG_ERR,			"eni_pci_attach: atm_physif_register failed\n" );		return;	}	eni_units[unit] = eup;#if BSD >= 199506	/*	 * Add hook to out shutdown function	 */	at_shutdown ( (bootlist_fn)eni_pci_shutdown, eup, SHUTDOWN_POST_SYNC );#endif	/*	 * Initialize driver processing	 */	if ( eni_init ( eup ) ) {		log ( LOG_ERR, "eni_pci_attach: Failed eni_init()\n" );		/*		 * Can't unmap PCI memory (yet).		 */		/*		 * Unmap PCI interrupt		 */		(void) pci_unmap_int ( config_id );		/*		 * Fall through to return		 */	}	return;}/* * Device reset routine * * Arguments: *	eup			pointer to per unit structure * * Returns: *	none * */static voideni_pci_reset ( eup )	Eni_unit *eup;{	/*	 * We should really close down any open VCI's and	 * release all memory (TX and RX) buffers. For now,	 * we assume we're shutting the card down for good.	 */	/*	 * Issue RESET command to Midway chip	 */	eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;	/*	 * Delay to allow everything to terminate	 */	DELAY ( MIDWAY_DELAY );	return;}#ifdef	__FreeBSD__#if BSD < 199506/* * Device shutdown routine * * Arguments: *	kdc		pointer to device's configuration table *	force		forced shutdown flag * * Returns: * 	none * */static inteni_pci_shutdown ( kdc, force )	struct kern_devconf	*kdc;	int			force;{	Eni_unit	*eup = NULL;	if ( kdc->kdc_unit < eni_nunits ) {		eup = eni_units[kdc->kdc_unit];		if ( eup != NULL ) {			/* Do device reset */			eni_pci_reset ( eup );		}	}	(void) dev_detach ( kdc );	return ( 0 );}#else/* * Device shutdown routine * * Arguments: *	howto		type of shutdown *	eup		pointer to device unit structure * * Returns: *	none * */static voideni_pci_shutdown ( howto, eup )	int	howto;	void	*eup;{	/* Do device reset */	eni_pci_reset ( eup );}#endif	/* BSD < 199506 */#endif	/* __FreeBSD__ */

⌨️ 快捷键说明

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