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); | ... | ... |