* [Qemu-devel] [PATCH V3 1/8] hw/etraxfs_eth: Eliminate checkpatch errors
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 2/8] hw/mdio: Generalize etraxfs MDIO bitbanging emulation Grant Likely
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
This is a trivial patch to harmonize the coding style on
hw/etraxfs_eth.c. This is in preparation to split off the bitbang mdio
code into a separate file.
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/etraxfs_eth.c | 922 +++++++++++++++++++++++++++---------------------------
1 file changed, 466 insertions(+), 456 deletions(-)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index ec23fa6..0b474c0 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -35,582 +35,592 @@
#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).
* TODO: Add friendly names for the register nums.
*/
struct qemu_phy
{
- uint32_t regs[32];
+ uint32_t regs[32];
- int link;
+ int link;
- unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
- void (*write)(struct qemu_phy *phy, unsigned int req,
- unsigned int data);
+ unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
+ void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
};
static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
{
- int regnum;
- unsigned r = 0;
-
- regnum = req & 0x1f;
-
- switch (regnum) {
- case 1:
- if (!phy->link)
- break;
- /* MR1. */
- /* Speeds and modes. */
- r |= (1 << 13) | (1 << 14);
- r |= (1 << 11) | (1 << 12);
- r |= (1 << 5); /* Autoneg complete. */
- r |= (1 << 3); /* Autoneg able. */
- r |= (1 << 2); /* link. */
- break;
- case 5:
- /* Link partner ability.
- We are kind; always agree with whatever best mode
- the guest advertises. */
- r = 1 << 14; /* Success. */
- /* Copy advertised modes. */
- r |= phy->regs[4] & (15 << 5);
- /* Autoneg support. */
- r |= 1;
- break;
- case 18:
- {
- /* Diagnostics reg. */
- int duplex = 0;
- int speed_100 = 0;
-
- if (!phy->link)
- break;
-
- /* Are we advertising 100 half or 100 duplex ? */
- speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
- speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
- /* Are we advertising 10 duplex or 100 duplex ? */
- duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
- duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
- r = (speed_100 << 10) | (duplex << 11);
- }
- break;
-
- default:
- r = phy->regs[regnum];
- break;
- }
- D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
- return r;
+ int regnum;
+ unsigned r = 0;
+
+ regnum = req & 0x1f;
+
+ switch (regnum) {
+ case 1:
+ if (!phy->link) {
+ break;
+ }
+ /* MR1. */
+ /* Speeds and modes. */
+ r |= (1 << 13) | (1 << 14);
+ r |= (1 << 11) | (1 << 12);
+ r |= (1 << 5); /* Autoneg complete. */
+ r |= (1 << 3); /* Autoneg able. */
+ r |= (1 << 2); /* link. */
+ break;
+ case 5:
+ /* Link partner ability.
+ We are kind; always agree with whatever best mode
+ the guest advertises. */
+ r = 1 << 14; /* Success. */
+ /* Copy advertised modes. */
+ r |= phy->regs[4] & (15 << 5);
+ /* Autoneg support. */
+ r |= 1;
+ break;
+ case 18:
+ {
+ /* Diagnostics reg. */
+ int duplex = 0;
+ int speed_100 = 0;
+
+ if (!phy->link) {
+ break;
+ }
+
+ /* Are we advertising 100 half or 100 duplex ? */
+ speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+ speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+ /* Are we advertising 10 duplex or 100 duplex ? */
+ duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+ duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+ r = (speed_100 << 10) | (duplex << 11);
+ }
+ break;
+
+ default:
+ r = phy->regs[regnum];
+ break;
+ }
+ D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
+ return r;
}
-static void
+static void
tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
{
- int regnum;
-
- regnum = req & 0x1f;
- D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
- switch (regnum) {
- default:
- phy->regs[regnum] = data;
- break;
- }
+ int regnum;
+
+ regnum = req & 0x1f;
+ D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+ switch (regnum) {
+ default:
+ phy->regs[regnum] = data;
+ break;
+ }
}
-static void
+static void
tdk_init(struct qemu_phy *phy)
{
- phy->regs[0] = 0x3100;
- /* PHY Id. */
- phy->regs[2] = 0x0300;
- phy->regs[3] = 0xe400;
- /* Autonegotiation advertisement reg. */
- phy->regs[4] = 0x01E1;
- phy->link = 1;
-
- phy->read = tdk_read;
- phy->write = tdk_write;
+ phy->regs[0] = 0x3100;
+ /* PHY Id. */
+ phy->regs[2] = 0x0300;
+ phy->regs[3] = 0xe400;
+ /* Autonegotiation advertisement reg. */
+ phy->regs[4] = 0x01E1;
+ phy->link = 1;
+
+ phy->read = tdk_read;
+ phy->write = tdk_write;
}
struct qemu_mdio
{
- /* bus. */
- int mdc;
- int mdio;
-
- /* decoder. */
- enum {
- PREAMBLE,
- SOF,
- OPC,
- ADDR,
- REQ,
- TURNAROUND,
- DATA
- } state;
- unsigned int drive;
-
- unsigned int cnt;
- unsigned int addr;
- unsigned int opc;
- unsigned int req;
- unsigned int data;
-
- struct qemu_phy *devs[32];
+ /* bus. */
+ int mdc;
+ int mdio;
+
+ /* decoder. */
+ enum {
+ PREAMBLE,
+ SOF,
+ OPC,
+ ADDR,
+ REQ,
+ TURNAROUND,
+ DATA
+ } state;
+ unsigned int drive;
+
+ unsigned int cnt;
+ unsigned int addr;
+ unsigned int opc;
+ unsigned int req;
+ unsigned int data;
+
+ struct qemu_phy *devs[32];
};
-static void
+static void
mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
{
- bus->devs[addr & 0x1f] = phy;
+ bus->devs[addr & 0x1f] = phy;
}
#ifdef USE_THIS_DEAD_CODE
-static void
+static void
mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
{
- bus->devs[addr & 0x1f] = NULL;
+ bus->devs[addr & 0x1f] = NULL;
}
#endif
static void mdio_read_req(struct qemu_mdio *bus)
{
- struct qemu_phy *phy;
-
- phy = bus->devs[bus->addr];
- if (phy && phy->read)
- bus->data = phy->read(phy, bus->req);
- else
- bus->data = 0xffff;
+ struct qemu_phy *phy;
+
+ phy = bus->devs[bus->addr];
+ if (phy && phy->read) {
+ bus->data = phy->read(phy, bus->req);
+ } else {
+ bus->data = 0xffff;
+ }
}
static void mdio_write_req(struct qemu_mdio *bus)
{
- struct qemu_phy *phy;
+ struct qemu_phy *phy;
- phy = bus->devs[bus->addr];
- if (phy && phy->write)
- phy->write(phy, bus->req, bus->data);
+ phy = bus->devs[bus->addr];
+ if (phy && phy->write) {
+ phy->write(phy, bus->req, bus->data);
+ }
}
static void mdio_cycle(struct qemu_mdio *bus)
{
- bus->cnt++;
+ 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));
+ 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);
+ 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;
- }
+ 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;
+ }
}
/* ETRAX-FS Ethernet MAC block starts here. */
-#define RW_MA0_LO 0x00
-#define RW_MA0_HI 0x01
-#define RW_MA1_LO 0x02
-#define RW_MA1_HI 0x03
-#define RW_GA_LO 0x04
-#define RW_GA_HI 0x05
-#define RW_GEN_CTRL 0x06
-#define RW_REC_CTRL 0x07
-#define RW_TR_CTRL 0x08
-#define RW_CLR_ERR 0x09
-#define RW_MGM_CTRL 0x0a
-#define R_STAT 0x0b
-#define FS_ETH_MAX_REGS 0x17
+#define RW_MA0_LO 0x00
+#define RW_MA0_HI 0x01
+#define RW_MA1_LO 0x02
+#define RW_MA1_HI 0x03
+#define RW_GA_LO 0x04
+#define RW_GA_HI 0x05
+#define RW_GEN_CTRL 0x06
+#define RW_REC_CTRL 0x07
+#define RW_TR_CTRL 0x08
+#define RW_CLR_ERR 0x09
+#define RW_MGM_CTRL 0x0a
+#define R_STAT 0x0b
+#define FS_ETH_MAX_REGS 0x17
struct fs_eth
{
- SysBusDevice busdev;
- MemoryRegion mmio;
- NICState *nic;
- NICConf conf;
-
- /* Two addrs in the filter. */
- uint8_t macaddr[2][6];
- uint32_t regs[FS_ETH_MAX_REGS];
-
- union {
- void *vdma_out;
- struct etraxfs_dma_client *dma_out;
- };
- union {
- void *vdma_in;
- struct etraxfs_dma_client *dma_in;
- };
-
- /* MDIO bus. */
- struct qemu_mdio mdio_bus;
- unsigned int phyaddr;
- int duplex_mismatch;
-
- /* PHY. */
- struct qemu_phy phy;
+ SysBusDevice busdev;
+ MemoryRegion mmio;
+ NICState *nic;
+ NICConf conf;
+
+ /* Two addrs in the filter. */
+ uint8_t macaddr[2][6];
+ uint32_t regs[FS_ETH_MAX_REGS];
+
+ union {
+ void *vdma_out;
+ struct etraxfs_dma_client *dma_out;
+ };
+ union {
+ void *vdma_in;
+ struct etraxfs_dma_client *dma_in;
+ };
+
+ /* MDIO bus. */
+ struct qemu_mdio mdio_bus;
+ unsigned int phyaddr;
+ int duplex_mismatch;
+
+ /* 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;
- }
+ 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 uint64_t
eth_read(void *opaque, hwaddr addr, unsigned int size)
{
- struct fs_eth *eth = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
-
- switch (addr) {
- case R_STAT:
- r = eth->mdio_bus.mdio & 1;
- break;
- default:
- r = eth->regs[addr];
- D(printf ("%s %x\n", __func__, addr * 4));
- break;
- }
- return r;
+ struct fs_eth *eth = opaque;
+ uint32_t r = 0;
+
+ addr >>= 2;
+
+ switch (addr) {
+ case R_STAT:
+ r = eth->mdio_bus.mdio & 1;
+ break;
+ default:
+ r = eth->regs[addr];
+ D(printf("%s %x\n", __func__, addr * 4));
+ break;
+ }
+ return r;
}
static void eth_update_ma(struct fs_eth *eth, int ma)
{
- int reg;
- int i = 0;
-
- ma &= 1;
-
- reg = RW_MA0_LO;
- if (ma)
- reg = RW_MA1_LO;
-
- eth->macaddr[ma][i++] = eth->regs[reg];
- eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
- eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
- eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
- eth->macaddr[ma][i++] = eth->regs[reg + 1];
- eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
-
- D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
- eth->macaddr[ma][0], eth->macaddr[ma][1],
- eth->macaddr[ma][2], eth->macaddr[ma][3],
- eth->macaddr[ma][4], eth->macaddr[ma][5]));
+ int reg;
+ int i = 0;
+
+ ma &= 1;
+
+ reg = RW_MA0_LO;
+ if (ma) {
+ reg = RW_MA1_LO;
+ }
+
+ eth->macaddr[ma][i++] = eth->regs[reg];
+ eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
+ eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
+ eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
+ eth->macaddr[ma][i++] = eth->regs[reg + 1];
+ eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
+
+ D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
+ eth->macaddr[ma][0], eth->macaddr[ma][1],
+ eth->macaddr[ma][2], eth->macaddr[ma][3],
+ eth->macaddr[ma][4], eth->macaddr[ma][5]));
}
static void
eth_write(void *opaque, hwaddr addr,
uint64_t val64, unsigned int size)
{
- struct fs_eth *eth = opaque;
- uint32_t value = val64;
-
- addr >>= 2;
- switch (addr)
- {
- case RW_MA0_LO:
- case RW_MA0_HI:
- eth->regs[addr] = value;
- eth_update_ma(eth, 0);
- break;
- case RW_MA1_LO:
- case RW_MA1_HI:
- eth->regs[addr] = value;
- eth_update_ma(eth, 1);
- break;
-
- case RW_MGM_CTRL:
- /* Attach an MDIO/PHY abstraction. */
- if (value & 2)
- eth->mdio_bus.mdio = value & 1;
- if (eth->mdio_bus.mdc != (value & 4)) {
- mdio_cycle(ð->mdio_bus);
- eth_validate_duplex(eth);
- }
- eth->mdio_bus.mdc = !!(value & 4);
- eth->regs[addr] = value;
- break;
-
- case RW_REC_CTRL:
- eth->regs[addr] = value;
- eth_validate_duplex(eth);
- break;
-
- default:
- eth->regs[addr] = value;
- D(printf ("%s %x %x\n",
- __func__, addr, value));
- break;
- }
+ struct fs_eth *eth = opaque;
+ uint32_t value = val64;
+
+ addr >>= 2;
+ switch (addr) {
+ case RW_MA0_LO:
+ case RW_MA0_HI:
+ eth->regs[addr] = value;
+ eth_update_ma(eth, 0);
+ break;
+ case RW_MA1_LO:
+ case RW_MA1_HI:
+ eth->regs[addr] = value;
+ eth_update_ma(eth, 1);
+ break;
+
+ case RW_MGM_CTRL:
+ /* Attach an MDIO/PHY abstraction. */
+ if (value & 2) {
+ eth->mdio_bus.mdio = value & 1;
+ }
+ if (eth->mdio_bus.mdc != (value & 4)) {
+ mdio_cycle(ð->mdio_bus);
+ eth_validate_duplex(eth);
+ }
+ eth->mdio_bus.mdc = !!(value & 4);
+ eth->regs[addr] = value;
+ break;
+
+ case RW_REC_CTRL:
+ eth->regs[addr] = value;
+ eth_validate_duplex(eth);
+ break;
+
+ default:
+ eth->regs[addr] = value;
+ D(printf("%s %x %x\n", __func__, addr, value));
+ break;
+ }
}
/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
- filter dropping group addresses we have not joined. The filter has 64
- bits (m). The has function is a simple nible xor of the group addr. */
+ filter dropping group addresses we have not joined. The filter has 64
+ bits (m). The has function is a simple nible xor of the group addr. */
static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
{
- unsigned int hsh;
- int m_individual = eth->regs[RW_REC_CTRL] & 4;
- int match;
-
- /* First bit on the wire of a MAC address signals multicast or
- physical address. */
- if (!m_individual && !(sa[0] & 1))
- return 0;
-
- /* Calculate the hash index for the GA registers. */
- hsh = 0;
- hsh ^= (*sa) & 0x3f;
- hsh ^= ((*sa) >> 6) & 0x03;
- ++sa;
- hsh ^= ((*sa) << 2) & 0x03c;
- hsh ^= ((*sa) >> 4) & 0xf;
- ++sa;
- hsh ^= ((*sa) << 4) & 0x30;
- hsh ^= ((*sa) >> 2) & 0x3f;
- ++sa;
- hsh ^= (*sa) & 0x3f;
- hsh ^= ((*sa) >> 6) & 0x03;
- ++sa;
- hsh ^= ((*sa) << 2) & 0x03c;
- hsh ^= ((*sa) >> 4) & 0xf;
- ++sa;
- hsh ^= ((*sa) << 4) & 0x30;
- hsh ^= ((*sa) >> 2) & 0x3f;
-
- hsh &= 63;
- if (hsh > 31)
- match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
- else
- match = eth->regs[RW_GA_LO] & (1 << hsh);
- D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
- eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
- return match;
+ unsigned int hsh;
+ int m_individual = eth->regs[RW_REC_CTRL] & 4;
+ int match;
+
+ /* First bit on the wire of a MAC address signals multicast or
+ physical address. */
+ if (!m_individual && !(sa[0] & 1)) {
+ return 0;
+ }
+
+ /* Calculate the hash index for the GA registers. */
+ hsh = 0;
+ hsh ^= (*sa) & 0x3f;
+ hsh ^= ((*sa) >> 6) & 0x03;
+ ++sa;
+ hsh ^= ((*sa) << 2) & 0x03c;
+ hsh ^= ((*sa) >> 4) & 0xf;
+ ++sa;
+ hsh ^= ((*sa) << 4) & 0x30;
+ hsh ^= ((*sa) >> 2) & 0x3f;
+ ++sa;
+ hsh ^= (*sa) & 0x3f;
+ hsh ^= ((*sa) >> 6) & 0x03;
+ ++sa;
+ hsh ^= ((*sa) << 2) & 0x03c;
+ hsh ^= ((*sa) >> 4) & 0xf;
+ ++sa;
+ hsh ^= ((*sa) << 4) & 0x30;
+ hsh ^= ((*sa) >> 2) & 0x3f;
+
+ hsh &= 63;
+ if (hsh > 31) {
+ match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
+ } else {
+ match = eth->regs[RW_GA_LO] & (1 << hsh);
+ }
+ D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
+ eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
+ return match;
}
static int eth_can_receive(NetClientState *nc)
{
- return 1;
+ return 1;
}
static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
- unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
- int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
- int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
- int r_bcast = eth->regs[RW_REC_CTRL] & 8;
-
- if (size < 12)
- return -1;
-
- D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
- use_ma0, use_ma1, r_bcast));
-
- /* Does the frame get through the address filters? */
- if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
- && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
- && (!r_bcast || memcmp(buf, sa_bcast, 6))
- && !eth_match_groupaddr(eth, buf))
- return size;
-
- /* FIXME: Find another way to pass on the fake csum. */
- etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
+ unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
+ int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
+ int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
+ int r_bcast = eth->regs[RW_REC_CTRL] & 8;
+
+ if (size < 12) {
+ return -1;
+ }
+
+ D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+ use_ma0, use_ma1, r_bcast));
+
+ /* Does the frame get through the address filters? */
+ if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
+ && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
+ && (!r_bcast || memcmp(buf, sa_bcast, 6))
+ && !eth_match_groupaddr(eth, buf)) {
+ return size;
+ }
+
+ /* FIXME: Find another way to pass on the fake csum. */
+ etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
return size;
}
static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
{
- struct fs_eth *eth = opaque;
+ struct fs_eth *eth = opaque;
- D(printf("%s buf=%p len=%d\n", __func__, buf, len));
- qemu_send_packet(ð->nic->nc, buf, len);
- return len;
+ D(printf("%s buf=%p len=%d\n", __func__, buf, len));
+ qemu_send_packet(ð->nic->nc, buf, len);
+ return len;
}
static void eth_set_link(NetClientState *nc)
{
- struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
- D(printf("%s %d\n", __func__, nc->link_down));
- eth->phy.link = !nc->link_down;
+ struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
+ D(printf("%s %d\n", __func__, nc->link_down));
+ eth->phy.link = !nc->link_down;
}
static const MemoryRegionOps eth_ops = {
- .read = eth_read,
- .write = eth_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
+ .read = eth_read,
+ .write = eth_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
};
static void eth_cleanup(NetClientState *nc)
{
- struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
+ struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
- /* Disconnect the client. */
- eth->dma_out->client.push = NULL;
- eth->dma_out->client.opaque = NULL;
- eth->dma_in->client.opaque = NULL;
- eth->dma_in->client.pull = NULL;
+ /* Disconnect the client. */
+ eth->dma_out->client.push = NULL;
+ eth->dma_out->client.opaque = NULL;
+ eth->dma_in->client.opaque = NULL;
+ eth->dma_in->client.pull = NULL;
g_free(eth);
}
static NetClientInfo net_etraxfs_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .can_receive = eth_can_receive,
- .receive = eth_receive,
- .cleanup = eth_cleanup,
- .link_status_changed = eth_set_link,
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = eth_can_receive,
+ .receive = eth_receive,
+ .cleanup = eth_cleanup,
+ .link_status_changed = eth_set_link,
};
static int fs_eth_init(SysBusDevice *dev)
{
- struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
+ struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
- if (!s->dma_out || !s->dma_in) {
- hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
- }
+ if (!s->dma_out || !s->dma_in) {
+ hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
+ }
- s->dma_out->client.push = eth_tx_push;
- s->dma_out->client.opaque = s;
- s->dma_in->client.opaque = s;
- s->dma_in->client.pull = NULL;
+ s->dma_out->client.push = eth_tx_push;
+ s->dma_out->client.opaque = s;
+ s->dma_in->client.opaque = s;
+ s->dma_in->client.pull = NULL;
- memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c);
- sysbus_init_mmio(dev, &s->mmio);
+ memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c);
+ sysbus_init_mmio(dev, &s->mmio);
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
- object_get_typename(OBJECT(s)), dev->qdev.id, s);
- qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+ s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
+ object_get_typename(OBJECT(s)), dev->qdev.id, s);
+ qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
- tdk_init(&s->phy);
- mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
- return 0;
+ tdk_init(&s->phy);
+ mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
+ return 0;
}
static Property etraxfs_eth_properties[] = {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH V3 2/8] hw/mdio: Generalize etraxfs MDIO bitbanging emulation
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 1/8] hw/etraxfs_eth: Eliminate checkpatch errors Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 3/8] hw/mdio: Add PHY register definition Grant Likely
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
The etraxfs and Xilinx axienet Ethernet models implement quite a nice
MDIO core that supports both bitbanging and direct register access. This
change factors the common code out into a separate file. There are no
functional changes here, just movement of code.
The etraxfs and axienet are slightly different. The etraxfs version
includes the bitbang state processing, but the axienet version has a
minor enhancement for read/write of phy registers without using bitbang
state variables. This patch generalizes the etraxfs version, with the
axienet change backported in.
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/Makefile.objs | 2 +-
hw/cris/Makefile.objs | 1 +
hw/etraxfs_eth.c | 278 +------------------------------------------------
hw/mdio.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++
hw/mdio.h | 78 ++++++++++++++
hw/xilinx_axienet.c | 184 +-------------------------------
6 files changed, 346 insertions(+), 459 deletions(-)
create mode 100644 hw/mdio.c
create mode 100644 hw/mdio.h
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 74b07a7..af93dfc 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -74,7 +74,7 @@ common-obj-$(CONFIG_XILINX) += xilinx_timer.o
common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
-common-obj-$(CONFIG_XILINX_AXI) += stream.o
+common-obj-$(CONFIG_XILINX_AXI) += stream.o mdio.o
# PKUnity SoC devices
common-obj-$(CONFIG_PUV3) += puv3_intc.o
diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs
index aa9298a..b3da1e6 100644
--- a/hw/cris/Makefile.objs
+++ b/hw/cris/Makefile.objs
@@ -9,5 +9,6 @@ obj-y += etraxfs_pic.o
obj-y += etraxfs_eth.o
obj-y += etraxfs_timer.o
obj-y += etraxfs_ser.o
+obj-y += mdio.o
obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 0b474c0..f26e338 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -26,286 +26,10 @@
#include "sysbus.h"
#include "net/net.h"
#include "etraxfs.h"
+#include "mdio.h"
#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
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
- uint32_t regs[32];
-
- int link;
-
- unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
- void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
-};
-
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
-{
- int regnum;
- unsigned r = 0;
-
- regnum = req & 0x1f;
-
- switch (regnum) {
- case 1:
- if (!phy->link) {
- break;
- }
- /* MR1. */
- /* Speeds and modes. */
- r |= (1 << 13) | (1 << 14);
- r |= (1 << 11) | (1 << 12);
- r |= (1 << 5); /* Autoneg complete. */
- r |= (1 << 3); /* Autoneg able. */
- r |= (1 << 2); /* link. */
- break;
- case 5:
- /* Link partner ability.
- We are kind; always agree with whatever best mode
- the guest advertises. */
- r = 1 << 14; /* Success. */
- /* Copy advertised modes. */
- r |= phy->regs[4] & (15 << 5);
- /* Autoneg support. */
- r |= 1;
- break;
- case 18:
- {
- /* Diagnostics reg. */
- int duplex = 0;
- int speed_100 = 0;
-
- if (!phy->link) {
- break;
- }
-
- /* Are we advertising 100 half or 100 duplex ? */
- speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
- speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
- /* Are we advertising 10 duplex or 100 duplex ? */
- duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
- duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
- r = (speed_100 << 10) | (duplex << 11);
- }
- break;
-
- default:
- r = phy->regs[regnum];
- break;
- }
- D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
- return r;
-}
-
-static void
-tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
-{
- int regnum;
-
- regnum = req & 0x1f;
- D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
- switch (regnum) {
- default:
- phy->regs[regnum] = data;
- break;
- }
-}
-
-static void
-tdk_init(struct qemu_phy *phy)
-{
- phy->regs[0] = 0x3100;
- /* PHY Id. */
- phy->regs[2] = 0x0300;
- phy->regs[3] = 0xe400;
- /* Autonegotiation advertisement reg. */
- phy->regs[4] = 0x01E1;
- phy->link = 1;
-
- phy->read = tdk_read;
- phy->write = tdk_write;
-}
-
-struct qemu_mdio
-{
- /* bus. */
- int mdc;
- int mdio;
-
- /* decoder. */
- enum {
- PREAMBLE,
- SOF,
- OPC,
- ADDR,
- REQ,
- TURNAROUND,
- DATA
- } state;
- unsigned int drive;
-
- unsigned int cnt;
- unsigned int addr;
- unsigned int opc;
- unsigned int req;
- unsigned int data;
-
- struct qemu_phy *devs[32];
-};
-
-static void
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static void mdio_read_req(struct qemu_mdio *bus)
-{
- struct qemu_phy *phy;
-
- phy = bus->devs[bus->addr];
- if (phy && phy->read) {
- bus->data = phy->read(phy, bus->req);
- } else {
- bus->data = 0xffff;
- }
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
- struct qemu_phy *phy;
-
- phy = bus->devs[bus->addr];
- if (phy && phy->write) {
- phy->write(phy, bus->req, bus->data);
- }
-}
-
-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;
- }
-}
-
/* ETRAX-FS Ethernet MAC block starts here. */
#define RW_MA0_LO 0x00
diff --git a/hw/mdio.c b/hw/mdio.c
new file mode 100644
index 0000000..8328b9b
--- /dev/null
+++ b/hw/mdio.c
@@ -0,0 +1,262 @@
+/*
+ * QEMU Ethernet MDIO bus & PHY models
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This is a generic MDIO implementation.
+ *
+ * TODO:
+ * - Split PHYs out as separate device models so they can be defined and
+ * instantiated separately from the MDIO bus.
+ * - Split out bitbang state machine into a separate model. Mostly this consists
+ * of the mdio_cycle() routine and the bitbang state data in struct qemu_mdio
+ * - Use the GPIO interface for driving bitbang
+ */
+
+#include <stdio.h>
+#include "qemu-common.h"
+#include "qemu/log.h"
+#include "mdio.h"
+
+#define D(x)
+
+/*
+ * The MDIO extensions in the TDK PHY model were reversed engineered from the
+ * linux driver (PHYID and Diagnostics reg).
+ * TODO: Add friendly names for the register nums.
+ */
+static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
+{
+ int regnum;
+ unsigned r = 0;
+
+ regnum = req & 0x1f;
+
+ switch (regnum) {
+ case 1:
+ if (!phy->link) {
+ break;
+ }
+ /* MR1. */
+ /* Speeds and modes. */
+ r |= (1 << 13) | (1 << 14);
+ r |= (1 << 11) | (1 << 12);
+ r |= (1 << 5); /* Autoneg complete. */
+ r |= (1 << 3); /* Autoneg able. */
+ r |= (1 << 2); /* link. */
+ r |= (1 << 1); /* link. */
+ break;
+ case 5:
+ /* Link partner ability.
+ We are kind; always agree with whatever best mode
+ the guest advertises. */
+ r = 1 << 14; /* Success. */
+ /* Copy advertised modes. */
+ r |= phy->regs[4] & (15 << 5);
+ /* Autoneg support. */
+ r |= 1;
+ break;
+ case 17:
+ /* Marvel PHY on many xilinx boards. */
+ r = 0x8000; /* 1000Mb */
+ break;
+ case 18:
+ {
+ /* Diagnostics reg. */
+ int duplex = 0;
+ int speed_100 = 0;
+
+ if (!phy->link) {
+ break;
+ }
+
+ /* Are we advertising 100 half or 100 duplex ? */
+ speed_100 = !!(phy->regs[4] & PHY_ADVERTISE_100HALF);
+ speed_100 |= !!(phy->regs[4] & PHY_ADVERTISE_100FULL);
+
+ /* Are we advertising 10 duplex or 100 duplex ? */
+ duplex = !!(phy->regs[4] & PHY_ADVERTISE_100FULL);
+ duplex |= !!(phy->regs[4] & PHY_ADVERTISE_10FULL);
+ r = (speed_100 << 10) | (duplex << 11);
+ }
+ break;
+
+ default:
+ r = phy->regs[regnum];
+ break;
+ }
+ D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
+ return r;
+}
+
+static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+{
+ int regnum;
+
+ regnum = req & 0x1f;
+ D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+ switch (regnum) {
+ default:
+ phy->regs[regnum] = data;
+ break;
+ }
+}
+
+void tdk_init(struct qemu_phy *phy)
+{
+ phy->regs[0] = 0x3100;
+ /* PHY Id. */
+ phy->regs[2] = 0x0300;
+ phy->regs[3] = 0xe400;
+ /* Autonegotiation advertisement reg. */
+ phy->regs[4] = 0x01e1;
+ phy->link = 1;
+
+ phy->read = tdk_read;
+ phy->write = tdk_write;
+}
+
+void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+ bus->devs[addr & 0x1f] = phy;
+}
+
+uint16_t mdio_read_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req)
+{
+ struct qemu_phy *phy;
+
+ phy = bus->devs[bus->addr];
+ if (phy && phy->read) {
+ return phy->read(phy, req);
+ }
+ return 0xffff;
+}
+
+void mdio_write_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req,
+ uint16_t data)
+{
+ struct qemu_phy *phy;
+
+ phy = bus->devs[bus->addr];
+ if (phy && phy->write) {
+ phy->write(phy, req, data);
+ }
+}
+
+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));
+ 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;
+ bus->data = mdio_read_req(bus, bus->addr, bus->req);
+ 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->addr, bus->req, bus->data);
+ }
+ bus->drive = 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
diff --git a/hw/mdio.h b/hw/mdio.h
new file mode 100644
index 0000000..9f29912
--- /dev/null
+++ b/hw/mdio.h
@@ -0,0 +1,78 @@
+#ifndef BITBANG_MDIO_H
+#define BITBANG_MDIO_H
+
+/*
+ * QEMU Bitbang Ethernet MDIO bus & PHY controllers.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+/* PHY Advertisement control register */
+#define PHY_ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define PHY_ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define PHY_ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define PHY_ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+
+struct qemu_phy {
+ uint32_t regs[32];
+
+ int link;
+
+ unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
+ void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
+};
+
+struct qemu_mdio {
+ /* bus. */
+ int mdc;
+ int mdio;
+
+ /* decoder. */
+ enum {
+ PREAMBLE,
+ SOF,
+ OPC,
+ ADDR,
+ REQ,
+ TURNAROUND,
+ DATA
+ } state;
+ unsigned int drive;
+
+ unsigned int cnt;
+ unsigned int addr;
+ unsigned int opc;
+ unsigned int req;
+ unsigned int data;
+
+ struct qemu_phy *devs[32];
+};
+
+void tdk_init(struct qemu_phy *phy);
+void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,
+ unsigned int addr);
+uint16_t mdio_read_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req);
+void mdio_write_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req, uint16_t data);
+void mdio_cycle(struct qemu_mdio *bus);
+
+#endif
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index 51c2896..ff09510 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -24,190 +24,12 @@
#include "sysbus.h"
#include "qemu/log.h"
+#include "mdio.h"
#include "net/net.h"
#include "net/checksum.h"
#include "stream.h"
-#define DPHY(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 */
-
-struct PHY {
- uint32_t regs[32];
-
- int link;
-
- unsigned int (*read)(struct PHY *phy, unsigned int req);
- void (*write)(struct PHY *phy, unsigned int req,
- unsigned int data);
-};
-
-static unsigned int tdk_read(struct PHY *phy, unsigned int req)
-{
- int regnum;
- unsigned r = 0;
-
- regnum = req & 0x1f;
-
- switch (regnum) {
- case 1:
- if (!phy->link) {
- break;
- }
- /* MR1. */
- /* Speeds and modes. */
- r |= (1 << 13) | (1 << 14);
- r |= (1 << 11) | (1 << 12);
- r |= (1 << 5); /* Autoneg complete. */
- r |= (1 << 3); /* Autoneg able. */
- r |= (1 << 2); /* link. */
- r |= (1 << 1); /* link. */
- break;
- case 5:
- /* Link partner ability.
- We are kind; always agree with whatever best mode
- the guest advertises. */
- r = 1 << 14; /* Success. */
- /* Copy advertised modes. */
- r |= phy->regs[4] & (15 << 5);
- /* Autoneg support. */
- r |= 1;
- break;
- case 17:
- /* Marvel PHY on many xilinx boards. */
- r = 0x8000; /* 1000Mb */
- break;
- case 18:
- {
- /* Diagnostics reg. */
- int duplex = 0;
- int speed_100 = 0;
-
- if (!phy->link) {
- break;
- }
-
- /* Are we advertising 100 half or 100 duplex ? */
- speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
- speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
- /* Are we advertising 10 duplex or 100 duplex ? */
- duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
- duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
- r = (speed_100 << 10) | (duplex << 11);
- }
- break;
-
- default:
- r = phy->regs[regnum];
- break;
- }
- DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
- return r;
-}
-
-static void
-tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
-{
- int regnum;
-
- regnum = req & 0x1f;
- DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
- switch (regnum) {
- default:
- phy->regs[regnum] = data;
- break;
- }
-}
-
-static void
-tdk_init(struct PHY *phy)
-{
- phy->regs[0] = 0x3100;
- /* PHY Id. */
- phy->regs[2] = 0x0300;
- phy->regs[3] = 0xe400;
- /* Autonegotiation advertisement reg. */
- phy->regs[4] = 0x01E1;
- phy->link = 1;
-
- phy->read = tdk_read;
- phy->write = tdk_write;
-}
-
-struct MDIOBus {
- /* bus. */
- int mdc;
- int mdio;
-
- /* decoder. */
- enum {
- PREAMBLE,
- SOF,
- OPC,
- ADDR,
- REQ,
- TURNAROUND,
- DATA
- } state;
- unsigned int drive;
-
- unsigned int cnt;
- unsigned int addr;
- unsigned int opc;
- unsigned int req;
- unsigned int data;
-
- struct PHY *devs[32];
-};
-
-static void
-mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
- unsigned int reg)
-{
- struct PHY *phy;
- uint16_t data;
-
- phy = bus->devs[addr];
- if (phy && phy->read) {
- data = phy->read(phy, reg);
- } else {
- data = 0xffff;
- }
- DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
- return data;
-}
-
-static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
- unsigned int reg, uint16_t data)
-{
- struct PHY *phy;
-
- DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
- phy = bus->devs[addr];
- if (phy && phy->write) {
- phy->write(phy, reg, data);
- }
-}
-
#define DENET(x)
#define R_RAF (0x000 / 4)
@@ -299,8 +121,8 @@ enum {
/* Indirect registers. */
struct TEMAC {
- struct MDIOBus mdio_bus;
- struct PHY phy;
+ struct qemu_mdio mdio_bus;
+ struct qemu_phy phy;
void *parent;
};
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH V3 3/8] hw/mdio: Add PHY register definition
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 1/8] hw/etraxfs_eth: Eliminate checkpatch errors Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 2/8] hw/mdio: Generalize etraxfs MDIO bitbanging emulation Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 4/8] hw/mdio: Generalize phy initialization routine Grant Likely
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
Trivial patch to add #defines for defined PHY register address and bit fields
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/mdio.c | 8 ++++----
hw/mdio.h | 24 ++++++++++++++++++++++--
2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/hw/mdio.c b/hw/mdio.c
index 8328b9b..e5e30b6 100644
--- a/hw/mdio.c
+++ b/hw/mdio.c
@@ -122,12 +122,12 @@ static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
void tdk_init(struct qemu_phy *phy)
{
- phy->regs[0] = 0x3100;
+ phy->regs[PHY_CTRL] = 0x3100;
/* PHY Id. */
- phy->regs[2] = 0x0300;
- phy->regs[3] = 0xe400;
+ phy->regs[PHY_ID1] = 0x0300;
+ phy->regs[PHY_ID2] = 0xe400;
/* Autonegotiation advertisement reg. */
- phy->regs[4] = 0x01e1;
+ phy->regs[PHY_AUTONEG_ADV] = 0x01e1;
phy->link = 1;
phy->read = tdk_read;
diff --git a/hw/mdio.h b/hw/mdio.h
index 9f29912..0ba92cd 100644
--- a/hw/mdio.h
+++ b/hw/mdio.h
@@ -27,14 +27,34 @@
#include <stdint.h>
-/* PHY Advertisement control register */
+/* PHY MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+#define NUM_PHY_REGS 0x20 /* 5 bit address bus (0-0x1F) */
+
+#define PHY_CTRL_RST 0x8000 /* PHY reset command */
+#define PHY_CTRL_ANEG_RST 0x0200 /* Autonegotiation reset command */
+
+/* PHY Advertisement control and remote capability registers (same bitfields) */
#define PHY_ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
#define PHY_ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define PHY_ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define PHY_ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
struct qemu_phy {
- uint32_t regs[32];
+ uint32_t regs[NUM_PHY_REGS];
int link;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH V3 4/8] hw/mdio: Generalize phy initialization routine
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
` (2 preceding siblings ...)
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 3/8] hw/mdio: Add PHY register definition Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 5/8] hw/mdio: Mask out read-only bits Grant Likely
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
There really isn't anything tdk-specific about tdk_init() other than the
phy id registers. The function should instead be generalized for any
phy, at least as far as the ID registers are concerned. For the most
part the read/write behaviour should be very similar across PHYs.
This patch renames tdk_{read,write,init}() to mdio_phy_*() so it can be
used for any PHY.
More work definitely needs to be done here to make it easy to override
the default behaviour for specific PHYs, but this at least is a
reasonable start.
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/etraxfs_eth.c | 2 +-
hw/mdio.c | 14 +++++++-------
hw/mdio.h | 2 +-
hw/xilinx_axienet.c | 2 +-
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index f26e338..4d56134 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -342,7 +342,7 @@ static int fs_eth_init(SysBusDevice *dev)
object_get_typename(OBJECT(s)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
- tdk_init(&s->phy);
+ mdio_phy_init(&s->phy, 0x0300, 0xe400);
mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
return 0;
}
diff --git a/hw/mdio.c b/hw/mdio.c
index e5e30b6..040ecf6 100644
--- a/hw/mdio.c
+++ b/hw/mdio.c
@@ -43,7 +43,7 @@
* linux driver (PHYID and Diagnostics reg).
* TODO: Add friendly names for the register nums.
*/
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
+static unsigned int mdio_phy_read(struct qemu_phy *phy, unsigned int req)
{
int regnum;
unsigned r = 0;
@@ -107,7 +107,7 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
return r;
}
-static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+static void mdio_phy_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
{
int regnum;
@@ -120,18 +120,18 @@ static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
}
}
-void tdk_init(struct qemu_phy *phy)
+void mdio_phy_init(struct qemu_phy *phy, uint16_t id1, uint16_t id2)
{
phy->regs[PHY_CTRL] = 0x3100;
/* PHY Id. */
- phy->regs[PHY_ID1] = 0x0300;
- phy->regs[PHY_ID2] = 0xe400;
+ phy->regs[PHY_ID1] = id1;
+ phy->regs[PHY_ID2] = id2;
/* Autonegotiation advertisement reg. */
phy->regs[PHY_AUTONEG_ADV] = 0x01e1;
phy->link = 1;
- phy->read = tdk_read;
- phy->write = tdk_write;
+ phy->read = mdio_phy_read;
+ phy->write = mdio_phy_write;
}
void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
diff --git a/hw/mdio.h b/hw/mdio.h
index 0ba92cd..427c9ed 100644
--- a/hw/mdio.h
+++ b/hw/mdio.h
@@ -88,7 +88,7 @@ struct qemu_mdio {
struct qemu_phy *devs[32];
};
-void tdk_init(struct qemu_phy *phy);
+void mdio_phy_init(struct qemu_phy *phy, uint16_t id1, uint16_t id2);
void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,
unsigned int addr);
uint16_t mdio_read_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req);
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index ff09510..d501dbd 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -677,7 +677,7 @@ static int xilinx_enet_init(SysBusDevice *dev)
object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
- tdk_init(&s->TEMAC.phy);
+ mdio_phy_init(&s->TEMAC.phy, 0x0300, 0xe400);
mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
s->TEMAC.parent = s;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH V3 5/8] hw/mdio: Mask out read-only bits.
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
` (3 preceding siblings ...)
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 4/8] hw/mdio: Generalize phy initialization routine Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 6/8] hw/mdio: Refactor bitbanging state machine Grant Likely
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
The RST and ANEG_RST bits are commands, not settings. An operating
system will get confused (or at least u-boot does) if those bits remain
set after writing to them. Therefore, mask them out on write.
Similarly, no bits in the ID1, ID2, and remote capability registers are
writeable; so mask them out also.
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/mdio.c | 16 ++++++++++++----
hw/mdio.h | 1 +
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/hw/mdio.c b/hw/mdio.c
index 040ecf6..45e271f 100644
--- a/hw/mdio.c
+++ b/hw/mdio.c
@@ -109,17 +109,24 @@ static unsigned int mdio_phy_read(struct qemu_phy *phy, unsigned int req)
static void mdio_phy_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
{
- int regnum;
+ int regnum = req & 0x1f;
+ uint16_t mask = phy->regs_readonly_mask[regnum];
- regnum = req & 0x1f;
- D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+ D(printf("%s reg[%d] = %x; mask=%x\n", __func__, regnum, data, mask));
switch (regnum) {
default:
- phy->regs[regnum] = data;
+ phy->regs[regnum] = (phy->regs[regnum] & mask) | (data & ~mask);
break;
}
}
+static const uint16_t default_readonly_mask[32] = {
+ [PHY_CTRL] = PHY_CTRL_RST | PHY_CTRL_ANEG_RST,
+ [PHY_ID1] = 0xffff,
+ [PHY_ID2] = 0xffff,
+ [PHY_LP_ABILITY] = 0xffff,
+};
+
void mdio_phy_init(struct qemu_phy *phy, uint16_t id1, uint16_t id2)
{
phy->regs[PHY_CTRL] = 0x3100;
@@ -128,6 +135,7 @@ void mdio_phy_init(struct qemu_phy *phy, uint16_t id1, uint16_t id2)
phy->regs[PHY_ID2] = id2;
/* Autonegotiation advertisement reg. */
phy->regs[PHY_AUTONEG_ADV] = 0x01e1;
+ phy->regs_readonly_mask = default_readonly_mask;
phy->link = 1;
phy->read = mdio_phy_read;
diff --git a/hw/mdio.h b/hw/mdio.h
index 427c9ed..0a6c20a 100644
--- a/hw/mdio.h
+++ b/hw/mdio.h
@@ -55,6 +55,7 @@
struct qemu_phy {
uint32_t regs[NUM_PHY_REGS];
+ const uint16_t *regs_readonly_mask; /* 0=writable, 1=read-only */
int link;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH V3 6/8] hw/mdio: Refactor bitbanging state machine
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
` (4 preceding siblings ...)
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 5/8] hw/mdio: Mask out read-only bits Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 7/8] hw/mdio: Add VMState support Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 8/8] hw/mdio: Use bitbang core for smc91c111 network device Grant Likely
7 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
The MDIO state machine has a moderate amount of duplicate code in the
state processing that can be consolidated. This patch does so and
reorganizes it a bit so that far less code is required. Most of the
states simply stream a fixed number of bits in as a single integer and
can be handled by a common processing function that checks for
completion of the state and returns the streamed in value.
Changes include:
- Move clock state change tracking into core code
- Use a common shift register for clocking data in and out
- Create separate mdc & mdio accessor functions
- will be replaced with GPIO connection in a follow-on patch
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/etraxfs_eth.c | 11 ++---
hw/mdio.c | 134 ++++++++++++++++++++++--------------------------------
hw/mdio.h | 36 ++++++++-------
3 files changed, 78 insertions(+), 103 deletions(-)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 4d56134..6ff29ea 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -113,7 +113,7 @@ eth_read(void *opaque, hwaddr addr, unsigned int size)
switch (addr) {
case R_STAT:
- r = eth->mdio_bus.mdio & 1;
+ r = mdio_bitbang_get_data(ð->mdio_bus);
break;
default:
r = eth->regs[addr];
@@ -171,13 +171,10 @@ eth_write(void *opaque, hwaddr addr,
case RW_MGM_CTRL:
/* Attach an MDIO/PHY abstraction. */
if (value & 2) {
- eth->mdio_bus.mdio = value & 1;
+ mdio_bitbang_set_data(ð->mdio_bus, value & 1);
}
- if (eth->mdio_bus.mdc != (value & 4)) {
- mdio_cycle(ð->mdio_bus);
- eth_validate_duplex(eth);
- }
- eth->mdio_bus.mdc = !!(value & 4);
+ mdio_bitbang_set_clk(ð->mdio_bus, value & 4);
+ eth_validate_duplex(eth);
eth->regs[addr] = value;
break;
diff --git a/hw/mdio.c b/hw/mdio.c
index 45e271f..79f0e3b 100644
--- a/hw/mdio.c
+++ b/hw/mdio.c
@@ -43,7 +43,7 @@
* linux driver (PHYID and Diagnostics reg).
* TODO: Add friendly names for the register nums.
*/
-static unsigned int mdio_phy_read(struct qemu_phy *phy, unsigned int req)
+static uint16_t mdio_phy_read(struct qemu_phy *phy, unsigned int req)
{
int regnum;
unsigned r = 0;
@@ -107,7 +107,7 @@ static unsigned int mdio_phy_read(struct qemu_phy *phy, unsigned int req)
return r;
}
-static void mdio_phy_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+static void mdio_phy_write(struct qemu_phy *phy, unsigned int req, uint16_t data)
{
int regnum = req & 0x1f;
uint16_t mask = phy->regs_readonly_mask[regnum];
@@ -136,7 +136,7 @@ void mdio_phy_init(struct qemu_phy *phy, uint16_t id1, uint16_t id2)
/* Autonegotiation advertisement reg. */
phy->regs[PHY_AUTONEG_ADV] = 0x01e1;
phy->regs_readonly_mask = default_readonly_mask;
- phy->link = 1;
+ phy->link = true;
phy->read = mdio_phy_read;
phy->write = mdio_phy_write;
@@ -169,99 +169,75 @@ void mdio_write_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req,
}
}
-void mdio_cycle(struct qemu_mdio *bus)
+/**
+ * mdio_bitbang_update() - internal function to check how many clocks have
+ * passed and move to the next state if necessary. Returns TRUE on state change.
+ */
+static bool mdio_bitbang_update(struct qemu_mdio *bus, int num_bits, int next, uint16_t *reg)
{
- bus->cnt++;
+ if (bus->cnt < num_bits) {
+ return false;
+ }
+ if (reg) {
+ *reg = bus->shiftreg;
+ }
+ bus->state = next;
+ bus->cnt = 0;
+ bus->shiftreg = 0;
+ return true;
+}
+/**
+ * mdio_bitbang_set_clk() - set value of mdc signal and update state
+ */
+void mdio_bitbang_set_clk(struct qemu_mdio *bus, bool mdc)
+{
+ uint16_t tmp;
+
+ if (mdc == bus->mdc) {
+ return; /* Clock state hasn't changed; do nothing */
+ }
+
+ bus->mdc = mdc;
+ if (bus->mdc) {
+ /* Falling (inactive) clock edge */
+ if ((bus->state == DATA) && (bus->opc == 2)) {
+ bus->mdio = !!(bus->shiftreg & 0x8000);
+ }
+ return;
+ }
+
+ /* Rising clock Edge */
+ bus->shiftreg = (bus->shiftreg << 1) | bus->mdio;
+ 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));
+ bus->mdc, bus->mdio, bus->state, bus->cnt));
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;
- }
+ /* MDIO must be 30 clocks high, 1 low, and 1 high to get out of preamble */
+ if (bus->shiftreg == 0xfffffffd) {
+ mdio_bitbang_update(bus, 0, OPC, NULL);
}
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;
- }
- }
+ mdio_bitbang_update(bus, 2, ADDR, &bus->opc);
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;
- }
- }
+ mdio_bitbang_update(bus, 5, REQ, &bus->addr);
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;
- }
- }
+ mdio_bitbang_update(bus, 5, TURNAROUND, &bus->req);
break;
case TURNAROUND:
- if (bus->mdc && bus->cnt == 2*2) {
- bus->mdio = 0;
- bus->cnt = 0;
-
- if (bus->opc == 2) {
- bus->drive = 1;
- bus->data = mdio_read_req(bus, bus->addr, bus->req);
- bus->mdio = bus->data & 1;
- }
- bus->state = DATA;
+ /* If beginning of DATA READ cycle, then read PHY into shift register */
+ if (mdio_bitbang_update(bus, 2, DATA, NULL) && (bus->opc == 2)) {
+ bus->shiftreg = mdio_read_req(bus, bus->addr, bus->req);
}
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->addr, bus->req, bus->data);
- }
- bus->drive = 0;
- }
+ /* If end of DATA WRITE cycle, then write shift register to PHY */
+ if (mdio_bitbang_update(bus, 16, PREAMBLE, &tmp) && (bus->opc == 1)) {
+ mdio_write_req(bus, bus->addr, bus->req, tmp);
}
break;
default:
diff --git a/hw/mdio.h b/hw/mdio.h
index 0a6c20a..340501e 100644
--- a/hw/mdio.h
+++ b/hw/mdio.h
@@ -54,37 +54,33 @@
#define PHY_ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
struct qemu_phy {
- uint32_t regs[NUM_PHY_REGS];
+ uint16_t regs[NUM_PHY_REGS];
const uint16_t *regs_readonly_mask; /* 0=writable, 1=read-only */
- int link;
+ bool link;
- unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
- void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
+ uint16_t (*read)(struct qemu_phy *phy, unsigned int req);
+ void (*write)(struct qemu_phy *phy, unsigned int req, uint16_t data);
};
struct qemu_mdio {
- /* bus. */
- int mdc;
- int mdio;
-
- /* decoder. */
+ /* bitbanging state machine */
+ bool mdc;
+ bool mdio;
enum {
PREAMBLE,
- SOF,
OPC,
ADDR,
REQ,
TURNAROUND,
DATA
} state;
- unsigned int drive;
- unsigned int cnt;
- unsigned int addr;
- unsigned int opc;
- unsigned int req;
- unsigned int data;
+ uint16_t cnt; /* Bit count for current state */
+ uint16_t addr; /* PHY Address; retrieved during ADDR state */
+ uint16_t opc; /* Operation; 2:read */
+ uint16_t req; /* Register address */
+ uint32_t shiftreg; /* shift register; bits in to or out from PHY */
struct qemu_phy *devs[32];
};
@@ -94,6 +90,12 @@ void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,
unsigned int addr);
uint16_t mdio_read_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req);
void mdio_write_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req, uint16_t data);
-void mdio_cycle(struct qemu_mdio *bus);
+void mdio_bitbang_set_clk(struct qemu_mdio *bus, bool mdc);
+static inline void mdio_bitbang_set_data(struct qemu_mdio *bus, bool mdio) {
+ bus->mdio = mdio;
+}
+static inline bool mdio_bitbang_get_data(struct qemu_mdio *bus) {
+ return bus->mdio;
+}
#endif
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH V3 7/8] hw/mdio: Add VMState support
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
` (5 preceding siblings ...)
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 6/8] hw/mdio: Refactor bitbanging state machine Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 8/8] hw/mdio: Use bitbang core for smc91c111 network device Grant Likely
7 siblings, 0 replies; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
The MDIO model needs to have VMState support before it can be used by
devices that support VMState. This patch adds VMState macros for both
qemu_mdio and qemu_phy.
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/mdio.c | 30 ++++++++++++++++++++++++++++++
hw/mdio.h | 21 +++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/hw/mdio.c b/hw/mdio.c
index 79f0e3b..023ad90 100644
--- a/hw/mdio.c
+++ b/hw/mdio.c
@@ -244,3 +244,33 @@ void mdio_bitbang_set_clk(struct qemu_mdio *bus, bool mdc)
break;
}
}
+
+const VMStateDescription vmstate_mdio = {
+ .name = "mdio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(mdc, struct qemu_mdio),
+ VMSTATE_BOOL(mdio, struct qemu_mdio),
+ VMSTATE_UINT32(state, struct qemu_mdio),
+ VMSTATE_UINT16(cnt, struct qemu_mdio),
+ VMSTATE_UINT16(addr, struct qemu_mdio),
+ VMSTATE_UINT16(opc, struct qemu_mdio),
+ VMSTATE_UINT16(req, struct qemu_mdio),
+ VMSTATE_UINT32(shiftreg, struct qemu_mdio),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+const VMStateDescription vmstate_mdio_phy = {
+ .name = "mdio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16_ARRAY(regs, struct qemu_phy, 32),
+ VMSTATE_BOOL(link, struct qemu_phy),
+ VMSTATE_END_OF_LIST()
+ }
+};
diff --git a/hw/mdio.h b/hw/mdio.h
index 340501e..62d292b 100644
--- a/hw/mdio.h
+++ b/hw/mdio.h
@@ -26,6 +26,7 @@
*/
#include <stdint.h>
+#include "migration/vmstate.h"
/* PHY MII Register/Bit Definitions */
/* PHY Registers defined by IEEE */
@@ -63,6 +64,16 @@ struct qemu_phy {
void (*write)(struct qemu_phy *phy, unsigned int req, uint16_t data);
};
+extern const VMStateDescription vmstate_mdio_phy;
+
+#define VMSTATE_MDIO_PHY(_field, _state) { \
+ .name = (stringify(_field)), \
+ .size = sizeof(struct qemu_phy), \
+ .vmsd = &vmstate_mdio_phy, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, struct qemu_phy), \
+}
+
struct qemu_mdio {
/* bitbanging state machine */
bool mdc;
@@ -85,6 +96,16 @@ struct qemu_mdio {
struct qemu_phy *devs[32];
};
+extern const VMStateDescription vmstate_mdio;
+
+#define VMSTATE_MDIO(_field, _state) { \
+ .name = (stringify(_field)), \
+ .size = sizeof(struct qemu_mdio), \
+ .vmsd = &vmstate_mdio, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, struct qemu_mdio), \
+}
+
void mdio_phy_init(struct qemu_phy *phy, uint16_t id1, uint16_t id2);
void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,
unsigned int addr);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH V3 8/8] hw/mdio: Use bitbang core for smc91c111 network device
2013-02-02 23:40 [Qemu-devel] [PATCH V3 0/8] Generalize MDIO framework Grant Likely
` (6 preceding siblings ...)
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 7/8] hw/mdio: Add VMState support Grant Likely
@ 2013-02-02 23:40 ` Grant Likely
2013-02-02 23:51 ` Peter Maydell
7 siblings, 1 reply; 10+ messages in thread
From: Grant Likely @ 2013-02-02 23:40 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Anthony Liguori, Grant Likely, Paul Brook,
Edgar E. Iglesias, Andreas Färber
The smc91c111 device has bitbanged MDIO access, but the model doesn't
yet implement it. This patch uses the generalized bitbang MDIO support
pulled out of etraxfs Ethernet driver.
The MDIO state machine is driven by changes in state to the clock
control bit in the management register. The PHY model emulated is
currently trivial (being whatever was done for the etraxfs driver), but
it is enough to get an OS to recognize a PHY as being present.
Tested with the versatilepb model with U-Boot and the Linux Kernel as
client software.
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Andreas Färber <afaerber@suse.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
hw/Makefile.objs | 2 +-
hw/smc91c111.c | 23 ++++++++++++++++++++---
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index af93dfc..4ec6fb8 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -117,7 +117,7 @@ common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
common-obj-$(CONFIG_E1000_PCI) += e1000.o
common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
-common-obj-$(CONFIG_SMC91C111) += smc91c111.o
+common-obj-$(CONFIG_SMC91C111) += smc91c111.o mdio.o
common-obj-$(CONFIG_LAN9118) += lan9118.o
common-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index a34698f..506101b 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -10,6 +10,7 @@
#include "sysbus.h"
#include "net/net.h"
#include "devices.h"
+#include "mdio.h"
/* For crc32 */
#include <zlib.h>
@@ -44,6 +45,10 @@ typedef struct {
uint8_t int_level;
uint8_t int_mask;
MemoryRegion mmio;
+
+ /* MDIO bus and the attached phy */
+ struct qemu_mdio mdio_bus;
+ struct qemu_phy phy;
} smc91c111_state;
static const VMStateDescription vmstate_smc91c111 = {
@@ -71,6 +76,8 @@ static const VMStateDescription vmstate_smc91c111 = {
VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
VMSTATE_UINT8(int_level, smc91c111_state),
VMSTATE_UINT8(int_mask, smc91c111_state),
+ VMSTATE_MDIO(mdio_bus, smc91c111_state),
+ VMSTATE_MDIO_PHY(phy, smc91c111_state),
VMSTATE_END_OF_LIST()
}
};
@@ -437,7 +444,15 @@ static void smc91c111_writeb(void *opaque, hwaddr offset,
/* Multicast table. */
/* Not implemented. */
return;
- case 8: case 9: /* Management Interface. */
+ case 8: /* Management Interface. */
+ /* Update MDIO data line status; but only if output is enabled */
+ if (value & 8) {
+ mdio_bitbang_set_data(&s->mdio_bus, !!(value & 1));
+ }
+ /* Process the clock */
+ mdio_bitbang_set_clk(&s->mdio_bus, value & 4);
+ return;
+ case 9: /* Management Interface. */
/* Not implemented. */
return;
case 12: /* Early receive. */
@@ -576,8 +591,7 @@ static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
/* Not implemented. */
return 0;
case 8: /* Management Interface. */
- /* Not implemented. */
- return 0x30;
+ return 0x30 | (mdio_bitbang_get_data(&s->mdio_bus) ? 2 : 0);
case 9:
return 0x33;
case 10: /* Revision. */
@@ -754,6 +768,9 @@ static int smc91c111_init1(SysBusDevice *dev)
s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+ mdio_phy_init(&s->phy, 0x0016, 0xf84);
+ mdio_attach(&s->mdio_bus, &s->phy, 0);
/* ??? Save/restore. */
return 0;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH V3 8/8] hw/mdio: Use bitbang core for smc91c111 network device
2013-02-02 23:40 ` [Qemu-devel] [PATCH V3 8/8] hw/mdio: Use bitbang core for smc91c111 network device Grant Likely
@ 2013-02-02 23:51 ` Peter Maydell
0 siblings, 0 replies; 10+ messages in thread
From: Peter Maydell @ 2013-02-02 23:51 UTC (permalink / raw)
To: Grant Likely
Cc: Edgar E. Iglesias, Anthony Liguori, qemu-devel,
Andreas Färber, Paul Brook
On 2 February 2013 23:40, Grant Likely <grant.likely@secretlab.ca> wrote:
> static const VMStateDescription vmstate_smc91c111 = {
> @@ -71,6 +76,8 @@ static const VMStateDescription vmstate_smc91c111 = {
> VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
> VMSTATE_UINT8(int_level, smc91c111_state),
> VMSTATE_UINT8(int_mask, smc91c111_state),
> + VMSTATE_MDIO(mdio_bus, smc91c111_state),
> + VMSTATE_MDIO_PHY(phy, smc91c111_state),
> VMSTATE_END_OF_LIST()
> }
If you're adding vmstate fields to an existing structure
you need to either:
(a) increment the .version_id field, and set .minimum_version_id
field to the same value [and accept that old-to-new migration
won't be possible, which is OK in this particular case as it's
only used by ARM boards and I'm happy that we don't currently
support cross version migration on ARM]
(b) increment .version_id only, mark the new vmstate fields
as only-from-version-N, and cope with what you get if an
incoming migration hasn't got the fields.
For a complicated thing like the phy I would suggest course
(a) as the simplest approach.
-- PMM
^ permalink raw reply [flat|nested] 10+ messages in thread