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

📄 simp911x.c

📁 SMSC 9118 Driver for linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		privateData->SoftwareInterruptSignal=FALSE;
		Lan_SetBitsDW(INT_EN,INT_EN_SW_INT_EN_);
		do {
			udelay(10);
			dwTimeOut--;
		} while((dwTimeOut)&&(!(privateData->SoftwareInterruptSignal)));
		if(!(privateData->SoftwareInterruptSignal)) {
			SMSC_WARNING("ISR failed signal test");
			//disable IRQ anyway
			Lan_ClrBitsDW(INT_CFG,INT_CFG_IRQ_EN_);
		}
	}

	spin_lock(&dev->xmit_lock);
	netif_stop_queue(privateData->dev);
	spin_unlock(&dev->xmit_lock);

	//at this point all Rx and Tx activity is stopped

	privateData->stats.rx_dropped+=Lan_GetRegDW(RX_DROP);
	Tx_UpdateTxCounters(privateData);

#ifndef LINUX_2_6_OR_NEWER
	MOD_DEC_USE_COUNT;
#endif

	free_irq(irq[privateData->dwInstanceIndex],privateData);
	release_mem_region(privateData->dwLanBase,LAN_REGISTER_EXTENT);

	{//preserve important items, clear the rest
		DWORD dwLanBase=privateData->dwLanBase;
		DWORD dwIdRev=privateData->dwIdRev;
		DWORD dwInstanceIndex=privateData->dwInstanceIndex;
		struct net_device *tempDev=privateData->dev;
		struct net_device_stats tempStats;
		memcpy(&tempStats,&(privateData->stats),sizeof(struct net_device_stats));

		memset(privateData,0,sizeof(PRIVATE_DATA));

		memcpy(&(privateData->stats),&tempStats,sizeof(struct net_device_stats));
		privateData->dwLanBase=dwLanBase;
		privateData->dwInstanceIndex=dwInstanceIndex;
		privateData->dev=tempDev;
		privateData->dwIdRev=dwIdRev;
	}

DONE:
	SMSC_TRACE("<--Simp911x_stop, result=%d",result);
	return result;
}

//entry point for transmitting a packet
int Simp911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	int result=0;
	PPRIVATE_DATA privateData=NULL;
	if(skb==NULL) {
		SMSC_WARNING("Simp911x_hard_start_xmit(skb==NULL)");
		result=-EFAULT;
		goto DONE;
	}
	if(dev==NULL) {
		SMSC_WARNING("Simp911x_hard_start_xmit(dev==NULL)");
		result=-EFAULT;
		goto DONE;
	}
	if(dev->priv==NULL) {
		SMSC_WARNING("Simp911x_hard_start_xmit(dev->priv==NULL)");
		result=-EFAULT;
		goto DONE;
	}
	privateData=(PPRIVATE_DATA)(dev->priv);

	Tx_SendSkb(privateData,skb);

DONE:
	return result;
}

//entry point for getting status counters
struct net_device_stats * Simp911x_get_stats(struct net_device *dev)
{
	PPRIVATE_DATA privateData=NULL;
	if(dev==NULL) {
		SMSC_WARNING("Simp911x_get_stats(dev==NULL)");
		return NULL;
	}
	if(dev->priv==NULL) {
		SMSC_WARNING("Simp911x_get_stats(dev->priv==NULL)");
		return NULL;
	}
	privateData=(PPRIVATE_DATA)(dev->priv);
	return &(privateData->stats);
}

//entry point for setting addressing modes
void Simp911x_set_multicast_list(struct net_device *dev)
{
	SMSC_ASSERT(dev!=NULL);
	Rx_SetMulticastList(dev);
}

