|
@@ -203,17 +203,12 @@ static const VMStateDescription vmstate_imx_eth_txdescs = {
|
|
|
|
|
|
static const VMStateDescription vmstate_imx_eth = {
|
|
|
.name = TYPE_IMX_FEC,
|
|
|
- .version_id = 2,
|
|
|
- .minimum_version_id = 2,
|
|
|
+ .version_id = 3,
|
|
|
+ .minimum_version_id = 3,
|
|
|
.fields = (const VMStateField[]) {
|
|
|
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
|
|
|
VMSTATE_UINT32(rx_descriptor, IMXFECState),
|
|
|
VMSTATE_UINT32(tx_descriptor[0], IMXFECState),
|
|
|
- VMSTATE_UINT32(phy_status, IMXFECState),
|
|
|
- VMSTATE_UINT32(phy_control, IMXFECState),
|
|
|
- VMSTATE_UINT32(phy_advertise, IMXFECState),
|
|
|
- VMSTATE_UINT32(phy_int, IMXFECState),
|
|
|
- VMSTATE_UINT32(phy_int_mask, IMXFECState),
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
},
|
|
|
.subsections = (const VMStateDescription * const []) {
|
|
@@ -222,14 +217,6 @@ static const VMStateDescription vmstate_imx_eth = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
-#define PHY_INT_ENERGYON (1 << 7)
|
|
|
-#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
|
|
|
-#define PHY_INT_FAULT (1 << 5)
|
|
|
-#define PHY_INT_DOWN (1 << 4)
|
|
|
-#define PHY_INT_AUTONEG_LP (1 << 3)
|
|
|
-#define PHY_INT_PARFAULT (1 << 2)
|
|
|
-#define PHY_INT_AUTONEG_PAGE (1 << 1)
|
|
|
-
|
|
|
static void imx_eth_update(IMXFECState *s);
|
|
|
|
|
|
/*
|
|
@@ -238,47 +225,19 @@ static void imx_eth_update(IMXFECState *s);
|
|
|
* For now we don't handle any GPIO/interrupt line, so the OS will
|
|
|
* have to poll for the PHY status.
|
|
|
*/
|
|
|
-static void imx_phy_update_irq(IMXFECState *s)
|
|
|
-{
|
|
|
- imx_eth_update(s);
|
|
|
-}
|
|
|
-
|
|
|
-static void imx_phy_update_link(IMXFECState *s)
|
|
|
+static void imx_phy_update_irq(void *opaque, int n, int level)
|
|
|
{
|
|
|
- /* Autonegotiation status mirrors link status. */
|
|
|
- if (qemu_get_queue(s->nic)->link_down) {
|
|
|
- trace_imx_phy_update_link("down");
|
|
|
- s->phy_status &= ~0x0024;
|
|
|
- s->phy_int |= PHY_INT_DOWN;
|
|
|
- } else {
|
|
|
- trace_imx_phy_update_link("up");
|
|
|
- s->phy_status |= 0x0024;
|
|
|
- s->phy_int |= PHY_INT_ENERGYON;
|
|
|
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
|
|
|
- }
|
|
|
- imx_phy_update_irq(s);
|
|
|
+ imx_eth_update(opaque);
|
|
|
}
|
|
|
|
|
|
static void imx_eth_set_link(NetClientState *nc)
|
|
|
{
|
|
|
- imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
|
|
|
-}
|
|
|
-
|
|
|
-static void imx_phy_reset(IMXFECState *s)
|
|
|
-{
|
|
|
- trace_imx_phy_reset();
|
|
|
-
|
|
|
- s->phy_status = 0x7809;
|
|
|
- s->phy_control = 0x3000;
|
|
|
- s->phy_advertise = 0x01e1;
|
|
|
- s->phy_int_mask = 0;
|
|
|
- s->phy_int = 0;
|
|
|
- imx_phy_update_link(s);
|
|
|
+ lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii,
|
|
|
+ nc->link_down);
|
|
|
}
|
|
|
|
|
|
static uint32_t imx_phy_read(IMXFECState *s, int reg)
|
|
|
{
|
|
|
- uint32_t val;
|
|
|
uint32_t phy = reg / 32;
|
|
|
|
|
|
if (!s->phy_connected) {
|
|
@@ -296,54 +255,7 @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
|
|
|
|
|
|
reg %= 32;
|
|
|
|
|
|
- switch (reg) {
|
|
|
- case 0: /* Basic Control */
|
|
|
- val = s->phy_control;
|
|
|
- break;
|
|
|
- case 1: /* Basic Status */
|
|
|
- val = s->phy_status;
|
|
|
- break;
|
|
|
- case 2: /* ID1 */
|
|
|
- val = 0x0007;
|
|
|
- break;
|
|
|
- case 3: /* ID2 */
|
|
|
- val = 0xc0d1;
|
|
|
- break;
|
|
|
- case 4: /* Auto-neg advertisement */
|
|
|
- val = s->phy_advertise;
|
|
|
- break;
|
|
|
- case 5: /* Auto-neg Link Partner Ability */
|
|
|
- val = 0x0f71;
|
|
|
- break;
|
|
|
- case 6: /* Auto-neg Expansion */
|
|
|
- val = 1;
|
|
|
- break;
|
|
|
- case 29: /* Interrupt source. */
|
|
|
- val = s->phy_int;
|
|
|
- s->phy_int = 0;
|
|
|
- imx_phy_update_irq(s);
|
|
|
- break;
|
|
|
- case 30: /* Interrupt mask */
|
|
|
- val = s->phy_int_mask;
|
|
|
- break;
|
|
|
- case 17:
|
|
|
- case 18:
|
|
|
- case 27:
|
|
|
- case 31:
|
|
|
- qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n",
|
|
|
- TYPE_IMX_FEC, __func__, reg);
|
|
|
- val = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
|
|
|
- TYPE_IMX_FEC, __func__, reg);
|
|
|
- val = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- trace_imx_phy_read(val, phy, reg);
|
|
|
-
|
|
|
- return val;
|
|
|
+ return lan9118_phy_read(&s->mii, reg);
|
|
|
}
|
|
|
|
|
|
static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
|
|
@@ -365,39 +277,7 @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
|
|
|
|
|
|
reg %= 32;
|
|
|
|
|
|
- trace_imx_phy_write(val, phy, reg);
|
|
|
-
|
|
|
- switch (reg) {
|
|
|
- case 0: /* Basic Control */
|
|
|
- if (val & 0x8000) {
|
|
|
- imx_phy_reset(s);
|
|
|
- } else {
|
|
|
- s->phy_control = val & 0x7980;
|
|
|
- /* Complete autonegotiation immediately. */
|
|
|
- if (val & 0x1000) {
|
|
|
- s->phy_status |= 0x0020;
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- case 4: /* Auto-neg advertisement */
|
|
|
- s->phy_advertise = (val & 0x2d7f) | 0x80;
|
|
|
- break;
|
|
|
- case 30: /* Interrupt mask */
|
|
|
- s->phy_int_mask = val & 0xff;
|
|
|
- imx_phy_update_irq(s);
|
|
|
- break;
|
|
|
- case 17:
|
|
|
- case 18:
|
|
|
- case 27:
|
|
|
- case 31:
|
|
|
- qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n",
|
|
|
- TYPE_IMX_FEC, __func__, reg);
|
|
|
- break;
|
|
|
- default:
|
|
|
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
|
|
|
- TYPE_IMX_FEC, __func__, reg);
|
|
|
- break;
|
|
|
- }
|
|
|
+ lan9118_phy_write(&s->mii, reg, val);
|
|
|
}
|
|
|
|
|
|
static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
|
|
@@ -682,9 +562,6 @@ static void imx_eth_reset(DeviceState *d)
|
|
|
|
|
|
s->rx_descriptor = 0;
|
|
|
memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
|
|
|
-
|
|
|
- /* We also reset the PHY */
|
|
|
- imx_phy_reset(s);
|
|
|
}
|
|
|
|
|
|
static uint32_t imx_default_read(IMXFECState *s, uint32_t index)
|
|
@@ -1329,6 +1206,13 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
|
|
|
sysbus_init_irq(sbd, &s->irq[0]);
|
|
|
sysbus_init_irq(sbd, &s->irq[1]);
|
|
|
|
|
|
+ qemu_init_irq(&s->mii_irq, imx_phy_update_irq, s, 0);
|
|
|
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
|
|
|
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
|
|
|
+
|
|
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
|
|
|
|
|
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
|