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

📄 tlan.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	u32		ack;	u32		error;	u8		net_sts;	u32		phy;	u16		tlphy_ctl;	u16		tlphy_sts;		ack = 1;	if ( host_int & TLAN_HI_IV_MASK ) {		error = inl( dev->base_addr + TLAN_CH_PARM );		printk( "TLAN:  %s: Adaptor Error = 0x%x\n", dev->name, error );		TLan_ReadAndClearStats( dev, TLAN_RECORD );		outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );		TLan_FreeLists( dev );		TLan_ResetLists( dev );		TLan_ResetAdapter( dev );		dev->tbusy = 0;		ack = 0;	} else {		TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Status Check\n", dev->name );		phy = priv->phy[priv->phyNum];		net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );		if ( net_sts ) {			TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );			TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s:    Net_Sts = %x\n", dev->name, (unsigned) net_sts );		}		if ( ( net_sts & TLAN_NET_STS_MIRQ ) &&  ( priv->phyNum == 0 ) ) {			TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts );			TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );        		if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {                		tlphy_ctl |= TLAN_TC_SWAPOL;                		TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);        		} else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {                		tlphy_ctl &= ~TLAN_TC_SWAPOL;                		TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);        		}			if (debug) {				TLan_PhyPrint( dev );			}		}	}	return ack;} /* TLan_HandleStatusCheck */	/***************************************************************	 *	TLan_HandleRxEOC	 *	 *	Returns:	 *		1	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This driver is structured to determine EOC occurances by	 *	reading the CSTAT member of the list structure.  Rx EOC	 *	interrupts are disabled via the DIO INTDIS register.	 *	However, TLAN chips before revision 3.0 didn't have this	 *	CSTAT member or a INTDIS register, so if this chip is	 *	pre-3.0, process EOC interrupts normally.	 *	 **************************************************************/u32 TLan_HandleRxEOC( struct device *dev, u16 host_int ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	TLanList	*head_list;	u32		ack = 1;	host_int = 0;	if (  priv->tlanRev < 0x30 ) {		TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail );		head_list = priv->rxList + priv->rxHead;		outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );		ack |= TLAN_HC_GO | TLAN_HC_RT;		priv->rxEocCount++;	}	return ack;} /* TLan_HandleRxEOC *//***********************************************************************************************************************************************************	ThunderLAN Driver Timer Function***********************************************************************************************************************************************************/	/***************************************************************	 *	TLan_Timer	 *	 *	Returns:	 *		Nothing	 *	Parms:	 *		data	A value given to add timer when	 *			add_timer was called.	 *	 *	This function handles timed functionality for the	 *	TLAN driver.  The two current timer uses are for	 *	delaying for autonegotionation and driving the ACT LED.	 *	-	Autonegotiation requires being allowed about	 *		2 1/2 seconds before attempting to transmit a	 *		packet.  It would be a very bad thing to hang	 *		the kernel this long, so the driver doesn't	 *		allow transmission 'til after this time, for	 *		certain PHYs.  It would be much nicer if all	 *		PHYs were interrupt-capable like the internal	 *		PHY.	 *	-	The ACT LED, which shows adapter activity, is	 *		driven by the driver, and so must be left on	 *		for a short period to power up the LED so it	 *		can be seen.  This delay can be changed by	 *		changing the TLAN_TIMER_ACT_DELAY in tlan.h,	 *		if desired.  10 jiffies produces a slightly	 *		sluggish response.	 *	 **************************************************************/void TLan_Timer( unsigned long data ){	struct device	*dev = (struct device *) data;	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	u32		elapsed;	priv->timer.function = NULL;	switch ( priv->timerType ) {		case TLAN_TIMER_PHY_PDOWN:			TLan_PhyPowerDown( dev );			break;		case TLAN_TIMER_PHY_PUP:			TLan_PhyPowerUp( dev );			break;		case TLAN_TIMER_PHY_RESET:			TLan_PhyReset( dev );			break;		case TLAN_TIMER_PHY_START_LINK:			TLan_PhyStartLink( dev );			break;		case TLAN_TIMER_PHY_FINISH_AN:			TLan_PhyFinishAutoNeg( dev );			break;		case TLAN_TIMER_FINISH_RESET:			TLan_FinishReset( dev );			break;		case TLAN_TIMER_ACTIVITY:			cli();			if ( priv->timer.function == NULL ) {				elapsed = jiffies - priv->timerSetAt;				if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {					TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );				} else  {					priv->timer.function = &TLan_Timer;					priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;					sti();					add_timer( &priv->timer );				}			}			sti();			break;		default:			break;	}} /* TLan_Timer *//***********************************************************************************************************************************************************	ThunderLAN Driver Adapter Related Routines***********************************************************************************************************************************************************/	/***************************************************************	 *	TLan_ResetLists	 *  	 *	Returns:	 *		Nothing	 *	Parms:	 *		dev	The device structure with the list	 *			stuctures to be reset.	 *	 *	This routine sets the variables associated with managing	 *	the TLAN lists to their initial values.	 *	 **************************************************************/void TLan_ResetLists( struct device *dev ){	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;	int		i;	TLanList	*list;	struct sk_buff	*skb;	void		*t = NULL;	priv->txHead = 0;	priv->txTail = 0;	for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {		list = priv->txList + i;		list->cStat = TLAN_CSTAT_UNUSED;		if ( bbuf ) {			list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );		} else {			list->buffer[0].address = 0;		}		list->buffer[2].count = 0;		list->buffer[2].address = 0;	}	priv->rxHead = 0;	priv->rxTail = TLAN_NUM_RX_LISTS - 1;	for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {		list = priv->rxList + i;		list->cStat = TLAN_CSTAT_READY;		list->frameSize = TLAN_MAX_FRAME_SIZE;		list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;		if ( bbuf ) {			list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );		} else {			skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );			if ( skb == NULL ) {				printk( "TLAN:  Couldn't allocate memory for received data.\n" );				/* If this ever happened it would be a problem */			} else {				skb->dev = dev;				skb_reserve( skb, 2 );				t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );			}			list->buffer[0].address = virt_to_bus( t );			list->buffer[9].address = (u32) skb;		}		list->buffer[1].count = 0;		list->buffer[1].address = 0;		if ( i < TLAN_NUM_RX_LISTS - 1 )			list->forward = virt_to_bus( list + 1 );		else			list->forward = 0;	}} /* TLan_ResetLists */void TLan_FreeLists( struct device *dev ){	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;	int		i;	TLanList	*list;	struct sk_buff	*skb;	if ( ! bbuf ) {		for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {			list = priv->txList + i;			skb = (struct sk_buff *) list->buffer[9].address;			if ( skb ) {				dev_kfree_skb( skb );				list->buffer[9].address = 0;			}		}		for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {			list = priv->rxList + i;			skb = (struct sk_buff *) list->buffer[9].address;			if ( skb ) {				dev_kfree_skb( skb );				list->buffer[9].address = 0;			}		}	}} /* TLan_FreeLists */	/***************************************************************	 *	TLan_PrintDio	 *  	 *	Returns:	 *		Nothing	 *	Parms:	 *		io_base		Base IO port of the device of	 *				which to print DIO registers.	 *	 *	This function prints out all the the internal (DIO)	 *	registers of a TLAN chip.	 *	 **************************************************************/void TLan_PrintDio( u16 io_base ){	u32 data0, data1;	int	i;	printk( "TLAN:   Contents of internal registers for io base 0x%04hx.\n", io_base );	printk( "TLAN:      Off.  +0         +4\n" );	for ( i = 0; i < 0x4C; i+= 8 ) {		data0 = TLan_DioRead32( io_base, i );		data1 = TLan_DioRead32( io_base, i + 0x4 );		printk( "TLAN:      0x%02x  0x%08x 0x%08x\n", i, data0, data1 );	}} /* TLan_PrintDio */	/***************************************************************	 *	TLan_PrintList	 *  	 *	Returns:	 *		Nothing	 *	Parms:	 *		list	A pointer to the TLanList structure to	 *			be printed.	 *		type	A string to designate type of list,	 *			"Rx" or "Tx".	 *		num	The index of the list.	 *	 *	This function prints out the contents of the list	 *	pointed to by the list parameter.	 *	 **************************************************************/void TLan_PrintList( TLanList *list, char *type, int num){	int i;	printk( "TLAN:   %s List %d at 0x%08x\n", type, num, (u32) list );	printk( "TLAN:      Forward    = 0x%08x\n",  list->forward );	printk( "TLAN:      CSTAT      = 0x%04hx\n", list->cStat );	printk( "TLAN:      Frame Size = 0x%04hx\n", list->frameSize );	/* for ( i = 0; i < 10; i++ ) { */	for ( i = 0; i < 2; i++ ) {		printk( "TLAN:      Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address );	}} /* TLan_PrintList */	/***************************************************************	 *	TLan_ReadAndClearStats	 *	 *	Returns:	 *		Nothing	 *	Parms:	 *		dev	Pointer to device structure of adapter	 *			to which to read stats.	 *		record	Flag indicating whether to add 	 *	 *	This functions reads all the internal status registers	 *	of the TLAN chip, which clears them as a side effect.	 *	It then either adds the values to the device's status	 *	struct, or discards them, depending on whether record	 *	is TLAN_RECORD (!=0)  or TLAN_IGNORE (==0).	 *	 **************************************************************/void TLan_ReadAndClearStats( struct device *dev, int record ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	u32		tx_good, tx_under;	u32		rx_good, rx_over;	u32		def_tx, crc, code;	u32		multi_col, single_col;	u32		excess_col, late_col, loss;	outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR );	tx_good  = inb( dev->base_addr + TLAN_DIO_DATA );	tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;	tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;	tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 );	outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR );	rx_good  = inb( dev->base_addr + TLAN_DIO_DATA );	rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;	rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;	rx_over  = inb( dev->base_addr + TLAN_DIO_DATA + 3 );			outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR );	def_tx  = inb( dev->base_addr + TLAN_DIO_DATA );	def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;	crc     = inb( dev->base_addr + TLAN_DIO_DATA + 2 );	code    = inb( dev->base_addr + TLAN_DIO_DATA + 3 );		outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR );	multi_col   = inb( dev->base_addr + TLAN_DIO_DATA );	multi_col  += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;	single_col  = inb( dev->base_addr + TLAN_DIO_DATA + 2 );	single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8;	outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR );	excess_col = inb( dev->base_addr + TLAN_DIO_DATA );	late_col   = inb( dev->base_addr + TLAN_DIO_DATA + 1 );	loss       = inb( dev->base_addr + TLAN_DIO_DATA + 2 );	if ( record ) {		priv->stats.rx_packets += rx_good;		priv->stats.rx_errors  += rx_over + crc + code;		priv->stats.tx_packets += tx_good;		priv->stats.tx_errors  += tx_under + loss;		priv->stats.collisions += multi_col + single_col + excess_col + late_col;		priv->stats.rx_over_errors    += rx_over;		priv->stats.rx_crc_errors     += crc;		priv->stats.rx_frame_errors   += code;		priv->stats.tx_aborted_errors += tx_under;		priv->stats.tx_carrier_errors += loss;	}			} /* TLan_ReadAndClearStats */	/***************************************************************	 *	TLan_Reset	 *	 *	Returns:	 *		0	 *	Parms:	 *		dev	Pointer to device structure of adapter	 *			to be reset.	 *	 *	This function resets the adapter and it's physical	 *	device.  See Chap. 3, pp. 9-10 of the "ThunderLAN	 *	Programmer's Guide" for details.  The routine tries to	 *	implement what is detailed there, though adjustments	 *	have been made.	 *	 **************************************************************/voidTLan_ResetAdapter( struct device *dev ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	int		i;	u32		addr;	u32		data;	u8		data8;	priv->tlanFullDuplex = FALSE;	priv->phyOnline=0;/*  1.	Assert reset bit. */	data = inl(dev->base_addr + TLAN_HOST_CMD);	data |= TLAN_HC_AD_RST;	outl(data, dev->base_addr + TLAN_HOST_CMD);		udelay(1000);

⌨️ 快捷键说明

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