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,6 +30,12 @@ | ||
30 | 30 | ||
31 | #define D(x) | 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 | * The MDIO extensions in the TDK PHY model were reversed engineered from the | 40 | * The MDIO extensions in the TDK PHY model were reversed engineered from the |
35 | * linux driver (PHYID and Diagnostics reg). | 41 | * linux driver (PHYID and Diagnostics reg). |
@@ -78,9 +84,12 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) | @@ -78,9 +84,12 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) | ||
78 | int speed_100 = 0; | 84 | int speed_100 = 0; |
79 | 85 | ||
80 | /* Are we advertising 100 half or 100 duplex ? */ | 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 | /* Are we advertising 10 duplex or 100 duplex ? */ | 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 | r = (speed_100 << 10) | (duplex << 11); | 93 | r = (speed_100 << 10) | (duplex << 11); |
85 | } | 94 | } |
86 | break; | 95 | break; |
@@ -322,10 +331,40 @@ struct fs_eth | @@ -322,10 +331,40 @@ struct fs_eth | ||
322 | 331 | ||
323 | /* MDIO bus. */ | 332 | /* MDIO bus. */ |
324 | struct qemu_mdio mdio_bus; | 333 | struct qemu_mdio mdio_bus; |
334 | + unsigned int phyaddr; | ||
335 | + int duplex_mismatch; | ||
336 | + | ||
325 | /* PHY. */ | 337 | /* PHY. */ |
326 | struct qemu_phy phy; | 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 | static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr) | 368 | static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr) |
330 | { | 369 | { |
331 | struct fs_eth *eth = opaque; | 370 | struct fs_eth *eth = opaque; |
@@ -418,11 +457,18 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | @@ -418,11 +457,18 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
418 | /* Attach an MDIO/PHY abstraction. */ | 457 | /* Attach an MDIO/PHY abstraction. */ |
419 | if (value & 2) | 458 | if (value & 2) |
420 | eth->mdio_bus.mdio = value & 1; | 459 | eth->mdio_bus.mdio = value & 1; |
421 | - if (eth->mdio_bus.mdc != (value & 4)) | 460 | + if (eth->mdio_bus.mdc != (value & 4)) { |
422 | mdio_cycle(ð->mdio_bus); | 461 | mdio_cycle(ð->mdio_bus); |
462 | + eth_validate_duplex(eth); | ||
463 | + } | ||
423 | eth->mdio_bus.mdc = !!(value & 4); | 464 | eth->mdio_bus.mdc = !!(value & 4); |
424 | break; | 465 | break; |
425 | 466 | ||
467 | + case RW_REC_CTRL: | ||
468 | + eth->regs[addr] = value; | ||
469 | + eth_validate_duplex(eth); | ||
470 | + break; | ||
471 | + | ||
426 | default: | 472 | default: |
427 | eth->regs[addr] = value; | 473 | eth->regs[addr] = value; |
428 | D(printf ("%s %x %x\n", | 474 | D(printf ("%s %x %x\n", |
@@ -591,8 +637,9 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | @@ -591,8 +637,9 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | ||
591 | eth->dma_in = dma + 1; | 637 | eth->dma_in = dma + 1; |
592 | 638 | ||
593 | /* Connect the phy. */ | 639 | /* Connect the phy. */ |
640 | + eth->phyaddr = 1; | ||
594 | tdk_init(ð->phy); | 641 | tdk_init(ð->phy); |
595 | - mdio_attach(ð->mdio_bus, ð->phy, 0x1); | 642 | + mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr); |
596 | 643 | ||
597 | eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth); | 644 | eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth); |
598 | cpu_register_physical_memory (base, 0x5c, eth->ethregs); | 645 | cpu_register_physical_memory (base, 0x5c, eth->ethregs); |