ETRAX-FS: Correct ethernet PHY diagnostics register reads.
* Correct ethernet PHY diagnostics register reads. * Add friendly names for the speed/duplex fields. * Report duplex mismatches between MAC and PHY. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5300 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									9d92659858
								
							
						
					
					
						commit
						c64882682d
					
				@ -30,6 +30,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define D(x)
 | 
					#define D(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Advertisement control register. */
 | 
				
			||||||
 | 
					#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
 | 
				
			||||||
 | 
					#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
 | 
				
			||||||
 | 
					#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
 | 
				
			||||||
 | 
					#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/* 
 | 
				
			||||||
 * The MDIO extensions in the TDK PHY model were reversed engineered from the 
 | 
					 * The MDIO extensions in the TDK PHY model were reversed engineered from the 
 | 
				
			||||||
 * linux driver (PHYID and Diagnostics reg).
 | 
					 * linux driver (PHYID and Diagnostics reg).
 | 
				
			||||||
@ -78,9 +84,12 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
 | 
				
			|||||||
			int speed_100 = 0;
 | 
								int speed_100 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Are we advertising 100 half or 100 duplex ? */
 | 
								/* Are we advertising 100 half or 100 duplex ? */
 | 
				
			||||||
			speed_100 = !!(phy->regs[4] & 0x180);
 | 
								speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
 | 
				
			||||||
 | 
								speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Are we advertising 10 duplex or 100 duplex ? */
 | 
								/* Are we advertising 10 duplex or 100 duplex ? */
 | 
				
			||||||
			duplex = !!(phy->regs[4] & 0x180);
 | 
								duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
 | 
				
			||||||
 | 
								duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
 | 
				
			||||||
			r = (speed_100 << 10) | (duplex << 11);
 | 
								r = (speed_100 << 10) | (duplex << 11);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@ -322,10 +331,40 @@ struct fs_eth
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* MDIO bus.  */
 | 
						/* MDIO bus.  */
 | 
				
			||||||
	struct qemu_mdio mdio_bus;
 | 
						struct qemu_mdio mdio_bus;
 | 
				
			||||||
 | 
						unsigned int phyaddr;
 | 
				
			||||||
 | 
						int duplex_mismatch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* PHY.	 */
 | 
						/* PHY.	 */
 | 
				
			||||||
	struct qemu_phy phy;
 | 
						struct qemu_phy phy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void eth_validate_duplex(struct fs_eth *eth)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct qemu_phy *phy;
 | 
				
			||||||
 | 
						unsigned int phy_duplex;
 | 
				
			||||||
 | 
						unsigned int mac_duplex;
 | 
				
			||||||
 | 
						int new_mm = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						phy = eth->mdio_bus.devs[eth->phyaddr];
 | 
				
			||||||
 | 
						phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
 | 
				
			||||||
 | 
						mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mac_duplex != phy_duplex)
 | 
				
			||||||
 | 
							new_mm = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (eth->regs[RW_GEN_CTRL] & 1) {
 | 
				
			||||||
 | 
							if (new_mm != eth->duplex_mismatch) {
 | 
				
			||||||
 | 
								if (new_mm)
 | 
				
			||||||
 | 
									printf("HW: WARNING "
 | 
				
			||||||
 | 
									       "ETH duplex mismatch MAC=%d PHY=%d\n",
 | 
				
			||||||
 | 
									       mac_duplex, phy_duplex);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									printf("HW: ETH duplex ok.\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							eth->duplex_mismatch = new_mm;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
 | 
					static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct fs_eth *eth = opaque;
 | 
						struct fs_eth *eth = opaque;
 | 
				
			||||||
@ -418,11 +457,18 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 | 
				
			|||||||
			/* Attach an MDIO/PHY abstraction.  */
 | 
								/* Attach an MDIO/PHY abstraction.  */
 | 
				
			||||||
			if (value & 2)
 | 
								if (value & 2)
 | 
				
			||||||
				eth->mdio_bus.mdio = value & 1;
 | 
									eth->mdio_bus.mdio = value & 1;
 | 
				
			||||||
			if (eth->mdio_bus.mdc != (value & 4))
 | 
								if (eth->mdio_bus.mdc != (value & 4)) {
 | 
				
			||||||
				mdio_cycle(ð->mdio_bus);
 | 
									mdio_cycle(ð->mdio_bus);
 | 
				
			||||||
 | 
									eth_validate_duplex(eth);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			eth->mdio_bus.mdc = !!(value & 4);
 | 
								eth->mdio_bus.mdc = !!(value & 4);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case RW_REC_CTRL:
 | 
				
			||||||
 | 
								eth->regs[addr] = value;
 | 
				
			||||||
 | 
								eth_validate_duplex(eth);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			eth->regs[addr] = value;
 | 
								eth->regs[addr] = value;
 | 
				
			||||||
			D(printf ("%s %x %x\n",
 | 
								D(printf ("%s %x %x\n",
 | 
				
			||||||
@ -591,8 +637,9 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env,
 | 
				
			|||||||
	eth->dma_in = dma + 1;
 | 
						eth->dma_in = dma + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Connect the phy.  */
 | 
						/* Connect the phy.  */
 | 
				
			||||||
 | 
						eth->phyaddr = 1;
 | 
				
			||||||
	tdk_init(ð->phy);
 | 
						tdk_init(ð->phy);
 | 
				
			||||||
	mdio_attach(ð->mdio_bus, ð->phy, 0x1);
 | 
						mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
 | 
						eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
 | 
				
			||||||
	cpu_register_physical_memory (base, 0x5c, eth->ethregs);
 | 
						cpu_register_physical_memory (base, 0x5c, eth->ethregs);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user