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

📄 f91mac.c

📁 zilog的实时操作系统RZK,可以移植到多种处理器上
💻 C
📖 第 1 页 / 共 2 页
字号:
}



//reading from the AMD 79C874 PHY registers.
UINT16 ReadPhyReg(UINT16 phy_reg, UINT16* data)
{
	// read the creg
	EMAC_RGAD = phy_reg;
	EMAC_MIIMGT |= RSTAT;
	// wait for mii done
	while(EMAC_MIISTAT & MGTBUSY);
	*data = (EMAC_PRSD_L + ((UINT16)EMAC_PRSD_H<<8));
	return EMACDEV_ERR_SUCCESS;
}



void EmacReset( void )
{
	EMAC_IEN = 0;
	// Reset all pemac blocks
	EMAC_RST = SRST | HRTFN | HRRFN | HRTMC | HRRMC | HRMGT;
}



void EmacEnableIrq( void )
{
	// enable the tx and rx interrupts
	EMAC_IEN = RXDONEIEN | TXDONEIEN;
}



void EmacDisableIrq( void )
{
	// Disable the tx and rx interrupts
	EMAC_IEN = 0;
}


RZK_TIMERHANDLE_t emacTimerHdl ;

DDF_STATUS_t EthInitFunc(INT8 * ieeeaddr, void (*rxnotify)(void))
{
	//
	// ieeeaddr is pointer to a char array containing 6 bytes of
	// EMAC Station Address
	//
	UINT16    i;
	UINT16    temp;
	INT status ;

	/*
	 * Save the interrupt callback addresses
	 */
	rxnotifyfunc = rxnotify;	
	if( rxnotifyfunc == 0 )
	{
		return (ILLEGAL_CALLBACKS);
	}

	/*
	 * Ensure internal EMAC Ram is enabled. Calculate memory base address and clear it.
	 */
	pInternalSramBase = (INT8 *)((((UINT32)RAM_ADDR_U) << 16) + (INT8*)EMAC_RAM_OFFSET);
	RAM_CTL |= ERAM_EN;
	memset( (INT8*)pInternalSramBase,0, EMAC_RAM_SIZE );

	EmacReset();	
//	CRCErrors = RuntErrors = ExcessLengthErrors = RxMissCount = TxColCount = 0;
	polynomial = 0x04c11db7UL;

	// setup the emac station address
	for (i = 0; i < 6; i++) 
	{
		EmacStad(i) = *(ieeeaddr+i);
	}
	
	// check by reading back station address
	for (i = 0; i < 6; i++) 
	{
		if (EmacStad(i) != *(ieeeaddr+i))
			return(EMACDEV_ERR_PEMAC_NOT_FOUND);
	}

	// disable EMAC interrupts
	EMAC_IEN = 0;
	
	// clear interrupt status flags
	EMAC_ISTAT = 0xff;
	
	// setup buffer size
	if( F91_emac_config.bufSize > BUF32 )
	{
		bufSize = BUF32;
	}
	else
	{
		bufSize = F91_emac_config.bufSize;
	}
	bufSizeShift = 8 - bufSize;
	EMAC_BUFSZ = bufSize << 6;
	bufMask = 0xFFFF << bufSizeShift;
	bufSize = 1 << bufSizeShift;
//	kprintf( "Using packet buffer size %x, Mask %x, Shift %x\n", bufSize, bufMask, bufSizeShift );

	
	// set pause frame control timeout value
	EMAC_TPTV_L = 0x14;
	EMAC_TPTV_H = 0x00;

	/*
	 * Ensure there is enough room in the Tx buffer for at least 1
	 * full sized ethernet frame + one extra emac packet buffer.
	 */
	temp = (MAXDATASIZE + HEADERSIZE + sizeof(DESC_TBL_t) + (bufSize<<1) -1) & bufMask;
	if( ((F91_emac_config.txBufSize & bufMask) >= temp) 
	 && ((F91_emac_config.txBufSize & bufMask) <= EMAC_RAM_SIZE) )
	{
		temp = F91_emac_config.txBufSize & bufMask;
	}
	if( F91_emac_config.txBufSize != temp )
	{
		/*kprintf( "Adjusted F91 Tx buffer size to %u\n", temp )*/;
	}

	// init descriptor tables boundry pointers
	tlbp = (DESC_TBL_t*)(pInternalSramBase);
	bp   = (DESC_TBL_t*)(pInternalSramBase + temp);
	rhbp = (DESC_TBL_t*)(pInternalSramBase + EMAC_RAM_SIZE);
	//kprintf( "TLBP %x,  BP %x,  RHBP %x\n", tlbp, bp, rhbp );

	// load Emac i/o regs from pointers
   EMAC_TLBP_L = ((UINT32) tlbp);
	EMAC_TLBP_H = ((UINT32) tlbp) >> 8;
	EMAC_BP_L   = ((UINT32) bp);
	EMAC_BP_H   = ((UINT32) bp) >> 8;
	EMAC_BP_U   = ((UINT32) bp) >> 16;
	EMAC_RHBP_L = ((UINT32) rhbp);
	EMAC_RHBP_H = ((UINT32) rhbp) >> 8;

	//TOT notes
	//TRP =>  Transmit Read pointer, EMAC controller reads next pkt ot TX from here
	//TWP => Transmit Write pointer, Apliication write next pkt ot TX to here
	//RWP => received write pointer, EMAC controller write next pkt RXed here
	//RRP  => received read pointer, Apliication reads next pkt from here

	
	// setup s/w pointers to ring buffers
	twp = trp = tlbp;
	rwp = rrp = bp;
	
	// write rrp into i/o reg rrp
	EMAC_RRP_L = ((UINT32) rrp);
	EMAC_RRP_H = ((UINT32) rrp) >> 8;

	
	// host owns first buffer
	twp->stat = 0x0000;
	
	// set polling timer for minimum timeout period
	EMAC_PTMR = 1;
	
	// disable EMAC test modes
	EMAC_TEST = 0;
	
	// enable padding, crc generation, full duplex mode
// 	EMAC_CFG1 = PADEN | CRCEN | FULLD;
	
	// set the late collision byte at byte 56
	EMAC_CFG2 = 56;
	
	// set max # collisions = 15
	EMAC_CFG3 = 15;
	
	// Enable the EMAC receiver
	EMAC_CFG4 = RXEN;
	
	// Init the Address Filter
	EMAC_AFR = BROADCAST;

	#ifdef MULTICAST
	EMAC_AFR |= QMULTICAST;
	#endif
	// set the max # bytes per packet to 1536
	EMAC_MAXF_L = 0x00;
	EMAC_MAXF_H = 0x06;

	// take EMAC out of reset
	EMAC_RST = 0;	
	
	// Initialize the PHY AMD 79C874
	// set mmiimgt mdc clock rate
	EMAC_MIIMGT = CLKDIV20;

	g_MacSem = RZKCreateSemaphore((RZK_NAME_t*)"g_MacSem",1,RECV_ORDER_PRIORITY);
	if(g_MacSem == NULL)
		printf("\nEmac Semaphore creation error");
	status = phyInit() ;

	if(  status != EMACDEV_ERR_SUCCESS)
	{
		if(status == EMACDEV_ERR_PEMAC_PHYINIT_FAILED)
		{
				/* Added for initializing the link if cable has been pulled out during initialization */ // Against CR No 4401
		emacConnChkThdHdl = RZKCreateThreadEnhanced((RZK_NAME_t*)"EMACcon",
														(RZK_PTR_t)emacConnThd, 
														( FNP_THREAD_ENTRY* )NULL, 
														512, 
														2, 
														2,
														RZK_THREAD_PREEMPTION|RZK_THREAD_AUTOSTART,
														0 ) ;
			if( emacConnChkThdHdl == NULL )
			{
				return EMACDEV_ERR_RESOURCE_NOT_CREATED ;
			}
		}
		else
		{	
			#ifdef net_reset
				wdt_init(WDT_18OUT);
			#endif
		//	SetPDState(2,0);
			printf(" EMAC Initialization error\n") ;
			return EMACDEV_ERR_PEMAC_PHYINIT_FAILED ;
		}
	}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	//clear interrupt status register
	EMAC_ISTAT = 0xff;	

	// Check access to EMAC shared ram
	// don't overwrite tx status descriptor
	for (i=10; i<18; i++)
		pInternalSramBase[i] = i;

	for (i=10; i<18; i++) 
	{
		if( pInternalSramBase[i] != i )
			return (EMACDEV_ERR_PEMAC_SMEM_FAIL);
	}

	/*
	 * Create the Interrupt Task
	 */

/* Create Interrupt thread */
	emacInterruptThdHdl = RZKCreateThreadEnhanced((RZK_NAME_t*)"EMACIT",
													(RZK_PTR_t)F91EmacTask, 
													( FNP_THREAD_ENTRY* )NULL, 
													EMAC_THD_STACK_SIZE, 
													EMAC_TASK_PRIO, 
													2,
													RZK_THREAD_INTERRUPT|RZK_THREAD_PREEMPTION,
													0 ) ;
		if( emacInterruptThdHdl == NULL )
		{
			return EMACDEV_ERR_RESOURCE_NOT_CREATED ;
		}

	// setup EMAC interrupts
	RZKInstallInterruptHandler( (RZK_FNP_ISR)emacisr, IV_ERX) ;
	RZKInstallInterruptHandler( (RZK_FNP_ISR)emacisr, IV_ETX) ;
	RZKInstallInterruptHandler( (RZK_FNP_ISR)emacisr, IV_ESYS) ;


	// enable the tx and rx interrupts
	EMAC_IEN = RXDONEIEN | TXDONEIEN;
//	EMAC_IEN = RXDONEIEN | TXDONEIEN | RXOVRRUNIEN;				// When system interrupt handler added

	return (EMACDEV_ERR_PEMAC_INIT_DONE);
}



