diff mbox

[qemu] e1000: CTRL.RST emulation

Message ID 20110927112530.GA10828@redhat.com
State New
Headers show

Commit Message

Michael S. Tsirkin Sept. 27, 2011, 11:25 a.m. UTC
e1000 spec says CTRL.RST write should have the same effect
as bus reset, except that is preserves PCI Config.
Reset device registers and interrupts.

Fix suggested by Andy Gospodarek <andy@greyhouse.net>

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/e1000.c |   97 +++++++++++++++++++++++++++++++----------------------------
 1 files changed, 51 insertions(+), 46 deletions(-)

Comments

Peter Maydell Sept. 27, 2011, 11:50 a.m. UTC | #1
On 27 September 2011 12:25, Michael S. Tsirkin <mst@redhat.com> wrote:
> e1000 spec says CTRL.RST write should have the same effect
> as bus reset, except that is preserves PCI Config.
> Reset device registers and interrupts.
>
> Fix suggested by Andy Gospodarek <andy@greyhouse.net>

Doesn't this have the same effect as this patch:
http://patchwork.ozlabs.org/patch/108673/

except that it's harder to read because it's moved a lot
of code around in the file?

(I think you have an extra qemu_set_irq() call in there,
actually. But it was hard to find. Also your code has the
bug that was in earlier revisions of Anthony's patch where
after doing the reset you fall through and allow other bits
in the ctrl register to be set.)

-- PMM
Michael S. Tsirkin Sept. 27, 2011, 12:32 p.m. UTC | #2
On Tue, Sep 27, 2011 at 12:50:21PM +0100, Peter Maydell wrote:
> On 27 September 2011 12:25, Michael S. Tsirkin <mst@redhat.com> wrote:
> > e1000 spec says CTRL.RST write should have the same effect
> > as bus reset, except that is preserves PCI Config.
> > Reset device registers and interrupts.
> >
> > Fix suggested by Andy Gospodarek <andy@greyhouse.net>
> 
> Doesn't this have the same effect as this patch:
> http://patchwork.ozlabs.org/patch/108673/

Right except mine clears the interrupts as well.
I missed that patch - what happened to it in the end?

> except that it's harder to read because it's moved a lot
> of code around in the file?
> 
> (I think you have an extra qemu_set_irq() call in there,

The device spec says we should reset the interrupts.
So it seems necessary.

> actually. But it was hard to find.

I probably should split the patch out
1. code movement
2. code change

Forward declarations just to work around random
placement of functions in file seem wrong -
why not order the functions sensibly instead?

> Also your code has the
> bug that was in earlier revisions of Anthony's patch where
> after doing the reset you fall through and allow other bits
> in the ctrl register to be set.)
> 
> -- PMM

True.
Peter Maydell Sept. 27, 2011, 12:39 p.m. UTC | #3
On 27 September 2011 13:32, Michael S. Tsirkin <mst@redhat.com> wrote:
> On Tue, Sep 27, 2011 at 12:50:21PM +0100, Peter Maydell wrote:
>> On 27 September 2011 12:25, Michael S. Tsirkin <mst@redhat.com> wrote:
>> > e1000 spec says CTRL.RST write should have the same effect
>> > as bus reset, except that is preserves PCI Config.
>> > Reset device registers and interrupts.
>> >
>> > Fix suggested by Andy Gospodarek <andy@greyhouse.net>
>>
>> Doesn't this have the same effect as this patch:
>> http://patchwork.ozlabs.org/patch/108673/
>
> Right except mine clears the interrupts as well.

I agree that's required, but why doesn't it belong in
e1000_reset() ? Surely a qdev reset ought also to clear
the output irq signals...
[Disclaimer: this is fishing for somebody to explain to
me what the semantics of qdev reset actually are :-)]

> I missed that patch - what happened to it in the end?

I think it just got lost in the shuffle (Anthony L never
did come back and actually produce a compiler that gave
a warning on it, so I think that was just a misremembering
on his part.)

-- PMM
Michael S. Tsirkin Sept. 27, 2011, 1:09 p.m. UTC | #4
On Tue, Sep 27, 2011 at 01:39:17PM +0100, Peter Maydell wrote:
> On 27 September 2011 13:32, Michael S. Tsirkin <mst@redhat.com> wrote:
> > On Tue, Sep 27, 2011 at 12:50:21PM +0100, Peter Maydell wrote:
> >> On 27 September 2011 12:25, Michael S. Tsirkin <mst@redhat.com> wrote:
> >> > e1000 spec says CTRL.RST write should have the same effect
> >> > as bus reset, except that is preserves PCI Config.
> >> > Reset device registers and interrupts.
> >> >
> >> > Fix suggested by Andy Gospodarek <andy@greyhouse.net>
> >>
> >> Doesn't this have the same effect as this patch:
> >> http://patchwork.ozlabs.org/patch/108673/
> >
> > Right except mine clears the interrupts as well.
> 
> I agree that's required, but why doesn't it belong in
> e1000_reset() ?

I think not, because pci core resets interrupts for us.

> Surely a qdev reset ought also to clear
> the output irq signals...
> [Disclaimer: this is fishing for somebody to explain to
> me what the semantics of qdev reset actually are :-)]

AFAIK what happens is that the qdev is only involved
until we get to the pci root. From then on
pci_bus_reset calls pci_device_reset to reset the device.

> > I missed that patch - what happened to it in the end?
> 
> I think it just got lost in the shuffle (Anthony L never
> did come back and actually produce a compiler that gave
> a warning on it, so I think that was just a misremembering
> on his part.)
> 
> -- PMM

