Patchwork [V2,6/6] hw/mdio: Use bitbang core for smc91c111 network device

login
register
mail settings
Submitter Grant Likely
Date Jan. 23, 2013, 4:15 p.m.
Message ID <1358957730-17897-7-git-send-email-grant.likely@secretlab.ca>
Download mbox | patch
Permalink /patch/215059/
State New
Headers show

Comments

Grant Likely - Jan. 23, 2013, 4:15 p.m.
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   |   25 +++++++++++++++++++++----
 2 files changed, 22 insertions(+), 5 deletions(-)
Paul Brook - Jan. 25, 2013, 6:57 p.m.
> @@ -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()
>      }
>  };

> @@ -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);
> +
> +    tdk_init(&s->phy);
> +    mdio_attach(&s->mdio_bus, &s->phy, 0);
>      /* ??? Save/restore.  */
>      return 0;
>  }

There's no reason for smc91c111_state to contain the PHY state.  For devices 
with an off-chip PHY we have no way of knowing which phy is used, or what 
state is required.

The PHY should be a device in its own right, and know how to save/restore 
itself.  smc91c111_init1 should create the PHY, attach it to the MDIO bus, 
then forget about it.

Paul

Patch

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..c1b3678 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,8 +444,16 @@  static void smc91c111_writeb(void *opaque, hwaddr offset,
             /* Multicast table.  */
             /* Not implemented.  */
             return;
-        case 8: case 9: /* Management Interface.  */
-            /* Not implemented.  */
+        case 8: /* Management Interface.  */
+            /* Update MDIO data line status; but only if output is enabled */
+            if (value & 8) {
+                s->mdio_bus.mdio = !!(value & 1);
+            }
+            /* Process the clock */
+            mdio_cycle(&s->mdio_bus, value & 4);
+            return;
+        case 9: /* Management Interface.  */
+            /* Not implemented */
             return;
         case 12: /* Early receive.  */
             s->ercv = value & 0x1f;
@@ -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 | (s->mdio_bus.mdio ? 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);
+
+    tdk_init(&s->phy);
+    mdio_attach(&s->mdio_bus, &s->phy, 0);
     /* ??? Save/restore.  */
     return 0;
 }