/*
 * Internal function to calculate a multicast hash value for the receiver.
 * For this device, a bit mask is used to coarsely filter possible
 * multicast packets.  The bit is calculated by using the CRC algorithm
 * applied to the physical destination address, and then using the six
 * most significant bits as the integer bit index in the eight-byte mask.
 */
INT8 MulticastHash(INT8 *ether_addr)
{
	INT8 bitnum, current_octet;
	INT8 i;
	

	crc = -1;
	for(i=5; i >= 0; i--) {
		current_octet = *ether_addr++;
		for (bitnum = 0; bitnum < 8; bitnum++, current_octet >>= 1)
			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? polynomial : 0);
	}
	return ((UINT32) crc) >> 26;
}



void EthMAddFunc
(
	INT8 *							pAddr
)
{
	INT8 							bitnum;
	INT8 							i;
	INT8							data;
	INT8 							MAR;
	RZK_STATE_t stat ;

//	kprintf( "Add multicast addr %02x:%02x:%02x:%02x:%02x:%02x\n",
//		pAddr[0],
//		pAddr[1],
//		pAddr[2],
//		pAddr[3],
//		pAddr[4],
//		pAddr[5] );
	bitnum = MulticastHash(pAddr);
	stat = RZKDisablePreemption();

	//not sure about TS generating proper code here. Use temporary variables.
	MAR = bitnum/8;
	data = EmacHtbl(MAR);
	data |= (1 << (bitnum%8));
	EmacHtbl(MAR) = data;

	data = 0;
	for(i=0; i < 8; i++)
	{
		data |= EmacHtbl(i);
	}

	//if any bit set, enable multicast
	if(data)
	{
		EMAC_AFR |= QMULTICAST;
	}

	RZKRestorePreemption(stat);
}



/*
 * Remove given address from the list supported in HW.
 */
void EthMDelFunc
(
	INT8 *							pAddr
)
{
	INT8 								bitnum;
	INT8 								i;
	INT8								data;
	INT8 								MAR;
	RZK_STATE_t stat ;

//	kprintf( "Delete multicast addr %02x:%02x:%02x:%02x:%02x:%02x\n",
//		pAddr[0],
//		pAddr[1],
//		pAddr[2],
//		pAddr[3],
//		pAddr[4],
//		pAddr[5] );
	bitnum = MulticastHash(pAddr);
	stat = RZKDisablePreemption();
	
	MAR = bitnum/8;
	data = ~(1 << (bitnum%8));
	data &= EmacHtbl(MAR);
	EmacHtbl(MAR) = data;

	data = 0;
	for(i=0; i < 8; i++)
	{
		data |= EmacHtbl(i);
	}

	//if no bit is set, disable multicast
	if(!data)
	{
		EMAC_AFR &= ~(QMULTICAST);
	}
	RZKRestorePreemption(stat);
}










⌨️ 快捷键说明

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