ETRAX: Add support for the ethernet receivers dest addr filters.
* Support the station address filters MA0 and MA1. * Model the group address bloom filter. * Indentation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4487 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									57e49b4074
								
							
						
					
					
						commit
						f6953f1345
					
				
							
								
								
									
										123
									
								
								hw/etraxfs_eth.c
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								hw/etraxfs_eth.c
									
									
									
									
									
								
							@ -285,8 +285,18 @@ static void mdio_cycle(struct qemu_mdio *bus)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* ETRAX-FS Ethernet MAC block starts here.  */
 | 
					/* ETRAX-FS Ethernet MAC block starts here.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define R_STAT            0x2c
 | 
					#define RW_MA0_LO	  0x00
 | 
				
			||||||
 | 
					#define RW_MA0_HI	  0x04
 | 
				
			||||||
 | 
					#define RW_MA1_LO	  0x08
 | 
				
			||||||
 | 
					#define RW_MA1_HI	  0x0c
 | 
				
			||||||
 | 
					#define RW_GA_LO	  0x10
 | 
				
			||||||
 | 
					#define RW_GA_HI	  0x14
 | 
				
			||||||
 | 
					#define RW_GEN_CTRL	  0x18
 | 
				
			||||||
 | 
					#define RW_REC_CTRL	  0x1c
 | 
				
			||||||
 | 
					#define RW_TR_CTRL	  0x20
 | 
				
			||||||
 | 
					#define RW_CLR_ERR	  0x24
 | 
				
			||||||
#define RW_MGM_CTRL	  0x28
 | 
					#define RW_MGM_CTRL	  0x28
 | 
				
			||||||
 | 
					#define R_STAT		  0x2c
 | 
				
			||||||
#define FS_ETH_MAX_REGS	  0x5c
 | 
					#define FS_ETH_MAX_REGS	  0x5c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct fs_eth
 | 
					struct fs_eth
 | 
				
			||||||
@ -295,9 +305,10 @@ struct fs_eth
 | 
				
			|||||||
	qemu_irq *irq;
 | 
						qemu_irq *irq;
 | 
				
			||||||
	target_phys_addr_t base;
 | 
						target_phys_addr_t base;
 | 
				
			||||||
	VLANClientState *vc;
 | 
						VLANClientState *vc;
 | 
				
			||||||
	uint8_t macaddr[6];
 | 
					 | 
				
			||||||
	int ethregs;
 | 
						int ethregs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Two addrs in the filter.  */
 | 
				
			||||||
 | 
						uint8_t macaddr[2][6];
 | 
				
			||||||
	uint32_t regs[FS_ETH_MAX_REGS];
 | 
						uint32_t regs[FS_ETH_MAX_REGS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned char rx_fifo[1536];
 | 
						unsigned char rx_fifo[1536];
 | 
				
			||||||
@ -352,6 +363,30 @@ eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
 | 
				
			|||||||
		  addr, env->pc);
 | 
							  addr, env->pc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void eth_update_ma(struct fs_eth *eth, int ma)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int reg;
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ma &= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = RW_MA0_LO;
 | 
				
			||||||
 | 
						if (ma)
 | 
				
			||||||
 | 
							reg = RW_MA1_LO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						eth->macaddr[ma][i++] = eth->regs[reg];
 | 
				
			||||||
 | 
						eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
 | 
				
			||||||
 | 
						eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
 | 
				
			||||||
 | 
						eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
 | 
				
			||||||
 | 
						eth->macaddr[ma][i++] = eth->regs[reg + 4];
 | 
				
			||||||
 | 
						eth->macaddr[ma][i++] = eth->regs[reg + 4] >> 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
 | 
				
			||||||
 | 
							 eth->macaddr[ma][0], eth->macaddr[ma][1],
 | 
				
			||||||
 | 
							 eth->macaddr[ma][2], eth->macaddr[ma][3],
 | 
				
			||||||
 | 
							 eth->macaddr[ma][4], eth->macaddr[ma][5]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 | 
					eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -362,6 +397,23 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 | 
				
			|||||||
	addr -= eth->base;
 | 
						addr -= eth->base;
 | 
				
			||||||
	switch (addr)
 | 
						switch (addr)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							case RW_MA0_LO:
 | 
				
			||||||
 | 
								eth->regs[addr] = value;
 | 
				
			||||||
 | 
								eth_update_ma(eth, 0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case RW_MA0_HI:
 | 
				
			||||||
 | 
								eth->regs[addr] = value;
 | 
				
			||||||
 | 
								eth_update_ma(eth, 0);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case RW_MA1_LO:
 | 
				
			||||||
 | 
								eth->regs[addr] = value;
 | 
				
			||||||
 | 
								eth_update_ma(eth, 1);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case RW_MA1_HI:
 | 
				
			||||||
 | 
								eth->regs[addr] = value;
 | 
				
			||||||
 | 
								eth_update_ma(eth, 1);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case RW_MGM_CTRL:
 | 
							case RW_MGM_CTRL:
 | 
				
			||||||
			/* Attach an MDIO/PHY abstraction.  */
 | 
								/* Attach an MDIO/PHY abstraction.  */
 | 
				
			||||||
			if (value & 2)
 | 
								if (value & 2)
 | 
				
			||||||
@ -372,12 +424,57 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 | 
				
			|||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
 | 
								eth->regs[addr] = value;
 | 
				
			||||||
			printf ("%s %x %x pc=%x\n",
 | 
								printf ("%s %x %x pc=%x\n",
 | 
				
			||||||
				__func__, addr, value, env->pc);
 | 
									__func__, addr, value, env->pc);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
 | 
				
			||||||
 | 
					   filter dropping group addresses we have not joined.	The filter has 64
 | 
				
			||||||
 | 
					   bits (m). The has function is a simple nible xor of the group addr.	*/
 | 
				
			||||||
 | 
					static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int hsh;
 | 
				
			||||||
 | 
						int m_individual = eth->regs[RW_REC_CTRL] & 4;
 | 
				
			||||||
 | 
						int match;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First bit on the wire of a MAC address signals multicast or
 | 
				
			||||||
 | 
						   physical address.  */
 | 
				
			||||||
 | 
						if (!m_individual && !sa[0] & 1)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Calculate the hash index for the GA registers. */
 | 
				
			||||||
 | 
						hsh = 0;
 | 
				
			||||||
 | 
						hsh ^= (*sa) & 0x3f;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) >> 6) & 0x03;
 | 
				
			||||||
 | 
						++sa;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) << 2) & 0x03c;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) >> 4) & 0xf;
 | 
				
			||||||
 | 
						++sa;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) << 4) & 0x30;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) >> 2) & 0x3f;
 | 
				
			||||||
 | 
						++sa;
 | 
				
			||||||
 | 
						hsh ^= (*sa) & 0x3f;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) >> 6) & 0x03;
 | 
				
			||||||
 | 
						++sa;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) << 2) & 0x03c;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) >> 4) & 0xf;
 | 
				
			||||||
 | 
						++sa;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) << 4) & 0x30;
 | 
				
			||||||
 | 
						hsh ^= ((*sa) >> 2) & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hsh &= 63;
 | 
				
			||||||
 | 
						if (hsh > 31)
 | 
				
			||||||
 | 
							match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							match = eth->regs[RW_GA_LO] & (1 << hsh);
 | 
				
			||||||
 | 
						D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
 | 
				
			||||||
 | 
							 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
 | 
				
			||||||
 | 
						return match;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int eth_can_receive(void *opaque)
 | 
					static int eth_can_receive(void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct fs_eth *eth = opaque;
 | 
						struct fs_eth *eth = opaque;
 | 
				
			||||||
@ -393,9 +490,30 @@ static int eth_can_receive(void *opaque)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void eth_receive(void *opaque, const uint8_t *buf, int size)
 | 
					static void eth_receive(void *opaque, const uint8_t *buf, int size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 | 
				
			||||||
	struct fs_eth *eth = opaque;
 | 
						struct fs_eth *eth = opaque;
 | 
				
			||||||
 | 
						int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
 | 
				
			||||||
 | 
						int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
 | 
				
			||||||
 | 
						int r_bcast = eth->regs[RW_REC_CTRL] & 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (size < 12)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
 | 
				
			||||||
 | 
							 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
 | 
				
			||||||
 | 
							 use_ma0, use_ma1, r_bcast));
 | 
				
			||||||
 | 
						       
 | 
				
			||||||
 | 
						/* Does the frame get through the address filters?  */
 | 
				
			||||||
 | 
						if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
 | 
				
			||||||
 | 
						    && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
 | 
				
			||||||
 | 
						    && (!r_bcast || memcmp(buf, sa_bcast, 6))
 | 
				
			||||||
 | 
						    && !eth_match_groupaddr(eth, buf))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (size > sizeof(eth->rx_fifo)) {
 | 
						if (size > sizeof(eth->rx_fifo)) {
 | 
				
			||||||
		/* TODO: signal error.	*/
 | 
							/* TODO: signal error.	*/
 | 
				
			||||||
 | 
						} else if (eth->rx_fifo_len) {
 | 
				
			||||||
 | 
							/* FIFO overrun.  */
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		memcpy(eth->rx_fifo, buf, size);
 | 
							memcpy(eth->rx_fifo, buf, size);
 | 
				
			||||||
		/* +4, HW passes the CRC to sw.	 */
 | 
							/* +4, HW passes the CRC to sw.	 */
 | 
				
			||||||
@ -471,7 +589,6 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env,
 | 
				
			|||||||
	eth->irq = irq;
 | 
						eth->irq = irq;
 | 
				
			||||||
	eth->dma_out = dma;
 | 
						eth->dma_out = dma;
 | 
				
			||||||
	eth->dma_in = dma + 1;
 | 
						eth->dma_in = dma + 1;
 | 
				
			||||||
	memcpy(eth->macaddr, nd->macaddr, 6);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Connect the phy.  */
 | 
						/* Connect the phy.  */
 | 
				
			||||||
	tdk_init(ð->phy);
 | 
						tdk_init(ð->phy);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user