//primary entry point for ISR
irqreturn_t Simp911x_ISR(int Irq, void *dev_id, struct pt_regs *regs)
{
	DWORD dwIntCfg=0;
	DWORD dwIntSts=0;
	PPRIVATE_DATA privateData=(PPRIVATE_DATA)dev_id;
	BOOLEAN serviced=FALSE;

	if(privateData==NULL) {
		SMSC_WARNING("Simp911x_ISR(privateData==NULL)");
		goto DONE;
	}
	if(privateData->dwLanBase==0) {
		SMSC_WARNING("Simp911x_ISR(dwLanBase==0)");
		goto DONE;
	}
	dwIntCfg=Lan_GetRegDW(INT_CFG);
	if((dwIntCfg&0x00001100)!=0x00001100) {
		SMSC_TRACE("In ISR, not my interrupt, dwIntCfg=0x%08lX",
			dwIntCfg);
		goto DONE;
	}
	{
		DWORD reservedBits=0x00FFCEEEUL;
		if(dwIntCfg&reservedBits) {
			SMSC_WARNING("In ISR, reserved bits are high.");
			//this could mean surprise removal
			goto DONE;
		}
	}
	dwIntSts=Lan_GetRegDW(INT_STS);
	if(dwIntSts&INT_STS_SW_INT_) {
		Lan_ClrBitsDW(INT_EN,INT_EN_SW_INT_EN_);
		Lan_SetRegDW(INT_STS,INT_STS_SW_INT_);
		privateData->SoftwareInterruptSignal=TRUE;
		serviced=TRUE;
		if(privateData->RequestIrqDisable) {
			Lan_ClrBitsDW(INT_CFG,INT_CFG_IRQ_EN_);
			dwIntSts=0;//prevent any pending interrupts from being handled.
		}
	}
	if(Tx_HandleInterrupt(privateData,dwIntSts)) {
		serviced=TRUE;
	}
	if(Rx_HandleInterrupt(privateData,dwIntSts)) {
		serviced=TRUE;
	}
	if(!serviced) {
		SMSC_WARNING("unserviced interrupt dwIntCfg=0x%08lX,dwIntSts=0x%08lX,INT_EN=0x%08lX",
			dwIntCfg,dwIntSts,Lan_GetRegDW(INT_EN));
	}
DONE:
	return IRQ_RETVAL(serviced);
}

#ifdef USE_PHY_WORK_AROUND
BOOLEAN Phy_Reset(PPRIVATE_DATA privateData)
{
	BOOLEAN result=FALSE;
	WORD wTemp=0;
	DWORD dwLoopCount=100000;
	SMSC_TRACE("Performing PHY BCR Reset");
	Phy_SetRegW(privateData,PHY_BCR,PHY_BCR_RESET_);
	do {
		udelay(10);
		wTemp=Phy_GetRegW(privateData,PHY_BCR);
		dwLoopCount--;
	} while((dwLoopCount>0)&&(wTemp&PHY_BCR_RESET_));
	if(wTemp&PHY_BCR_RESET_) {
		SMSC_WARNING("Phy Reset failed to complete.");
		goto DONE;
	}
	//extra delay required because the phy may not be completed with its reset
	//  when PHY_BCR_RESET_ is cleared.
	//  They say 256 uS is enough delay but I'm using 500 here to be safe
	udelay(500);
	result=TRUE;
DONE:
	return result;
}

DWORD Phy_LBT_GetTxStatus(PPRIVATE_DATA privateData)
{
	DWORD result=Lan_GetRegDW(TX_FIFO_INF);
	result&=TX_FIFO_INF_TSUSED_;
	if(result!=0x00000000UL) {
		result=Lan_GetRegDW(TX_STATUS_FIFO);
	} else {
		result=0;
	}
	return result;
}

DWORD Phy_LBT_GetRxStatus(PPRIVATE_DATA privateData)
{
	DWORD result=Lan_GetRegDW(RX_FIFO_INF);
	if(result&0x00FF0000UL) {
		//Rx status is available, read it
		result=Lan_GetRegDW(RX_STATUS_FIFO);
	} else {
		result=0;
	}
	return result;
}
BOOLEAN Phy_CheckLoopBackPacket(PPRIVATE_DATA privateData)

{
	BOOLEAN result=FALSE;
	DWORD tryCount=0;
	DWORD dwLoopCount=0;
	for(tryCount=0;tryCount<10;tryCount++)
	{
		DWORD dwTxCmdA=0;
		DWORD dwTxCmdB=0;
		DWORD dwStatus=0;
		DWORD dwPacketLength=0;

		//zero-out Rx Packet memory
		memset(privateData->LoopBackRxPacket,0,MIN_PACKET_SIZE);

		//write Tx Packet to 118
		dwTxCmdA=
			((((DWORD)(privateData->LoopBackTxPacket))&0x03UL)<<16) | //DWORD alignment adjustment
			TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_ |
			((DWORD)(MIN_PACKET_SIZE));
		dwTxCmdB=
			(((DWORD)(MIN_PACKET_SIZE))<<16) |
			((DWORD)(MIN_PACKET_SIZE));
		Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
		Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
		Tx_WriteFifo(
			privateData->dwLanBase,
			(DWORD *)(((DWORD)(privateData->LoopBackTxPacket))&0xFFFFFFFCUL),
			(((DWORD)(MIN_PACKET_SIZE))+3+
			(((DWORD)(privateData->LoopBackTxPacket))&0x03UL))>>2);

		//wait till transmit is done
		dwLoopCount=60;
		while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetTxStatus(privateData))==0)) {
			udelay(5);
			dwLoopCount--;
		}
		if(dwStatus==0) {
			SMSC_WARNING("Failed to Transmit during Loop Back Test");
			continue;
		}
		if(dwStatus&0x00008000UL) {
			SMSC_WARNING("Transmit encountered errors during Loop Back Test");
			continue;
		}

		//wait till receive is done
		dwLoopCount=60;
		while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetRxStatus(privateData))==0))
		{
	         udelay(5);
	         dwLoopCount--;
		}
		if(dwStatus==0) {
			SMSC_WARNING("Failed to Receive during Loop Back Test");
			continue;
		}
		if(dwStatus&RX_STS_ES_)
		{
			SMSC_WARNING("Receive encountered errors during Loop Back Test");
			continue;
		}

		dwPacketLength=((dwStatus&0x3FFF0000UL)>>16);

		Rx_ReadFifo(
			privateData->dwLanBase,
			((DWORD *)(privateData->LoopBackRxPacket)),
			(dwPacketLength+3+(((DWORD)(privateData->LoopBackRxPacket))&0x03UL))>>2);

		if(dwPacketLength!=(MIN_PACKET_SIZE+4)) {
			SMSC_WARNING("Unexpected packet size during loop back test, size=%ld, will retry",dwPacketLength);
		} else {
			DWORD byteIndex=0;
			BOOLEAN foundMissMatch=FALSE;
			for(byteIndex=0;byteIndex<MIN_PACKET_SIZE;byteIndex++) {
				if(privateData->LoopBackTxPacket[byteIndex]!=privateData->LoopBackRxPacket[byteIndex])
				{
					foundMissMatch=TRUE;
					break;
				}
			}
			if(!foundMissMatch) {
				SMSC_TRACE("Successfully Verified Loop Back Packet");
				result=TRUE;
				goto DONE;
			} else {
				SMSC_WARNING("Data miss match during loop back test, will retry.");
			}
		}
	}
