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

📄 ethernet_smsc91c111.c

📁 Intrisyc 公司的PXA255-bootloader,源码易懂
💻 C
📖 第 1 页 / 共 3 页
字号:
        }#if DEBUG_LEVEL >= 5        /*         * For some reason we must read OFFSET_FPR here or else          * OFFSET_EPHSR doesn't always set BIT_EPHSR_TX_SUC below         * when BIT_CR_AUTO_RELEASE is being used         */        SETUP_BANK(BANK_FPR);        READ_REG16(OFFSET_FPR, _temp);        /*         * Do a sanity check on the packet number.         * Not reliable when we are using BIT_CR_AUTO_RELEASE         */        if (!(_temp & BIT_FPR_TEMPTY) &&            (_temp & MASK_FPR_PACKET_NUM) != packet_number)        {                ERROR ("Packet # mismatch %d,%d\r\n",                       _temp & MASK_FPR_PACKET_NUM, packet_number);        }#endif        /*         * Check transmission status.  It might be better to check         * it from the TX Packet itself if we intended to queue up a         * bunch, send and so on.  (Currently, a tx packet must finish         * before another is queued.)         */        SETUP_BANK(BANK_EPHSR);        READ_REG16(OFFSET_EPHSR, _temp);	if (_temp & BIT_EPHSR_TX_SUC)	{                DEBUG_4 ("Tx OK\r\n");		// Release memory here because BIT_CR_AUTO_RELEASE is unset		release_tx_packet (packet_number);                // Clear the TX interrupt bit                SETUP_BANK (BANK_ISR);                WRITE_REG8 (OFFSET_IRQAR, BIT_ISR_TX_INT);		/*		 * Enable Receive		 */		SETUP_BANK(BANK_RCR);		READ_REG16(OFFSET_RCR, _temp);		_temp |= BIT_RCR_RXEN;		WRITE_REG16(OFFSET_RCR, _temp);		return 1;	}		else 	{                DEBUG_2 ("Tx unsuccessful %x\r\n", _temp);                DEBUG_2 ("ISR is %x\r\n", _temp8);		release_tx_packet (packet_number);                // Clear the TX interrupt bit                SETUP_BANK (BANK_ISR);                WRITE_REG8 (OFFSET_IRQAR, BIT_ISR_TX_INT);                if (retry++ < MAX_RETRANSMIT)                {                    DEBUG_2 ("Retry Tx\r\n");                    goto retransmit;		}                else                {                    return 0;		}	}	return 1;} // End of tx_packet_ethernetint rx_packet_ethernet(u8 *data, u16 *size, char bcast_enable){	unsigned char packet_number;	unsigned short _temp;	const unsigned short start_size=*size;	int retry=0;	int success;	/*	 * Enable the SMSC to Receive Packets if it is not already able to	 * do so.	 */	SETUP_BANK(BANK_RCR);	if (!(REG16(OFFSET_RCR) & BIT_RCR_RXEN))	{			REG16(OFFSET_RCR) |= BIT_RCR_RXEN;	}restart_rx:	/*	 * Wait for the RX Packet to Come in	 */	SETUP_BANK(BANK_ISR);	if (!(REG8(OFFSET_ISR) & BIT_ISR_RCV_INT))	{		return 0;	}	/*	 * Double check that we have Received Packets Waiting	 * This doesn't seem necessary with the BIT_ISR_RCV_INT check above,	 * but we need the packet number from this register regardless.	 */	SETUP_BANK(BANK_FPR);	READ_REG16(OFFSET_FPR, _temp);	if (_temp & BIT_FPR_REMPTY)	{		return 0;	}        DEBUG_4 ("Rx...");	/*	 * Grab the Packet Number out of the Fifo Ports Register	 */	packet_number = _temp >> 8;		*size = start_size;	if (!(success = read_mmu_data (&packet_number, data, size)))	{		DEBUG_2 ("%s: read_mmu_data Failed\r\n", __FUNCTION__);	}	if (!release_rx_packet ())	{		ERROR ("%s: Failed to Release Received Packet\r\n",				__FUNCTION__);	}	if (!success)	{		return 0;	}	/*	 * To allow this to work better, we send it whether we want broadcast	 * packets or not.  ARP and DHCP both need Broadcast, Bootp and tftp	 * don't.  This will make bootp really, really quick and same with	 * tftp.  It also makes tftp quick because it drops the packets on	 * the floor.  Remember that we must honour ARP requests at all times	 * because the host's ARP cache might be invalidated at any time.	 *	 * If we want even more performance, we should do this in 	 * read_mmu_data however, that is not currently done that way because	 * it is not clean.	 */	if (!bcast_enable)	{		if ((data[0]== 0xFF) && (data[1] == 0xFF) &&		    (data[2] == 0xFF) && (data[3]== 0xFF) &&		    (data[4] == 0xFF) && (data[5] == 0xFF) &&                    (data[ETHER_TYPE_OFFSET] != (ETHER_TYPE_ARP & 0xff) ||                     data[ETHER_TYPE_OFFSET+1] != ETHER_TYPE_ARP >> 8))		{                        DEBUG_3 ("Dropping b'cast RX\r\n");			if (retry++ > MAX_RX_RETRY)			{				return 0;			}			else			{				goto restart_rx;			}		}	}        // There seems to be a bug somewhere that causes the occasional         // packet we transmit to show up here as an incoming packet.        // Until we figure out why, detect those packets and throw them away.        SETUP_BANK(BANK_IAR);        if ((REG16(OFFSET_IAR01) == *(u16 *)(data + ETHER_SRC_OFFSET)) &&            (REG16(OFFSET_IAR23) == *(u16 *)(data + ETHER_SRC_OFFSET + 2)) &&            (REG16(OFFSET_IAR45) == *(u16 *)(data + ETHER_SRC_OFFSET + 4)))        {            DEBUG_2("Ignoring bogus received packet from myself\r\n");            return 0;        }        DEBUG_4 ("Rx OK\r\n");	return 1;} // End of rx_packet_ethernet////////////////////////////////////////////////////////////////////////////////// read_mac_ethernet// PURPOSE: Reads the MAC address.// PARAMS:  (OUT) u16 * macaddr - An array to return the MAC address.// RETURNS: 1 for success, 0 for failure.////////////////////////////////////////////////////////////////////////////////int read_mac_ethernet(u16 *macaddr, unsigned short num){    u16 mac_size=sizeof(short) * 3;#ifdef TAGGED_EEPROM    char tag[7];    // Try to read the tagged format MAC address.  If that fails (likely    // because the EEPROM isn't in tagged format) fall back to the old format.    if (check_eeprom_header())    {        itc_strcpy(tag, "MACADx");        tag[5] = num + '0';        if (eeprom_get_item(tag, sizeof(tag)-1, (u8 *)macaddr, &mac_size) <= 0)        {            DEBUG_3("Could not find EEPROM tag %s\r\n", tag);            return 0;        }        return 1;    }    // If the EEPROM isn't in tagged format yet, fall through to old-style    // reading routine (this is needed in order to read old addresses in    // order to upgrade the EEPROM format).#endif    // Read the MAC address from the old-style fixed location in EEPROM    // THIS IS OBSOLETE but needed for reading an old-style MAC address    return read_data_eeprom (EEPROM_MAC_ADDR + (num * mac_size),                              (unsigned char*)macaddr, &mac_size);} // End of read_mac_ethernet////////////////////////////////////////////////////////////////////////////////// write_mac_ethernet// PURPOSE: Writes a new MAC address.// PARAMS:  (IN) u16 * macaddr - An array containing the new MAC address.// RETURNS: 1 for success, 0 for failure.////////////////////////////////////////////////////////////////////////////////int write_mac_ethernet(u16 *macaddr, unsigned short num){    u16 mac_size=sizeof(short) * 3;#ifdef TAGGED_EEPROM    char tag[7];    itc_strcpy(tag, "MACADx");    tag[5] = num + '0';    if (eeprom_write_item(tag, sizeof(tag)-1, (u8 *)macaddr, mac_size) < 0)    {        ERROR("Could not write to EEPROM\r\n");        return 0;    }    return 1;#else    // Write the MAC address into the old-style fixed location in EEPROM    // THIS IS OBSOLETE!    return write_data_eeprom (EEPROM_MAC_ADDR + (num * mac_size),                              (unsigned char*)macaddr,	&mac_size);#endif} // End of write_mac_ethernet/* * Here starts local functions */static int probe_smsc91c111 (unsigned int *address){	unsigned short data;	SETUP_BANK(BANK_BSR);	READ_REG16(OFFSET_BSR, data);		if ((data & 0xff00) == BSR_UNIQUE)	{		itc_printf ("SMSC LAN91C111 Found at Address 0x%x\r\n",				(unsigned int) address);#if DEBUG_LEVEL >= 2		SETUP_BANK(BANK_RR);		READ_REG16(OFFSET_RR, data);		/*		 * Print out the Chip ID and Revision		 */		itc_printf ("SMSC Chip ID: 0x%x\r\n", ((data >> 4) & 0xF));		itc_printf ("SMSC Chip Revision: 0x%x\r\n", (data & 0xF));#endif		return 1;	}		return 0;} // End of probe_smsc91c111/* * NOTES: * 	When you write data to the SMSC the first 16 bits must be status * 	bytes (0's are good) and the second 16 bits is suppose to be the * 	size of the ethernet frame. * * 	The size of the ethernet frame should be the size of the data + 6 * 	because the size should include the 4 bytes (status and size) and * 	2 bytes for the trailer (described later).  Also, the SMSC always * 	ignores ODD counts (you send it 11 bytes it reads it as 10 bytes.) * * 	The trailer is how the SMSC figures out if you are sending an ODD * 	number of bytes or not.  The trailer is the last 2 bytes of data. * 	If the second byte in the trailer has bit 5 set then the first * 	byte in the trailer in a valid byte and should be included in the * 	transmission, but if bit 5 in the trailer is 0 then the first byte * 	in the trailer is just a pad and is ignored. * * 	Also note that the auto-increment only works in 32-bit mode, so * 	all data is re-aligned on the fly if its not 32-bit aligned already. */static int write_mmu_data (unsigned char packet_number, unsigned char *data, 		unsigned int data_size){	unsigned short pointer_offset;	unsigned int *data32=NULL, _temp32;	unsigned short *data16=NULL;	unsigned short _temp;	int counter,i;	unsigned int alignment, leftovers;	if (data_size > ((1 << 11) - 1))		return 0;	/*	 * We set up the pointer register to auto-increment.  This is the	 * fastest way to do it.	 */		SETUP_BANK(BANK_PR);	counter=MAX_PR_COUNTER;	do 	{		READ_REG16(OFFSET_PR, _temp);	} while ((_temp & BIT_PR_NOTEMPTY) && --counter);        if (!counter)        {                ERROR("TX FIFO not empty\r\n");        }	WRITE_REG16(OFFSET_PR, BIT_PR_AUTO_INC);	SETUP_BANK(BANK_DR);	REG32(OFFSET_DR) = ((data_size) + 6) << 16;	/*	 * Leftovers has 2 purposes, to figure out our alignment, and send the	 * remainder of the data at the end.	 */	leftovers = ((unsigned int)data % 4);	if (leftovers == 0)	{		alignment = 4;		data32 = (unsigned int *)data;	} else if (leftovers == 2)	{		alignment = 2;		data16 = (unsigned short *)data;	} else	{		alignment = 1;	}	/*	 * This was changed when it became apparent that auto-increment may	 * not have been working right in the 16 and 8 bit write cases.  If	 * you know it works, this can be redone so that the leftovers	 * gets data_size % alignment and changes are done in the respective	 * if statements below (so one REG8 or REG16 is done).	 *	 * Order was right, but I saw the MMU increment 32 bits after a 16 bit	 * access.  (FFEEDDCC) Would become (FFEE0000 DDCC0000).	 */	leftovers = (data_size % 4);	for (pointer_offset=0;pointer_offset < (data_size - leftovers);		pointer_offset += 4)	{		if (alignment == 4)		{			REG32(OFFSET_DR) = data32[pointer_offset/4];		} else if (alignment == 2)		{			_temp32 = data16[pointer_offset/2];			_temp32 |= data16[pointer_offset/2 + 1] << 16;			REG32(OFFSET_DR) = _temp32;		} else		{			_temp32 = data[pointer_offset];			_temp32 |= data[pointer_offset + 1] << 8;			_temp32 |= data[pointer_offset + 2] << 16;			_temp32 |= data[pointer_offset + 3] << 24;			REG32(OFFSET_DR) = _temp32;		}	}	/*	 * Here we send out the remaining bytes and setup the ODD Byte if	 * we have to.	 */	if (leftovers)	{		SETUP_BANK(BANK_PR);                counter=MAX_PR_COUNTER;		do 		{			READ_REG16(OFFSET_PR, _temp);		} while ((_temp & BIT_PR_NOTEMPTY) && --counter);                if (!counter)                {                        ERROR("TX FIFO not empty, but was\r\n");                }		/*		 * This is necessary as the pointer offset for the DR		 * is different than our data pointer.  Don't forget that		 * the first 32-bit word in the DR is the size and status		 */		WRITE_REG16(OFFSET_PR, pointer_offset + 4);			_temp32 = 0;		SETUP_BANK(BANK_DR);		for (i=0;i<leftovers;i++)		{			_temp32 |= data[pointer_offset + i] << (i*8);		}		if ((data_size & 1) == 1)		{			/*			 * We have an odd number of bytes			 */			_temp32 |= 0x20 << (i*8);					}		REG32(OFFSET_DR) = _temp32;	} 	return 1;} // End of write_mmu_data/* * Apparently, the SMSC has difficulty with the ODD Byte on receive if you * get one that is Rev 0.  Although, there is not documentation on this on * the SMSC Website (Errata could not be found) the Linux Driver does this. * * Also, it only hurts if the upper-levels are unable to figure out that * the size is one larger, so the Revision Register (Chip ID and Rev) are * checked and if the appropriate Rev and Chip ID is found, the ODD Byte * is read regardless of the status. * * Chip ID == 9 and Rev 0 apparently is the problem chip. * * Additionally, the auto-increment does not work for anything other than * 32-bit accesses (see write_mmu_data comment for more info) */static int read_mmu_data (unsigned char *packet_number, unsigned char *data, 		unsigned short *data_size){	unsigned short pointer_offset;	unsigned short size;	unsigned int *data32, _temp32, data_count;	int counter;	unsigned short *data16;	unsigned short _temp;	int leftovers,i;	if (*data_size > ((1 << 11) -1))	{		ERROR("%s: Data buffer > max allowable rx packet\r\n",		      __FUNCTION__);	}	/*	 * Setup the pointer register to auto-increment our addresses so	 * that we don't have to worry about it.  This should not be a big	 * deal on hardware that works	 */		SETUP_BANK(BANK_PR);	counter=MAX_PR_COUNTER;	do	{		READ_REG16(OFFSET_PR, _temp);	} while ((_temp & BIT_PR_NOTEMPTY) && --counter);	WRITE_REG16(OFFSET_PR, BIT_PR_RCV | BIT_PR_READ | BIT_PR_AUTO_INC);	SETUP_BANK(BANK_DR);	_temp32 = REG32(OFFSET_DR);	//stat = _temp32 & 0xFFFF;	size = ((_temp32 >> 16) & 0x7FF);	// Size includes the status, byte count and control words	// Ignore the ODD bit for now and read the extra odd byte regardless.	data_count = size - 6 + 1;

⌨️ 快捷键说明

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