static void mdio_cycle(struct qemu_mdio *bus) { bus->cnt++; D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); #if 0 if (bus->mdc) printf("%d", bus->mdio); #endif switch (bus->state) { case PREAMBLE: if (bus->mdc) { if (bus->cnt >= (32 * 2) && !bus->mdio) { bus->cnt = 0; bus->state = SOF; bus->data = 0; } } break; case SOF: if (bus->mdc) { if (bus->mdio != 1) printf("WARNING: no SOF\n"); if (bus->cnt == 1*2) { bus->cnt = 0; bus->opc = 0; bus->state = OPC; } } break; case OPC: if (bus->mdc) { bus->opc <<= 1; bus->opc |= bus->mdio & 1; if (bus->cnt == 2*2) { bus->cnt = 0; bus->addr = 0; bus->state = ADDR; } } break; case ADDR: if (bus->mdc) { bus->addr <<= 1; bus->addr |= bus->mdio & 1; if (bus->cnt == 5*2) { bus->cnt = 0; bus->req = 0; bus->state = REQ; } } break; case REQ: if (bus->mdc) { bus->req <<= 1; bus->req |= bus->mdio & 1; if (bus->cnt == 5*2) { bus->cnt = 0; bus->state = TURNAROUND; } } break; case TURNAROUND: if (bus->mdc && bus->cnt == 2*2) { bus->mdio = 0; bus->cnt = 0; if (bus->opc == 2) { bus->drive = 1; mdio_read_req(bus); bus->mdio = bus->data & 1; } bus->state = DATA; } break; case DATA: if (!bus->mdc) { if (bus->drive) { bus->mdio = !!(bus->data & (1 << 15)); bus->data <<= 1; } } else { if (!bus->drive) { bus->data <<= 1; bus->data |= bus->mdio; } if (bus->cnt == 16 * 2) { bus->cnt = 0; bus->state = PREAMBLE; if (!bus->drive) mdio_write_req(bus); bus->drive = 0; } } break; default: break; } }
static void eth_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct xlx_ethlite *s = opaque; unsigned int base = 0; uint32_t value = val64; addr >>= 2; switch (addr) { case R_TX_CTRL0: case R_TX_CTRL1: if (addr == R_TX_CTRL1) base = 0x800 / 4; D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", __func__, addr * 4, value)); if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { qemu_send_packet(qemu_get_queue(s->nic), (void *) &s->regs[base], s->regs[base + R_TX_LEN0]); D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0])); if (s->regs[base + R_TX_CTRL0] & CTRL_I) eth_pulse_irq(s); } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) { memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6); if (s->regs[base + R_TX_CTRL0] & CTRL_I) eth_pulse_irq(s); } /* We are fast and get ready pretty much immediately so we actually never flip the S nor P bits to one. */ s->regs[addr] = value & ~(CTRL_P | CTRL_S); break; /* Keep these native. */ case R_RX_CTRL0: case R_RX_CTRL1: if (!(value & CTRL_S)) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } case R_TX_LEN0: case R_TX_LEN1: case R_TX_GIE0: D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", __func__, addr * 4, value)); s->regs[addr] = value; break; case R_MDIOCTRL: if (((unsigned int)value & R_MDIOCTRL_MDIOSTS_MASK) != 0) { struct TEMAC *t = &s->TEMAC; unsigned int op = s->regs[R_MDIOADDR] & R_MDIOADDR_OP_MASK; unsigned int phyaddr = (s->regs[R_MDIOADDR] & R_MDIOADDR_PHYADR_MASK) >> R_MDIOADDR_PHYADR_SHIFT; unsigned int regaddr = s->regs[R_MDIOADDR] & R_MDIOADDR_REGADR_MASK; if (op) { /* read PHY registers */ s->regs[R_MDIORD] = mdio_read_req( &t->mdio_bus, phyaddr, regaddr); } else { /* write PHY registers */ mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->regs[R_MDIOWR]); } } s->regs[addr] = value; default: s->regs[addr] = tswap32(value); break; } }