Yes, that just looks strange. So I intend to just stick this
patch in my tree, unless someone NACKs. Then it'll get merged
in due course.
Anthony Liguori Sept. 27, 2011, 2:30 p.m. UTC | #5
On 09/27/2011 06:50 AM, Peter Maydell wrote:
> On 27 September 2011 12:25, Michael S. Tsirkin<mst@redhat.com>  wrote:
>> e1000 spec says CTRL.RST write should have the same effect
>> as bus reset, except that is preserves PCI Config.
>> Reset device registers and interrupts.
>>
>> Fix suggested by Andy Gospodarek<andy@greyhouse.net>
>
> Doesn't this have the same effect as this patch:
> http://patchwork.ozlabs.org/patch/108673/
>
> except that it's harder to read because it's moved a lot
> of code around in the file?
>
> (I think you have an extra qemu_set_irq() call in there,
> actually. But it was hard to find. Also your code has the
> bug that was in earlier revisions of Anthony's patch where
> after doing the reset you fall through and allow other bits
> in the ctrl register to be set.)

I didn't see your note which said not to rend the patch unless I produce a 
compiler that issues a warning.  Since Anthony P. was going to resubmit, I never 
looked into it further.

I honestly don't care at this point which patch gets merged.

Regards,

Anthony Liguori

>
> -- PMM
diff mbox

Patch

diff --git a/hw/e1000.c b/hw/e1000.c
index 6a3a941..81328f4 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -151,6 +151,40 @@  static const char phy_regcap[0x20] = {
     [PHY_ID2] = PHY_R,		[M88E1000_PHY_SPEC_STATUS] = PHY_R
 };
 
+static const uint16_t e1000_eeprom_template[64] = {
+    0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
+    0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040,
+    0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
+    0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
+    0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
+    0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
+};
+
+static const uint16_t phy_reg_init[] = {
+    [PHY_CTRL] = 0x1140,			[PHY_STATUS] = 0x796d, // link initially up
+    [PHY_ID1] = 0x141,				[PHY_ID2] = PHY_ID2_INIT,
+    [PHY_1000T_CTRL] = 0x0e00,			[M88E1000_PHY_SPEC_CTRL] = 0x360,
+    [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,	[PHY_AUTONEG_ADV] = 0xde1,
+    [PHY_LP_ABILITY] = 0x1e0,			[PHY_1000T_STATUS] = 0x3c00,
+    [M88E1000_PHY_SPEC_STATUS] = 0xac00,
+};
+
+static const uint32_t mac_reg_init[] = {
+    [PBA] =     0x00100030,
+    [LEDCTL] =  0x602,
+    [CTRL] =    E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
+                E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
+    [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
+                E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
+                E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
+                E1000_STATUS_LU,
+    [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
+                E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
+                E1000_MANC_RMCP_EN,
+};
+
 static void
 set_interrupt_cause(E1000State *s, int index, uint32_t val)
 {
@@ -192,9 +226,26 @@  rxbufsize(uint32_t v)
     return 2048;
 }
 
+static void e1000_reset(void *opaque)
+{
+    E1000State *d = opaque;
+
+    memset(d->phy_reg, 0, sizeof d->phy_reg);
+    memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
+    memset(d->mac_reg, 0, sizeof d->mac_reg);
+    memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
+    d->rxbuf_min_shift = 1;
+    memset(&d->tx, 0, sizeof d->tx);
+}
+
 static void
 set_ctrl(E1000State *s, int index, uint32_t val)
 {
+    if (val & E1000_CTRL_RST) {
+        e1000_reset(s);
+        qemu_set_irq(s->dev.irq[0], 0);
+    }
+
     /* RST is self clearing */
     s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
 }
@@ -1047,40 +1098,6 @@  static const VMStateDescription vmstate_e1000 = {
     }
 };
 
-static const uint16_t e1000_eeprom_template[64] = {
-    0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
-    0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040,
-    0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
-    0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
-    0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
-    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
-    0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
-    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
-};
-
-static const uint16_t phy_reg_init[] = {
-    [PHY_CTRL] = 0x1140,			[PHY_STATUS] = 0x796d, // link initially up
-    [PHY_ID1] = 0x141,				[PHY_ID2] = PHY_ID2_INIT,
-    [PHY_1000T_CTRL] = 0x0e00,			[M88E1000_PHY_SPEC_CTRL] = 0x360,
-    [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,	[PHY_AUTONEG_ADV] = 0xde1,
-    [PHY_LP_ABILITY] = 0x1e0,			[PHY_1000T_STATUS] = 0x3c00,
-    [M88E1000_PHY_SPEC_STATUS] = 0xac00,
-};
-
-static const uint32_t mac_reg_init[] = {
-    [PBA] =     0x00100030,
-    [LEDCTL] =  0x602,
-    [CTRL] =    E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
-                E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
-    [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
-                E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
-                E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
-                E1000_STATUS_LU,
-    [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
-                E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
-                E1000_MANC_RMCP_EN,
-};
-
 /* PCI interface */
 
 static void
@@ -1120,18 +1137,6 @@  pci_e1000_uninit(PCIDevice *dev)
     return 0;
 }
 
-static void e1000_reset(void *opaque)
-{
-    E1000State *d = opaque;
-
-    memset(d->phy_reg, 0, sizeof d->phy_reg);
-    memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
-    memset(d->mac_reg, 0, sizeof d->mac_reg);
-    memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
-    d->rxbuf_min_shift = 1;
-    memset(&d->tx, 0, sizeof d->tx);
-}
-
 static NetClientInfo net_e1000_info = {
     .type = NET_CLIENT_TYPE_NIC,
     .size = sizeof(NICState),