Commit c64882682db39f594bec1cec5a56e943f58220f2
1 parent
9d926598
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
Showing
1 changed file
with
51 additions
and
4 deletions
hw/etraxfs_eth.c
| ... | ... | @@ -30,6 +30,12 @@ |
| 30 | 30 | |
| 31 | 31 | #define D(x) |
| 32 | 32 | |
| 33 | +/* Advertisement control register. */ | |
| 34 | +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ | |
| 35 | +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ | |
| 36 | +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ | |
| 37 | +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ | |
| 38 | + | |
| 33 | 39 | /* |
| 34 | 40 | * The MDIO extensions in the TDK PHY model were reversed engineered from the |
| 35 | 41 | * linux driver (PHYID and Diagnostics reg). |
| ... | ... | @@ -78,9 +84,12 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) |
| 78 | 84 | int speed_100 = 0; |
| 79 | 85 | |
| 80 | 86 | /* Are we advertising 100 half or 100 duplex ? */ |
| 81 | - speed_100 = !!(phy->regs[4] & 0x180); | |
| 87 | + speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); | |
| 88 | + speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); | |
| 89 | + | |
| 82 | 90 | /* Are we advertising 10 duplex or 100 duplex ? */ |
| 83 | - duplex = !!(phy->regs[4] & 0x180); | |
| 91 | + duplex = !!(phy->regs[4] & ADVERTISE_100FULL); | |
| 92 | + duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); | |
| 84 | 93 | r = (speed_100 << 10) | (duplex << 11); |
| 85 | 94 | } |
| 86 | 95 | break; |
| ... | ... | @@ -322,10 +331,40 @@ struct fs_eth |
| 322 | 331 | |
| 323 | 332 | /* MDIO bus. */ |
| 324 | 333 | struct qemu_mdio mdio_bus; |
| 334 | + unsigned int phyaddr; | |
| 335 | + int duplex_mismatch; | |
| 336 | + | |
| 325 | 337 | /* PHY. */ |
| 326 | 338 | struct qemu_phy phy; |
| 327 | 339 | }; |
| 328 | 340 | |
| 341 | +static void eth_validate_duplex(struct fs_eth *eth) | |
| 342 | +{ | |
| 343 | + struct qemu_phy *phy; | |
| 344 | + unsigned int phy_duplex; | |
| 345 | + unsigned int mac_duplex; | |
| 346 | + int new_mm = 0; | |
| 347 | + | |
| 348 | + phy = eth->mdio_bus.devs[eth->phyaddr]; | |
| 349 | + phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); | |
| 350 | + mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); | |
| 351 | + | |
| 352 | + if (mac_duplex != phy_duplex) | |
| 353 | + new_mm = 1; | |
| 354 | + | |
| 355 | + if (eth->regs[RW_GEN_CTRL] & 1) { | |
| 356 | + if (new_mm != eth->duplex_mismatch) { | |
| 357 | + if (new_mm) | |
| 358 | + printf("HW: WARNING " | |
| 359 | + "ETH duplex mismatch MAC=%d PHY=%d\n", | |
| 360 | + mac_duplex, phy_duplex); | |
| 361 | + else | |
| 362 | + printf("HW: ETH duplex ok.\n"); | |
| 363 | + } | |
| 364 | + eth->duplex_mismatch = new_mm; | |
| 365 | + } | |
| 366 | +} | |
| 367 | + | |
| 329 | 368 | static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr) |
| 330 | 369 | { |
| 331 | 370 | struct fs_eth *eth = opaque; |
| ... | ... | @@ -418,11 +457,18 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
| 418 | 457 | /* Attach an MDIO/PHY abstraction. */ |
| 419 | 458 | if (value & 2) |
| 420 | 459 | eth->mdio_bus.mdio = value & 1; |
| 421 | - if (eth->mdio_bus.mdc != (value & 4)) | |
| 460 | + if (eth->mdio_bus.mdc != (value & 4)) { | |
| 422 | 461 | mdio_cycle(ð->mdio_bus); |
| 462 | + eth_validate_duplex(eth); | |
| 463 | + } | |
| 423 | 464 | eth->mdio_bus.mdc = !!(value & 4); |
| 424 | 465 | break; |
| 425 | 466 | |
| 467 | + case RW_REC_CTRL: | |
| 468 | + eth->regs[addr] = value; | |
| 469 | + eth_validate_duplex(eth); | |
| 470 | + break; | |
| 471 | + | |
| 426 | 472 | default: |
| 427 | 473 | eth->regs[addr] = value; |
| 428 | 474 | D(printf ("%s %x %x\n", |
| ... | ... | @@ -591,8 +637,9 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, |
| 591 | 637 | eth->dma_in = dma + 1; |
| 592 | 638 | |
| 593 | 639 | /* Connect the phy. */ |
| 640 | + eth->phyaddr = 1; | |
| 594 | 641 | tdk_init(ð->phy); |
| 595 | - mdio_attach(ð->mdio_bus, ð->phy, 0x1); | |
| 642 | + mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr); | |
| 596 | 643 | |
| 597 | 644 | eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth); |
| 598 | 645 | cpu_register_physical_memory (base, 0x5c, eth->ethregs); | ... | ... |