DONE:
	return result;
}
BOOLEAN Phy_LoopBackTest(PPRIVATE_DATA privateData)
{
	BOOLEAN result=FALSE;
	DWORD byteIndex=0;
	DWORD tryCount=0;
	//Initialize Tx Packet
	for(byteIndex=0;byteIndex<6;byteIndex++) {
		//use broadcast destination address
		privateData->LoopBackTxPacket[byteIndex]=(BYTE)0xFF;
	}
	for(byteIndex=6;byteIndex<12;byteIndex++) {
		//use incrementing source address
		privateData->LoopBackTxPacket[byteIndex]=(BYTE)byteIndex;
	}
	//Set length type field
	privateData->LoopBackTxPacket[12]=0x00;
	privateData->LoopBackTxPacket[13]=0x00;
	for(byteIndex=14;byteIndex<MIN_PACKET_SIZE;byteIndex++)
	{
		privateData->LoopBackTxPacket[byteIndex]=(BYTE)byteIndex;
	}
	{
		DWORD dwRegVal=Lan_GetRegDW(HW_CFG);
		dwRegVal&=HW_CFG_TX_FIF_SZ_;
		dwRegVal|=HW_CFG_SF_;
		Lan_SetRegDW(HW_CFG,dwRegVal);
	}
	Lan_SetRegDW(TX_CFG,TX_CFG_TX_ON_);
	Lan_SetRegDW(RX_CFG,(((DWORD)(privateData->LoopBackRxPacket))&0x03)<<8);

	//Set Phy to 10/FD, no ANEG,
	Phy_SetRegW(privateData,PHY_BCR,0x0100);

	//enable MAC Tx/Rx, FD
	Mac_SetRegDW(privateData,MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_);

	//set Phy to loopback mode
	Phy_SetRegW(privateData,PHY_BCR,0x4100);

	for(tryCount=0;tryCount<10;tryCount++) {
		if(Phy_CheckLoopBackPacket(privateData))
		{
			result=TRUE;
			goto DONE;
		}
		privateData->dwResetCount++;
		//disable MAC rx
		Mac_SetRegDW(privateData,MAC_CR,0UL);
		Phy_Reset(privateData);

		//Set Phy to 10/FD, no ANEG, and Loopbackmode
		Phy_SetRegW(privateData,PHY_BCR,0x4100);

		//enable MAC Tx/Rx, FD
		Mac_SetRegDW(privateData,MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_);
	}
DONE:
	//disable MAC
	Mac_SetRegDW(privateData,MAC_CR,0UL);
	//Cancel Phy loopback mode
	Phy_SetRegW(privateData,PHY_BCR,0U);

	Lan_SetRegDW(TX_CFG,0UL);
	Lan_SetRegDW(RX_CFG,0UL);

	return result;
}

#endif //USE_PHY_WORK_AROUND

//Sets the link mode
void Phy_SetLink(PPRIVATE_DATA privateData) 
{
	WORD wTemp;

	//Because this is part of the single threaded initialization
	//  path there is no need to acquire the MacPhyAccessLock

	wTemp=Phy_GetRegW(pri

⌨️ 快捷键说明

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