qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus
@ 2016-12-30 15:21 minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 01/19] i2c: Allow I2C devices to NAK start events minyard
                   ` (18 more replies)
  0 siblings, 19 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard

I've had this working for a while, primarily for my own testing
capability, but I guess I should put it out there for other people
as this interface is starting to show up in ARM64 devices and maybe
it's useful to others.

It's actually a few sets of patches that each accomplish a different
things, but all required for full function of the device.

[PATCH 01/19] i2c: Allow I2C devices to NAK start events
[PATCH 02/19] i2c-smbus: Use a int for return

The above two are more general bug fixes.  The first has already
been sent out, it's required for the SMBus alert device and for
IPMI to be able to NAK when they have no data.  The second is just
a little bug fix, and may not be strictly necessary.

[PATCH 03/19] i2c:pm_smbus: Clean up some style issues
[PATCH 04/19] i2c:pm_smbus: Fix the semantics of block I2C transfers
[PATCH 05/19] i2c:pm_smbus: Make the I2C block read command read-only
[PATCH 06/19] i2c:pm_smbus: Add block transfer capability
[PATCH 07/19] i2c:pm_smbus: Fix state transfer
[PATCH 08/19] i2c:pm_smbus: Add interrupt handling
[PATCH 09/19] i2c:pm_smbus: Add the ability to force block transfer

The above changes fix the pm_smbus device so it works properly and so
it can do block transfers, which are required by IPMI.

[PATCH 10/19] ipmi: Add an SMBus IPMI interface
[PATCH 11/19] acpi: Add i2c serial bus CRS handling
[PATCH 12/19] ipmi: Fix SSIF ACPI handling to use the right CRS
[PATCH 13/19] pc: Add _enabled to the end of some boolean flags
[PATCH 14/19] pc: Add an SMB0 ACPI device to q35

The above add the IPMI on SMBus device itself and then add the ACPI
handling for it.

[PATCH 15/19] hw: Add an IRQ interface
[PATCH 16/19] isa: Add an irq device.

I'm not sure about the above patches.  They add a generic "interrupt"
device then add an ISA version of them.  The SMBus alert device
requires an interrupt of some type.  It seemed like having a generic
interrupt that could be tied to a device was a nice feature, it would
keep from having to have a separate isa/pci/whatever version of
the alert device for something that was on an I2C bus.  But I'm not
really sure this is the best way.

[PATCH 17/19] i2c: Allow SMBus device to NAK start events
[PATCH 18/19] i2c: Add an SMBus alert device.
[PATCH 19/19] ipmi_smbus: Add alert capability to the IPMI SSIF code

The above add an SMBus alert device.  It's basically something that
muxes "interrupt" signals from I2C device onto a single interrupt and
allows the I2C master to fetch which I2C device in sending the
interrupt.  This allows the IPMI device to tell the host that it has
something ready for it, thus really speeding things up.

-corey

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 01/19] i2c: Allow I2C devices to NAK start events
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 02/19] i2c-smbus: Use a int for return minyard
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

Add a return value to the event handler.  Some I2C devices will
NAK if they have no data, so allow them to do this.  This required
the following changes:

Go through all the event handlers and change them to return int
and return 0.

Modify i2c_start_transfer to terminate the transaction on a NAK.

Modify smbus handing to not assert if a NAK occurs on a second
operation, and terminate the transaction and return -1 instead.

Add some information on semantics to I2CSlaveClass.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/arm/pxa2xx.c      |  4 +++-
 hw/arm/tosa.c        |  4 +++-
 hw/arm/z2.c          |  4 +++-
 hw/audio/wm8750.c    |  4 +++-
 hw/display/ssd0303.c |  4 +++-
 hw/gpio/max7310.c    |  4 +++-
 hw/i2c/core.c        | 31 +++++++++++++++++++++++++------
 hw/i2c/i2c-ddc.c     |  4 +++-
 hw/i2c/smbus.c       | 13 +++++++++----
 hw/input/lm832x.c    |  4 +++-
 hw/misc/tmp105.c     |  3 ++-
 hw/timer/ds1338.c    |  4 +++-
 hw/timer/twl92230.c  |  4 +++-
 include/hw/i2c/i2c.h | 16 ++++++++++++----
 14 files changed, 78 insertions(+), 25 deletions(-)

diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index bdcf6bc..d31b457 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1258,7 +1258,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s)
 }
 
 /* These are only stubs now.  */
-static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
+static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
 {
     PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
     PXA2xxI2CState *s = slave->host;
@@ -1280,6 +1280,8 @@ static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
         break;
     }
     pxa2xx_i2c_update(s);
+
+    return 0;
 }
 
 static int pxa2xx_i2c_rx(I2CSlave *i2c)
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
index 39d9dbb..c3db996 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -172,7 +172,7 @@ static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
+static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
 {
     TosaDACState *s = TOSA_DAC(i2c);
 
@@ -194,6 +194,8 @@ static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
     default:
         break;
     }
+
+    return 0;
 }
 
 static int tosa_dac_recv(I2CSlave *s)
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index b3a6bbd..1607cbd 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -220,7 +220,7 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void aer915_event(I2CSlave *i2c, enum i2c_event event)
+static int aer915_event(I2CSlave *i2c, enum i2c_event event)
 {
     AER915State *s = AER915(i2c);
 
@@ -238,6 +238,8 @@ static void aer915_event(I2CSlave *i2c, enum i2c_event event)
     default:
         break;
     }
+
+    return 0;
 }
 
 static int aer915_recv(I2CSlave *slave)
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
index 0c6500e..f8b5beb 100644
--- a/hw/audio/wm8750.c
+++ b/hw/audio/wm8750.c
@@ -303,7 +303,7 @@ static void wm8750_reset(I2CSlave *i2c)
     s->i2c_len = 0;
 }
 
-static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
+static int wm8750_event(I2CSlave *i2c, enum i2c_event event)
 {
     WM8750State *s = WM8750(i2c);
 
@@ -321,6 +321,8 @@ static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
     default:
         break;
     }
+
+    return 0;
 }
 
 #define WM8750_LINVOL	0x00
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index d301756..68a80b9 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -179,7 +179,7 @@ static int ssd0303_send(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
+static int ssd0303_event(I2CSlave *i2c, enum i2c_event event)
 {
     ssd0303_state *s = SSD0303(i2c);
 
@@ -193,6 +193,8 @@ static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
         /* Nothing to do.  */
         break;
     }
+
+    return 0;
 }
 
 static void ssd0303_update_display(void *opaque)
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
index 1bd5eaf..f82e3e6 100644
--- a/hw/gpio/max7310.c
+++ b/hw/gpio/max7310.c
@@ -129,7 +129,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void max7310_event(I2CSlave *i2c, enum i2c_event event)
+static int max7310_event(I2CSlave *i2c, enum i2c_event event)
 {
     MAX7310State *s = MAX7310(i2c);
     s->len = 0;
@@ -147,6 +147,8 @@ static void max7310_event(I2CSlave *i2c, enum i2c_event event)
     default:
         break;
     }
+
+    return 0;
 }
 
 static const VMStateDescription vmstate_max7310 = {
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index e40781e..2c1234c 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -88,18 +88,26 @@ int i2c_bus_busy(I2CBus *bus)
     return !QLIST_EMPTY(&bus->current_devs);
 }
 
+/* TODO: Make this handle multiple masters.  */
 /*
- * Returns non-zero if the address is not valid.  If this is called
- * again without an intervening i2c_end_transfer(), like in the SMBus
- * case where the operation is switched from write to read, this
- * function will not rescan the bus and thus cannot fail.
+ * Start or continue an i2c transaction.  When this is called for the
+ * first time or after an i2c_end_transfer(), if it returns an error
+ * the bus transaction is terminated (or really never started).  If
+ * this is called after another i2c_start_transfer() without an
+ * intervening i2c_end_transfer(), and it returns an error, the
+ * transaction will not be terminated.  The caller must do it.
+ *
+ * This corresponds with the way real hardware works.  The SMBus
+ * protocol uses a start transfer to switch from write to read mode
+ * without releasing the bus.  If that fails, the bus is still
+ * in a transaction.
  */
-/* TODO: Make this handle multiple masters.  */
 int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
 {
     BusChild *kid;
     I2CSlaveClass *sc;
     I2CNode *node;
+    bool bus_scanned = false;
 
     if (address == I2C_BROADCAST) {
         /*
@@ -130,6 +138,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
                 }
             }
         }
+        bus_scanned = true;
     }
 
     if (QLIST_EMPTY(&bus->current_devs)) {
@@ -137,11 +146,21 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
     }
 
     QLIST_FOREACH(node, &bus->current_devs, next) {
+        int rv;
+
         sc = I2C_SLAVE_GET_CLASS(node->elt);
         /* If the bus is already busy, assume this is a repeated
            start condition.  */
+
         if (sc->event) {
-            sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
+            rv = sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
+            if (rv && !bus->broadcast) {
+                if (bus_scanned) {
+                    /* First call, terminate the transfer. */
+                    i2c_end_transfer(bus);
+                }
+                return rv;
+            }
         }
     }
     return 0;
diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c
index 1227212..66899d7 100644
--- a/hw/i2c/i2c-ddc.c
+++ b/hw/i2c/i2c-ddc.c
@@ -230,13 +230,15 @@ static void i2c_ddc_reset(DeviceState *ds)
     s->reg = 0;
 }
 
-static void i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
+static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
 {
     I2CDDCState *s = I2CDDC(i2c);
 
     if (event == I2C_START_SEND) {
         s->firstbyte = true;
     }
+
+    return 0;
 }
 
 static int i2c_ddc_rx(I2CSlave *i2c)
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index 5b4dd3e..2d1b79a 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -67,7 +67,7 @@ static void smbus_do_write(SMBusDevice *dev)
     }
 }
 
-static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
+static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
 {
     SMBusDevice *dev = SMBUS_DEVICE(s);
 
@@ -148,6 +148,8 @@ static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
             break;
         }
     }
+
+    return 0;
 }
 
 static int smbus_i2c_recv(I2CSlave *s)
@@ -249,7 +251,8 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
     }
     i2c_send(bus, command);
     if (i2c_start_transfer(bus, addr, 1)) {
-        assert(0);
+        i2c_end_transfer(bus);
+        return -1;
     }
     data = i2c_recv(bus);
     i2c_nack(bus);
@@ -276,7 +279,8 @@ int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
     }
     i2c_send(bus, command);
     if (i2c_start_transfer(bus, addr, 1)) {
-        assert(0);
+        i2c_end_transfer(bus);
+        return -1;
     }
     data = i2c_recv(bus);
     data |= i2c_recv(bus) << 8;
@@ -307,7 +311,8 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
     }
     i2c_send(bus, command);
     if (i2c_start_transfer(bus, addr, 1)) {
-        assert(0);
+        i2c_end_transfer(bus);
+        return -1;
     }
     len = i2c_recv(bus);
     if (len > 32) {
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
index 539682c..2340523 100644
--- a/hw/input/lm832x.c
+++ b/hw/input/lm832x.c
@@ -383,7 +383,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
     }
 }
 
-static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
+static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
 {
     LM823KbdState *s = LM8323(i2c);
 
@@ -397,6 +397,8 @@ static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
     default:
         break;
     }
+
+    return 0;
 }
 
 static int lm_i2c_rx(I2CSlave *i2c)
diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c
index f5c2472..04e8378 100644
--- a/hw/misc/tmp105.c
+++ b/hw/misc/tmp105.c
@@ -176,7 +176,7 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
+static int tmp105_event(I2CSlave *i2c, enum i2c_event event)
 {
     TMP105State *s = TMP105(i2c);
 
@@ -185,6 +185,7 @@ static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
     }
 
     s->len = 0;
+    return 0;
 }
 
 static int tmp105_post_load(void *opaque, int version_id)
diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index f5d04dd..3849b74 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -94,7 +94,7 @@ static void inc_regptr(DS1338State *s)
     }
 }
 
-static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
+static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
 {
     DS1338State *s = DS1338(i2c);
 
@@ -113,6 +113,8 @@ static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
     default:
         break;
     }
+
+    return 0;
 }
 
 static int ds1338_recv(I2CSlave *i2c)
diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c
index 7ba4e9a..b8d914e 100644
--- a/hw/timer/twl92230.c
+++ b/hw/timer/twl92230.c
@@ -713,12 +713,14 @@ static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
     }
 }
 
-static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
+static int menelaus_event(I2CSlave *i2c, enum i2c_event event)
 {
     MenelausState *s = TWL92230(i2c);
 
     if (event == I2C_START_SEND)
         s->firstbyte = 1;
+
+    return 0;
 }
 
 static int menelaus_tx(I2CSlave *i2c, uint8_t data)
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index c4085aa..2ce611d 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -32,14 +32,22 @@ typedef struct I2CSlaveClass
     /* Callbacks provided by the device.  */
     int (*init)(I2CSlave *dev);
 
-    /* Master to slave.  */
+    /* Master to slave. Returns non-zero for a NAK, 0 for success. */
     int (*send)(I2CSlave *s, uint8_t data);
 
-    /* Slave to master.  */
+    /*
+     * Slave to master.  This cannot fail, the device should always
+     * return something here.  Negative values probably result in 0xff
+     * and a possible log from the driver, and shouldn't be used.
+     */
     int (*recv)(I2CSlave *s);
 
-    /* Notify the slave of a bus state change.  */
-    void (*event)(I2CSlave *s, enum i2c_event event);
+    /*
+     * Notify the slave of a bus state change.  For start event,
+     * returns non-zero to NAK an operation.  For other events the
+     * return code is not used and should be zero.
+     */
+    int (*event)(I2CSlave *s, enum i2c_event event);
 } I2CSlaveClass;
 
 struct I2CSlave
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 02/19] i2c-smbus: Use a int for return
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 01/19] i2c: Allow I2C devices to NAK start events minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 03/19] i2c:pm_smbus: Clean up some style issues minyard
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

The return value from getting the data may be an error, so
use an integer to hold it.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/smbus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index 2d1b79a..c631a1c 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -222,7 +222,7 @@ int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
 
 int smbus_receive_byte(I2CBus *bus, uint8_t addr)
 {
-    uint8_t data;
+    int data;
 
     if (i2c_start_transfer(bus, addr, 1)) {
         return -1;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 03/19] i2c:pm_smbus: Clean up some style issues
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 01/19] i2c: Allow I2C devices to NAK start events minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 02/19] i2c-smbus: Use a int for return minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 04/19] i2c:pm_smbus: Fix the semantics of block I2C transfers minyard
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

Fix some spacing issues, remove extraneous comments, add some
defines instead of hard-coding numbers.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/pm_smbus.c | 58 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 38 insertions(+), 20 deletions(-)

diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 6fc3923..92c3aebd 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -23,8 +23,6 @@
 #include "hw/i2c/pm_smbus.h"
 #include "hw/i2c/smbus.h"
 
-/* no save/load? */
-
 #define SMBHSTSTS       0x00
 #define SMBHSTCNT       0x02
 #define SMBHSTCMD       0x03
@@ -33,19 +31,34 @@
 #define SMBHSTDAT1      0x06
 #define SMBBLKDAT       0x07
 
-#define STS_HOST_BUSY   (1)
-#define STS_INTR        (1<<1)
-#define STS_DEV_ERR     (1<<2)
-#define STS_BUS_ERR     (1<<3)
-#define STS_FAILED      (1<<4)
-#define STS_SMBALERT    (1<<5)
-#define STS_INUSE_STS   (1<<6)
-#define STS_BYTE_DONE   (1<<7)
+#define STS_HOST_BUSY   (1 << 0)
+#define STS_INTR        (1 << 1)
+#define STS_DEV_ERR     (1 << 2)
+#define STS_BUS_ERR     (1 << 3)
+#define STS_FAILED      (1 << 4)
+#define STS_SMBALERT    (1 << 5)
+#define STS_INUSE_STS   (1 << 6)
+#define STS_BYTE_DONE   (1 << 7)
 /* Signs of successfully transaction end :
 *  ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR )
 */
 
-//#define DEBUG
+#define CTL_INTREN      (1 << 0)
+#define CTL_KILL        (1 << 1)
+#define CTL_LAST_BYTE   (1 << 5)
+#define CTL_START       (1 << 6)
+#define CTL_PEC_EN      (1 << 7)
+#define CTL_RETURN_MASK 0x1f
+
+#define PROT_QUICK          0
+#define PROT_BYTE           1
+#define PROT_BYTE_DATA      2
+#define PROT_WORD_DATA      3
+#define PROT_PROC_CALL      4
+#define PROT_BLOCK_DATA     5
+#define PROT_I2C_BLOCK_DATA 6
+
+/*#define DEBUG*/
 
 #ifdef DEBUG
 # define SMBUS_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
@@ -68,11 +81,12 @@ static void smb_transaction(PMSMBus *s)
     if ((s->smb_stat & STS_DEV_ERR) != 0)  {
         goto error;
     }
+
     switch(prot) {
-    case 0x0:
+    case PROT_QUICK:
         ret = smbus_quick_command(bus, addr, read);
         goto done;
-    case 0x1:
+    case PROT_BYTE:
         if (read) {
             ret = smbus_receive_byte(bus, addr);
             goto data8;
@@ -80,7 +94,7 @@ static void smb_transaction(PMSMBus *s)
             ret = smbus_send_byte(bus, addr, cmd);
             goto done;
         }
-    case 0x2:
+    case PROT_BYTE_DATA:
         if (read) {
             ret = smbus_read_byte(bus, addr, cmd);
             goto data8;
@@ -89,16 +103,17 @@ static void smb_transaction(PMSMBus *s)
             goto done;
         }
         break;
-    case 0x3:
+    case PROT_WORD_DATA:
         if (read) {
             ret = smbus_read_word(bus, addr, cmd);
             goto data16;
         } else {
-            ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
+            ret = smbus_write_word(bus, addr, cmd,
+                                   (s->smb_data1 << 8) | s->smb_data0);
             goto done;
         }
         break;
-    case 0x5:
+    case PROT_I2C_BLOCK_DATA:
         if (read) {
             ret = smbus_read_block(bus, addr, cmd, s->smb_data);
             goto data8;
@@ -149,8 +164,9 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
         break;
     case SMBHSTCNT:
         s->smb_ctl = val;
-        if (val & 0x40)
+        if (s->smb_ctl & CTL_START) {
             smb_transaction(s);
+        }
         break;
     case SMBHSTCMD:
         s->smb_cmd = val;
@@ -185,7 +201,7 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
         break;
     case SMBHSTCNT:
         s->smb_index = 0;
-        val = s->smb_ctl & 0x1f;
+        val = s->smb_ctl & CTL_RETURN_MASK;
         break;
     case SMBHSTCMD:
         val = s->smb_cmd;
@@ -208,7 +224,9 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
         val = 0;
         break;
     }
-    SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", addr, val);
+    SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n",
+                  addr, val);
+
     return val;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 04/19] i2c:pm_smbus: Fix the semantics of block I2C transfers
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (2 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 03/19] i2c:pm_smbus: Clean up some style issues minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 05/19] i2c:pm_smbus: Make the I2C block read command read-only minyard
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

The I2C block transfer commands was not implemented correctly, it
read a length byte and such like it was an smbus transfer.

So fix the smbus_read_block() and smbus_write_block() functions
so they can properly handle I2C transfers, and normal SMBus
transfers (for upcoming changes).  Pass in a transfer size and
a bool to know whether to use the size byte (like SMBus) or use
the length given (like I2C).

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/pm_smbus.c      | 10 ++++++++--
 hw/i2c/smbus.c         | 37 ++++++++++++++++++++++++-------------
 include/hw/i2c/smbus.h | 17 +++++++++++++++--
 3 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 92c3aebd..679edbc 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -115,10 +115,16 @@ static void smb_transaction(PMSMBus *s)
         break;
     case PROT_I2C_BLOCK_DATA:
         if (read) {
-            ret = smbus_read_block(bus, addr, cmd, s->smb_data);
+            int xfersize = s->smb_data0;
+            if (xfersize > sizeof(s->smb_data)) {
+                xfersize = sizeof(s->smb_data);
+            }
+            ret = smbus_read_block(bus, addr, s->smb_data1, s->smb_data,
+                                   xfersize, false, true);
             goto data8;
         } else {
-            ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
+            ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0,
+                                    false);
             goto done;
         }
         break;
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index c631a1c..4cb651e 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -301,33 +301,42 @@ int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
     return 0;
 }
 
-int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
+int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+                     int len, bool recv_len, bool send_cmd)
 {
-    int len;
+    int rlen;
     int i;
 
-    if (i2c_start_transfer(bus, addr, 0)) {
-        return -1;
+    if (send_cmd) {
+        if (i2c_start_transfer(bus, addr, 0)) {
+            return -1;
+        }
+        i2c_send(bus, command);
     }
-    i2c_send(bus, command);
     if (i2c_start_transfer(bus, addr, 1)) {
-        i2c_end_transfer(bus);
+        if (send_cmd) {
+            i2c_end_transfer(bus);
+        }
         return -1;
     }
-    len = i2c_recv(bus);
-    if (len > 32) {
-        len = 0;
+    if (recv_len) {
+        rlen = i2c_recv(bus);
+    } else {
+        rlen = len;
     }
-    for (i = 0; i < len; i++) {
+    if (rlen > len) {
+        rlen = 0;
+    }
+    for (i = 0; i < rlen; i++) {
         data[i] = i2c_recv(bus);
     }
     i2c_nack(bus);
     i2c_end_transfer(bus);
-    return len;
+    return rlen;
 }
 
 int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
-                      int len)
+                      int len, bool send_len)
 {
     int i;
 
@@ -338,7 +347,9 @@ int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
         return -1;
     }
     i2c_send(bus, command);
-    i2c_send(bus, len);
+    if (send_len) {
+        i2c_send(bus, len);
+    }
     for (i = 0; i < len; i++) {
         i2c_send(bus, data[i]);
     }
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index 544bbc1..f1b8078 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -73,9 +73,22 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command);
 int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data);
 int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command);
 int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data);
-int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data);
+
+/*
+ * Do a block transfer from an I2C device.  If recv_len is set, then the
+ * first received byte is a length field and is used to know how much data
+ * to receive.  Otherwise receive "len" bytes.  If send_cmd is set, send
+ * the command byte first before receiving the data.
+ */
+int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+                     int len, bool recv_len, bool send_cmd);
+
+/*
+ * Do a block transfer to an I2C device.  If send_len is set, send the
+ * "len" value before the data.
+ */
 int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
-                      int len);
+                      int len, bool send_len);
 
 void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
                        const uint8_t *eeprom_spd, int size);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 05/19] i2c:pm_smbus: Make the I2C block read command read-only
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (3 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 04/19] i2c:pm_smbus: Fix the semantics of block I2C transfers minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 06/19] i2c:pm_smbus: Add block transfer capability minyard
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

It did have write capability, but the manual says the behavior
with write enabled is undefined.  So just set an error in this
case.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/pm_smbus.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 679edbc..e7a8e92 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -56,7 +56,7 @@
 #define PROT_WORD_DATA      3
 #define PROT_PROC_CALL      4
 #define PROT_BLOCK_DATA     5
-#define PROT_I2C_BLOCK_DATA 6
+#define PROT_I2C_BLOCK_READ 6
 
 /*#define DEBUG*/
 
@@ -113,7 +113,7 @@ static void smb_transaction(PMSMBus *s)
             goto done;
         }
         break;
-    case PROT_I2C_BLOCK_DATA:
+    case PROT_I2C_BLOCK_READ:
         if (read) {
             int xfersize = s->smb_data0;
             if (xfersize > sizeof(s->smb_data)) {
@@ -123,9 +123,8 @@ static void smb_transaction(PMSMBus *s)
                                    xfersize, false, true);
             goto data8;
         } else {
-            ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0,
-                                    false);
-            goto done;
+            /* The manual says the behavior is undefined, just set DEV_ERR. */
+            goto error;
         }
         break;
     default:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 06/19] i2c:pm_smbus: Add block transfer capability
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (4 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 05/19] i2c:pm_smbus: Make the I2C block read command read-only minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 07/19] i2c:pm_smbus: Fix state transfer minyard
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

There was no block transfer code in pm_smbus.c, and it is needed
for some devices.  So add it.

This adds both byte-by-byte block transfers and buffered block
transfers.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/pm_smbus.c         | 151 ++++++++++++++++++++++++++++++++++++++++++----
 hw/i2c/smbus_ich9.c       |   8 ++-
 include/hw/i2c/pm_smbus.h |  20 +++++-
 3 files changed, 164 insertions(+), 15 deletions(-)

diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index e7a8e92..686d411 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -30,6 +30,7 @@
 #define SMBHSTDAT0      0x05
 #define SMBHSTDAT1      0x06
 #define SMBBLKDAT       0x07
+#define SMBAUXCTL       0x0d
 
 #define STS_HOST_BUSY   (1 << 0)
 #define STS_INTR        (1 << 1)
@@ -58,6 +59,10 @@
 #define PROT_BLOCK_DATA     5
 #define PROT_I2C_BLOCK_READ 6
 
+#define AUX_PEC       (1 << 0)
+#define AUX_BLK       (1 << 1)
+#define AUX_MASK      0x3
+
 /*#define DEBUG*/
 
 #ifdef DEBUG
@@ -127,6 +132,51 @@ static void smb_transaction(PMSMBus *s)
             goto error;
         }
         break;
+    case PROT_BLOCK_DATA:
+        if (read) {
+            ret = smbus_read_block(bus, addr, cmd, s->smb_data,
+                                   sizeof(s->smb_data), !s->i2c_enable,
+                                   !s->i2c_enable);
+            if (ret < 0) {
+                goto error;
+            }
+            s->smb_index = 0;
+            s->op_done = false;
+            if (s->smb_auxctl & AUX_BLK) {
+                s->smb_stat |= STS_INTR;
+            } else {
+                s->smb_blkdata = s->smb_data[0];
+                s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
+            }
+            s->smb_data0 = ret;
+            goto out;
+        } else {
+            if (s->smb_auxctl & AUX_BLK) {
+                if (s->smb_index != s->smb_data0) {
+                    s->smb_index = 0;
+                    goto error;
+                }
+                /* Data is already all written to the queue, just do
+                   the operation. */
+                s->smb_index = 0;
+                ret = smbus_write_block(bus, addr, cmd, s->smb_data,
+                                        s->smb_data0, !s->i2c_enable);
+                if (ret < 0) {
+                    goto error;
+                }
+                s->op_done = true;
+                s->smb_stat |= STS_INTR;
+                s->smb_stat &= ~STS_HOST_BUSY;
+            } else {
+                s->op_done = false;
+                s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
+                s->smb_data[0] = s->smb_blkdata;
+                s->smb_index = 0;
+                ret = 0;
+            }
+            goto out;
+        }
+        break;
     default:
         goto error;
     }
@@ -146,13 +196,13 @@ done:
     if (ret < 0) {
         goto error;
     }
-    s->smb_stat |= STS_BYTE_DONE | STS_INTR;
+    s->smb_stat |= STS_INTR;
+out:
     return;
 
 error:
     s->smb_stat |= STS_DEV_ERR;
     return;
-
 }
 
 static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
@@ -164,14 +214,61 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
                   " val=0x%02" PRIx64 "\n", addr, val);
     switch(addr) {
     case SMBHSTSTS:
-        s->smb_stat = (~(val & 0xff)) & s->smb_stat;
-        s->smb_index = 0;
+        s->smb_stat &= ~(val & ~STS_HOST_BUSY);
+        if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) {
+            uint8_t read = s->smb_addr & 0x01;
+
+            s->smb_index++;
+            if (!read && s->smb_index == s->smb_data0) {
+                uint8_t prot = (s->smb_ctl >> 2) & 0x07;
+                uint8_t cmd = s->smb_cmd;
+                uint8_t addr = s->smb_addr >> 1;
+                int ret;
+
+                if (prot == PROT_I2C_BLOCK_READ) {
+                    s->smb_stat |= STS_DEV_ERR;
+                    goto out;
+                }
+
+                ret = smbus_write_block(s->smbus, addr, cmd, s->smb_data,
+                                        s->smb_data0, !s->i2c_enable);
+                if (ret < 0) {
+                    s->smb_stat |= STS_DEV_ERR;
+                    goto out;
+                }
+                s->op_done = true;
+                s->smb_stat |= STS_INTR;
+                s->smb_stat &= ~STS_HOST_BUSY;
+            } else if (!read) {
+                s->smb_data[s->smb_index] = s->smb_blkdata;
+                s->smb_stat |= STS_BYTE_DONE;
+            } else if (s->smb_ctl & CTL_LAST_BYTE) {
+                s->op_done = true;
+                s->smb_blkdata = s->smb_data[s->smb_index];
+                s->smb_index = 0;
+                s->smb_stat |= STS_INTR;
+                s->smb_stat &= ~STS_HOST_BUSY;
+            } else {
+                s->smb_blkdata = s->smb_data[s->smb_index];
+                s->smb_stat |= STS_BYTE_DONE;
+            }
+        }
         break;
     case SMBHSTCNT:
-        s->smb_ctl = val;
-        if (s->smb_ctl & CTL_START) {
+        s->smb_ctl = val & ~CTL_START; /* CTL_START always reads 0 */
+        if (val & CTL_START) {
+            if (!s->op_done) {
+                s->smb_index = 0;
+                s->op_done = true;
+            }
             smb_transaction(s);
         }
+        if (s->smb_ctl & CTL_KILL) {
+            s->op_done = true;
+            s->smb_index = 0;
+            s->smb_stat |= STS_FAILED;
+            s->smb_stat &= ~STS_HOST_BUSY;
+        }
         break;
     case SMBHSTCMD:
         s->smb_cmd = val;
@@ -186,13 +283,24 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
         s->smb_data1 = val;
         break;
     case SMBBLKDAT:
-        s->smb_data[s->smb_index++] = val;
-        if (s->smb_index > 31)
+        if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
             s->smb_index = 0;
+        }
+        if (s->smb_auxctl & AUX_BLK) {
+            s->smb_data[s->smb_index++] = val;
+        } else {
+            s->smb_blkdata = val;
+        }
+        break;
+    case SMBAUXCTL:
+        s->smb_auxctl = val & AUX_MASK;
         break;
     default:
         break;
     }
+
+ out:
+    return;
 }
 
 static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
@@ -205,7 +313,6 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
         val = s->smb_stat;
         break;
     case SMBHSTCNT:
-        s->smb_index = 0;
         val = s->smb_ctl & CTL_RETURN_MASK;
         break;
     case SMBHSTCMD:
@@ -221,9 +328,22 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
         val = s->smb_data1;
         break;
     case SMBBLKDAT:
-        val = s->smb_data[s->smb_index++];
-        if (s->smb_index > 31)
+        if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
             s->smb_index = 0;
+        }
+        if (s->smb_auxctl & AUX_BLK) {
+            val = s->smb_data[s->smb_index++];
+            if (!s->op_done && s->smb_index == s->smb_data0) {
+                s->op_done = true;
+                s->smb_index = 0;
+                s->smb_stat &= ~STS_HOST_BUSY;
+            }
+        } else {
+            val = s->smb_blkdata;
+        }
+        break;
+    case SMBAUXCTL:
+        val = s->smb_auxctl;
         break;
     default:
         val = 0;
@@ -235,6 +355,13 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
     return val;
 }
 
+static void pm_smbus_reset(PMSMBus *s)
+{
+    s->op_done = true;
+    s->smb_index = 0;
+    s->smb_stat = 0;
+}
+
 static const MemoryRegionOps pm_smbus_ops = {
     .read = smb_ioport_readb,
     .write = smb_ioport_writeb,
@@ -245,6 +372,8 @@ static const MemoryRegionOps pm_smbus_ops = {
 
 void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
 {
+    smb->op_done = true;
+    smb->reset = pm_smbus_reset;
     smb->smbus = i2c_init_bus(parent, "i2c");
     memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb,
                           "pm-smbus", 64);
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 48fab22..686ed09 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -62,12 +62,16 @@ static void ich9_smbus_write_config(PCIDevice *d, uint32_t address,
     pci_default_write_config(d, address, val, len);
     if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) {
         uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
-        if ((hostc & ICH9_SMB_HOSTC_HST_EN) &&
-            !(hostc & ICH9_SMB_HOSTC_I2C_EN)) {
+        if (hostc & ICH9_SMB_HOSTC_HST_EN) {
             memory_region_set_enabled(&s->smb.io, true);
         } else {
             memory_region_set_enabled(&s->smb.io, false);
         }
+        s->smb.i2c_enable = (hostc & ICH9_SMB_HOSTC_I2C_EN) != 0;
+        if (hostc & ICH9_SMB_HOSTC_SSRESET) {
+            s->smb.reset(&s->smb);
+            s->dev.config[ICH9_SMB_HOSTC] &= ~ICH9_SMB_HOSTC_SSRESET;
+        }
     }
 }
 
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index 2a837af..99d5489 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -1,6 +1,8 @@
 #ifndef PM_SMBUS_H
 #define PM_SMBUS_H
 
+#define PM_SMBUS_MAX_MSG_SIZE 32
+
 typedef struct PMSMBus {
     I2CBus *smbus;
     MemoryRegion io;
@@ -11,8 +13,22 @@ typedef struct PMSMBus {
     uint8_t smb_addr;
     uint8_t smb_data0;
     uint8_t smb_data1;
-    uint8_t smb_data[32];
-    uint8_t smb_index;
+    uint8_t smb_data[PM_SMBUS_MAX_MSG_SIZE];
+    uint8_t smb_blkdata;
+    uint8_t smb_auxctl;
+    uint32_t smb_index;
+
+    /* Set by pm_smbus.c */
+    void (*reset)(struct PMSMBus *s);
+
+    /* Set by the user. */
+    bool i2c_enable;
+
+    /* Internally used by pm_smbus. */
+
+    /* Set on block transfers after the last byte has been read, so the
+       INTR bit can be set at the right time. */
+    bool op_done;
 } PMSMBus;
 
 void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 07/19] i2c:pm_smbus: Fix state transfer
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (5 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 06/19] i2c:pm_smbus: Add block transfer capability minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 08/19] i2c:pm_smbus: Add interrupt handling minyard
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

Transfer the state information for the SMBus registers and
internal data so it will work on a VM transfer.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/acpi/piix4.c           |  1 +
 hw/i2c/pm_smbus.c         | 19 +++++++++++++++++++
 hw/i2c/smbus_ich9.c       |  3 ++-
 include/hw/i2c/pm_smbus.h |  2 ++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 17d36bd..d64b53b 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -321,6 +321,7 @@ static const VMStateDescription vmstate_acpi = {
         VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
         VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
         VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
+        VMSTATE_STRUCT(smb, PIIX4PMState, 1, pmsmb_vmstate, PMSMBus),
         VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState),
         VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
         VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 686d411..92e3cc5 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -370,6 +370,25 @@ static const MemoryRegionOps pm_smbus_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+const VMStateDescription pmsmb_vmstate = {
+    .name = "pmsmb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(smb_stat, PMSMBus),
+        VMSTATE_UINT8(smb_ctl, PMSMBus),
+        VMSTATE_UINT8(smb_cmd, PMSMBus),
+        VMSTATE_UINT8(smb_addr, PMSMBus),
+        VMSTATE_UINT8(smb_data0, PMSMBus),
+        VMSTATE_UINT8(smb_data1, PMSMBus),
+        VMSTATE_VBUFFER_UINT32(smb_data, PMSMBus, 1, NULL, 0, smb_index),
+        VMSTATE_UINT8(smb_auxctl, PMSMBus),
+        VMSTATE_BOOL(i2c_enable, PMSMBus),
+        VMSTATE_BOOL(op_done, PMSMBus),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
 {
     smb->op_done = true;
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 686ed09..85c7260 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -49,7 +49,8 @@ static const VMStateDescription vmstate_ich9_smbus = {
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState),
+        VMSTATE_PCI_DEVICE(dev, ICH9SMBState),
+        VMSTATE_STRUCT(smb, ICH9SMBState, 1, pmsmb_vmstate, PMSMBus),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index 99d5489..b1e1970 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -33,4 +33,6 @@ typedef struct PMSMBus {
 
 void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
 
+extern const VMStateDescription pmsmb_vmstate;
+
 #endif /* PM_SMBUS_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 08/19] i2c:pm_smbus: Add interrupt handling
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (6 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 07/19] i2c:pm_smbus: Fix state transfer minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 09/19] i2c:pm_smbus: Add the ability to force block transfer enable minyard
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

Add the necessary code so that interrupts actually work from
the pm_smbus device.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/pm_smbus.c         | 14 +++++++++++++-
 hw/i2c/smbus_ich9.c       | 17 +++++++++++++++++
 include/hw/i2c/pm_smbus.h |  2 ++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 92e3cc5..8838360 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -205,6 +205,12 @@ error:
     return;
 }
 
+static bool
+smb_irq_value(PMSMBus *s)
+{
+    return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN);
+}
+
 static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
                               unsigned width)
 {
@@ -300,7 +306,9 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
     }
 
  out:
-    return;
+    if (s->set_irq) {
+        s->set_irq(s, smb_irq_value(s));
+    }
 }
 
 static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
@@ -352,6 +360,10 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
     SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n",
                   addr, val);
 
+    if (s->set_irq) {
+        s->set_irq(s, smb_irq_value(s));
+    }
+
     return val;
 }
 
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 85c7260..5bc34de 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -41,6 +41,8 @@
 typedef struct ICH9SMBState {
     PCIDevice dev;
 
+    bool irq_enabled;
+
     PMSMBus smb;
 } ICH9SMBState;
 
@@ -50,6 +52,7 @@ static const VMStateDescription vmstate_ich9_smbus = {
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
         VMSTATE_PCI_DEVICE(dev, ICH9SMBState),
+        VMSTATE_BOOL(irq_enabled, ICH9SMBState),
         VMSTATE_STRUCT(smb, ICH9SMBState, 1, pmsmb_vmstate, PMSMBus),
         VMSTATE_END_OF_LIST()
     }
@@ -111,11 +114,25 @@ static void ich9_smb_class_init(ObjectClass *klass, void *data)
     dc->cannot_instantiate_with_device_add_yet = true;
 }
 
+static void ich9_smb_set_irq(PMSMBus *pmsmb, bool enabled)
+{
+    ICH9SMBState *s = pmsmb->opaque;
+
+    if (enabled == s->irq_enabled) {
+        return;
+    }
+
+    s->irq_enabled = enabled;
+    pci_set_irq(&s->dev, enabled);
+}
+
 I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
 {
     PCIDevice *d =
         pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE);
     ICH9SMBState *s = ICH9_SMB_DEVICE(d);
+    s->smb.set_irq = ich9_smb_set_irq;
+    s->smb.opaque = s;
     return s->smb.smbus;
 }
 
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index b1e1970..cfe596f 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -23,6 +23,8 @@ typedef struct PMSMBus {
 
     /* Set by the user. */
     bool i2c_enable;
+    void (*set_irq)(struct PMSMBus *s, bool enabled);
+    void *opaque;
 
     /* Internally used by pm_smbus. */
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 09/19] i2c:pm_smbus: Add the ability to force block transfer enable
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (7 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 08/19] i2c:pm_smbus: Add interrupt handling minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 10/19] ipmi: Add an SMBus IPMI interface minyard
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

The PIIX4 hardware has block transfer buffer always enabled in
the hardware, but the i801 does not.  Add a parameter to pm_smbus_init
to force on the block transfer so the PIIX4 handler can enable this
by default, as it was disabled by default before.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/acpi/piix4.c           | 2 +-
 hw/i2c/pm_smbus.c         | 5 ++++-
 hw/i2c/smbus_ich9.c       | 2 +-
 hw/isa/vt82c686.c         | 2 +-
 include/hw/i2c/pm_smbus.h | 2 +-
 5 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index d64b53b..b23605b 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -512,7 +512,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
     pci_conf[0x90] = s->smb_io_base | 1;
     pci_conf[0x91] = s->smb_io_base >> 8;
     pci_conf[0xd2] = 0x09;
-    pm_smbus_init(DEVICE(dev), &s->smb);
+    pm_smbus_init(DEVICE(dev), &s->smb, true);
     memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
     memory_region_add_subregion(pci_address_space_io(dev),
                                 s->smb_io_base, &s->smb.io);
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 8838360..4f8046e 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -401,11 +401,14 @@ const VMStateDescription pmsmb_vmstate = {
     }
 };
 
-void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk)
 {
     smb->op_done = true;
     smb->reset = pm_smbus_reset;
     smb->smbus = i2c_init_bus(parent, "i2c");
+    if (force_aux_blk) {
+        smb->smb_auxctl |= AUX_BLK;
+    }
     memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb,
                           "pm-smbus", 64);
 }
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 5bc34de..e9b07c9 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -89,7 +89,7 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp)
     pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
     /* TODO bar0, bar1: 64bit BAR support*/
 
-    pm_smbus_init(&d->qdev, &s->smb);
+    pm_smbus_init(&d->qdev, &s->smb, false);
     pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
                      &s->smb.io);
 }
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 41d5254..3e905c6 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -362,7 +362,7 @@ static void vt82c686b_pm_realize(PCIDevice *dev, Error **errp)
     pci_conf[0x90] = s->smb_io_base | 1;
     pci_conf[0x91] = s->smb_io_base >> 8;
     pci_conf[0xd2] = 0x90;
-    pm_smbus_init(&s->dev.qdev, &s->smb);
+    pm_smbus_init(&s->dev.qdev, &s->smb, false);
     memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io);
 
     apm_init(dev, &s->apm, NULL, s);
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index cfe596f..471345e 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -33,7 +33,7 @@ typedef struct PMSMBus {
     bool op_done;
 } PMSMBus;
 
-void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk);
 
 extern const VMStateDescription pmsmb_vmstate;
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 10/19] ipmi: Add an SMBus IPMI interface
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (8 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 09/19] i2c:pm_smbus: Add the ability to force block transfer enable minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 11/19] acpi: Add i2c serial bus CRS handling minyard
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 default-configs/i386-softmmu.mak   |   1 +
 default-configs/x86_64-softmmu.mak |   1 +
 hw/ipmi/Makefile.objs              |   1 +
 hw/ipmi/smbus_ipmi.c               | 230 +++++++++++++++++++++++++++++++++++++
 4 files changed, 233 insertions(+)
 create mode 100644 hw/ipmi/smbus_ipmi.c

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 0b51360..803c2aa 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -14,6 +14,7 @@ CONFIG_IPMI_LOCAL=y
 CONFIG_IPMI_EXTERN=y
 CONFIG_ISA_IPMI_KCS=y
 CONFIG_ISA_IPMI_BT=y
+CONFIG_IPMI_SSIF=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 7f89503..621c83b 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -14,6 +14,7 @@ CONFIG_IPMI_LOCAL=y
 CONFIG_IPMI_EXTERN=y
 CONFIG_ISA_IPMI_KCS=y
 CONFIG_ISA_IPMI_BT=y
+CONFIG_IPMI_SSIF=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_I8254=y
diff --git a/hw/ipmi/Makefile.objs b/hw/ipmi/Makefile.objs
index 1b422bb..bb37016 100644
--- a/hw/ipmi/Makefile.objs
+++ b/hw/ipmi/Makefile.objs
@@ -3,3 +3,4 @@ common-obj-$(CONFIG_IPMI_LOCAL) += ipmi_bmc_sim.o
 common-obj-$(CONFIG_IPMI_EXTERN) += ipmi_bmc_extern.o
 common-obj-$(CONFIG_ISA_IPMI_KCS) += isa_ipmi_kcs.o
 common-obj-$(CONFIG_ISA_IPMI_BT) += isa_ipmi_bt.o
+common-obj-$(CONFIG_IPMI_SSIF) += smbus_ipmi.o
diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c
new file mode 100644
index 0000000..4d99b48
--- /dev/null
+++ b/hw/ipmi/smbus_ipmi.c
@@ -0,0 +1,230 @@
+/*
+ * QEMU IPMI SMBus (SSIF) emulation
+ *
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/i2c/smbus.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/ipmi/ipmi.h"
+
+#define TYPE_SMBUS_IPMI "smbus-ipmi"
+#define SMBUS_IPMI(obj) OBJECT_CHECK(SMBusIPMIDevice, (obj), TYPE_SMBUS_IPMI)
+
+#define SSIF_IPMI_REQUEST                       2
+#define SSIF_IPMI_MULTI_PART_REQUEST_START      6
+#define SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE     7
+#define SSIF_IPMI_RESPONSE                      3
+#define SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE    9
+
+typedef struct SMBusIPMIDevice {
+    SMBusDevice parent;
+
+    IPMIBmc *bmc;
+
+    uint8_t outmsg[MAX_IPMI_MSG_SIZE];
+    uint32_t outpos;
+    uint32_t outlen;
+
+    uint8_t inmsg[MAX_IPMI_MSG_SIZE];
+    uint32_t inlen;
+
+    /*
+     * This is a response number that we send with the command to make
+     * sure that the response matches the command.
+     */
+    uint8_t waiting_rsp;
+
+    uint32_t uuid;
+} SMBusIPMIDevice;
+
+static void smbus_ipmi_handle_event(IPMIInterface *ii)
+{
+    /* No interrupts, so nothing to do here. */
+}
+
+static void smbus_ipmi_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
+                                  unsigned char *rsp, unsigned int rsp_len)
+{
+    SMBusIPMIDevice *sid = SMBUS_IPMI(ii);
+
+    if (sid->waiting_rsp == msg_id) {
+        sid->waiting_rsp++;
+
+        memcpy(sid->outmsg, rsp, rsp_len);
+        sid->outlen = rsp_len;
+        sid->outpos = 0;
+    }
+}
+
+static void smbus_ipmi_set_atn(IPMIInterface *ii, int val, int irq)
+{
+    /* This is where PEC would go. */
+}
+
+static void smbus_ipmi_set_irq_enable(IPMIInterface *ii, int val)
+{
+}
+
+static void ipmi_quick_cmd(SMBusDevice *dev, uint8_t read)
+{
+}
+
+static void ipmi_send_byte(SMBusDevice *dev, uint8_t val)
+{
+}
+
+static uint8_t ipmi_receive_byte(SMBusDevice *dev)
+{
+    SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
+
+    if (sid->outpos >= sid->outlen) {
+        return 0;
+    }
+
+    return sid->outmsg[sid->outpos++];
+}
+
+static void ipmi_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf,
+                            int len)
+{
+    SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
+    IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(sid->bmc);
+
+    if (cmd != SSIF_IPMI_REQUEST) {
+        return;
+    }
+
+    if (len < 3 || len > MAX_IPMI_MSG_SIZE || buf[0] != len - 1) {
+        return;
+    }
+
+    memcpy(sid->inmsg, buf + 1, len - 1);
+    sid->inlen = len;
+
+    sid->outlen = 0;
+    sid->outpos = 0;
+    bk->handle_command(sid->bmc, sid->inmsg, sid->inlen, sizeof(sid->inmsg),
+                       sid->waiting_rsp);
+}
+
+static uint8_t ipmi_read_data(SMBusDevice *dev, uint8_t cmd, int n)
+{
+    SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
+
+    if (cmd != SSIF_IPMI_RESPONSE) {
+        return 0;
+    }
+
+    if (n == 0) {
+        return sid->outlen;
+    }
+
+    return ipmi_receive_byte(dev);
+}
+
+static const VMStateDescription vmstate_smbus_ipmi = {
+    .name = TYPE_SMBUS_IPMI,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(waiting_rsp, SMBusIPMIDevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void smbus_ipmi_realize(DeviceState *dev, Error **errp)
+{
+    SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
+    IPMIInterface *ii = IPMI_INTERFACE(dev);
+
+    if (!sid->bmc) {
+        error_setg(errp, "IPMI device requires a bmc attribute to be set");
+        return;
+    }
+
+    sid->uuid = ipmi_next_uuid();
+
+    sid->bmc->intf = ii;
+}
+
+static void smbus_ipmi_init(Object *obj)
+{
+    SMBusIPMIDevice *sid = SMBUS_IPMI(obj);
+
+    ipmi_bmc_find_and_link(OBJECT(obj), (Object **) &sid->bmc);
+}
+
+static void smbus_ipmi_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
+{
+    SMBusIPMIDevice *sid = SMBUS_IPMI(ii);
+
+    info->interface_name = "smbus";
+    info->interface_type = IPMI_SMBIOS_SSIF;
+    info->ipmi_spec_major_revision = 2;
+    info->ipmi_spec_minor_revision = 0;
+    info->i2c_slave_address = sid->bmc->slave_addr;
+    info->base_address = sid->parent.i2c.address;
+    info->memspace = IPMI_MEMSPACE_SMBUS;
+    info->register_spacing = 1;
+    info->uuid = sid->uuid;
+}
+
+static void smbus_ipmi_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(oc);
+
+    sc->quick_cmd = ipmi_quick_cmd;
+    sc->send_byte = ipmi_send_byte;
+    sc->receive_byte = ipmi_receive_byte;
+    sc->write_data = ipmi_write_data;
+    sc->read_data = ipmi_read_data;
+    dc->vmsd = &vmstate_smbus_ipmi;
+    dc->realize = smbus_ipmi_realize;
+    iic->set_atn = smbus_ipmi_set_atn;
+    iic->handle_rsp = smbus_ipmi_handle_rsp;
+    iic->handle_if_event = smbus_ipmi_handle_event;
+    iic->set_irq_enable = smbus_ipmi_set_irq_enable;
+    iic->get_fwinfo = smbus_ipmi_get_fwinfo;
+}
+
+static const TypeInfo smbus_ipmi_info = {
+    .name          = TYPE_SMBUS_IPMI,
+    .parent        = TYPE_SMBUS_DEVICE,
+    .instance_size = sizeof(SMBusIPMIDevice),
+    .instance_init = smbus_ipmi_init,
+    .class_init    = smbus_ipmi_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_IPMI_INTERFACE },
+        { }
+    }
+};
+
+static void smbus_ipmi_register_types(void)
+{
+    type_register_static(&smbus_ipmi_info);
+}
+
+type_init(smbus_ipmi_register_types)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 11/19] acpi: Add i2c serial bus CRS handling
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (9 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 10/19] ipmi: Add an SMBus IPMI interface minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 12/19] ipmi: Fix SSIF ACPI handling to use the right CRS minyard
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/acpi/aml-build.c         | 40 ++++++++++++++++++++++++++++++++++++++++
 include/hw/acpi/aml-build.h | 18 ++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index b2a1e40..7b2673f 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1607,3 +1607,43 @@ void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
     numamem->base_addr = cpu_to_le64(base);
     numamem->range_length = cpu_to_le64(len);
 }
+
+/* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */
+static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags,
+                                  uint16_t type_flags,
+                                  uint8_t revid, uint16_t data_length,
+                                  uint16_t resource_source_len)
+{
+    Aml *var = aml_alloc();
+    uint16_t length = data_length + resource_source_len + 9;
+
+    build_append_byte(var->buf, 0x8e); /* Serial Bus Connection Descriptor */
+    build_append_int_noprefix(var->buf, length, sizeof(length));
+    build_append_byte(var->buf, 1);    /* Revision ID */
+    build_append_byte(var->buf, 0);    /* Resource Source Index */
+    build_append_byte(var->buf, serial_bus_type); /* Serial Bus Type */
+    build_append_byte(var->buf, flags); /* General Flags */
+    build_append_int_noprefix(var->buf, type_flags, /* Type Specific Flags */
+                              sizeof(type_flags));
+    build_append_byte(var->buf, revid); /* Type Specification Revision ID */
+    build_append_int_noprefix(var->buf, data_length, sizeof(data_length));
+
+    return var;
+}
+
+/* ACPI 5.0: 6.4.3.8.2.1 I2C Serial Bus Connection Resource Descriptor */
+Aml *aml_i2c_serial_bus_device(uint16_t address, const char *resource_source)
+{
+    uint16_t resource_source_len = strlen(resource_source) + 1;
+    Aml *var = aml_serial_bus_device(AML_SERIAL_BUS_TYPE_I2C, 0, 0, 1,
+                                     6, resource_source_len);
+
+    /* Connection Speed.  Just set to 100K for now, it doesn't really matter. */
+    build_append_int_noprefix(var->buf, 100000, 4);
+    build_append_int_noprefix(var->buf, address, sizeof(address));
+
+    /* This is a string, not a name, so just copy it directly in. */
+    g_array_append_vals(var->buf, resource_source, resource_source_len);
+
+    return var;
+}
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 559326c..27e23b1 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -213,6 +213,23 @@ struct AcpiBuildTables {
     BIOSLinker *linker;
 } AcpiBuildTables;
 
+/*
+ * ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors
+ * Serial Bus Type
+ */
+#define AML_SERIAL_BUS_TYPE_I2C  1
+#define AML_SERIAL_BUS_TYPE_SPI  2
+#define AML_SERIAL_BUS_TYPE_UART 3
+
+/*
+ * ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors
+ * General Flags
+ */
+/* Slave Mode */
+#define AML_SERIAL_BUS_FLAG_MASTER_DEVICE       (1 << 0)
+/* Consumer/Producer */
+#define AML_SERIAL_BUS_FLAG_CONSUME_ONLY        (1 << 1)
+
 /**
  * init_aml_allocator:
  *
@@ -337,6 +354,7 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
 Aml *aml_dma(AmlDmaType typ, AmlDmaBusMaster bm, AmlTransferSize sz,
              uint8_t channel);
 Aml *aml_sleep(uint64_t msec);
+Aml *aml_i2c_serial_bus_device(uint16_t address, const char *resource_source);
 
 /* Block AML object primitives */
 Aml *aml_scope(const char *name_format, ...) GCC_FMT_ATTR(1, 2);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 12/19] ipmi: Fix SSIF ACPI handling to use the right CRS
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (10 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 11/19] acpi: Add i2c serial bus CRS handling minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 13/19] pc: Add _enabled to the end of some boolean flags minyard
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/acpi/ipmi.c         | 13 +++++++------
 hw/i386/acpi-build.c   |  2 +-
 include/hw/acpi/ipmi.h |  2 +-
 stubs/ipmi.c           |  2 +-
 4 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/hw/acpi/ipmi.c b/hw/acpi/ipmi.c
index 651e2e9..96e48eb 100644
--- a/hw/acpi/ipmi.c
+++ b/hw/acpi/ipmi.c
@@ -13,7 +13,7 @@
 #include "hw/acpi/acpi.h"
 #include "hw/acpi/ipmi.h"
 
-static Aml *aml_ipmi_crs(IPMIFwInfo *info)
+static Aml *aml_ipmi_crs(IPMIFwInfo *info, const char *resource)
 {
     Aml *crs = aml_resource_template();
 
@@ -48,7 +48,8 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info)
                             info->register_spacing, info->register_length));
         break;
     case IPMI_MEMSPACE_SMBUS:
-        aml_append(crs, aml_return(aml_int(info->base_address)));
+        aml_append(crs, aml_i2c_serial_bus_device(info->base_address,
+                                                  resource));
         break;
     default:
         abort();
@@ -61,7 +62,7 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info)
     return crs;
 }
 
-static Aml *aml_ipmi_device(IPMIFwInfo *info)
+static Aml *aml_ipmi_device(IPMIFwInfo *info, const char *resource)
 {
     Aml *dev;
     uint16_t version = ((info->ipmi_spec_major_revision << 8)
@@ -74,14 +75,14 @@ static Aml *aml_ipmi_device(IPMIFwInfo *info)
     aml_append(dev, aml_name_decl("_STR", aml_string("ipmi_%s",
                                                      info->interface_name)));
     aml_append(dev, aml_name_decl("_UID", aml_int(info->uuid)));
-    aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info)));
+    aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info, resource)));
     aml_append(dev, aml_name_decl("_IFT", aml_int(info->interface_type)));
     aml_append(dev, aml_name_decl("_SRV", aml_int(version)));
 
     return dev;
 }
 
-void build_acpi_ipmi_devices(Aml *scope, BusState *bus)
+void build_acpi_ipmi_devices(Aml *scope, BusState *bus, const char *resource)
 {
 
     BusChild *kid;
@@ -101,6 +102,6 @@ void build_acpi_ipmi_devices(Aml *scope, BusState *bus)
         iic = IPMI_INTERFACE_GET_CLASS(obj);
         memset(&info, 0, sizeof(info));
         iic->get_fwinfo(ii, &info);
-        aml_append(scope, aml_ipmi_device(&info));
+        aml_append(scope, aml_ipmi_device(&info, resource));
     }
 }
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 42ecf61..b8a16cf 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1455,7 +1455,7 @@ static void build_isa_devices_aml(Aml *table)
     } else if (!obj) {
         error_report("No ISA bus, unable to define IPMI ACPI data");
     } else {
-        build_acpi_ipmi_devices(scope, BUS(obj));
+        build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
     }
 
     aml_append(table, scope);
diff --git a/include/hw/acpi/ipmi.h b/include/hw/acpi/ipmi.h
index ab2bb29..d68bc85 100644
--- a/include/hw/acpi/ipmi.h
+++ b/include/hw/acpi/ipmi.h
@@ -17,6 +17,6 @@
  * bus matches the given bus.  The resource is the ACPI resource that
  * contains the IPMI device, this is required for the I2C CRS.
  */
-void build_acpi_ipmi_devices(Aml *table, BusState *bus);
+void build_acpi_ipmi_devices(Aml *table, BusState *bus, const char *resource);
 
 #endif /* HW_ACPI_IPMI_H */
diff --git a/stubs/ipmi.c b/stubs/ipmi.c
index 98b6dce..6c71d6c 100644
--- a/stubs/ipmi.c
+++ b/stubs/ipmi.c
@@ -9,6 +9,6 @@
 
 #include "hw/acpi/ipmi.h"
 
-void build_acpi_ipmi_devices(Aml *table, BusState *bus)
+void build_acpi_ipmi_devices(Aml *table, BusState *bus, const char *resource)
 {
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 13/19] pc: Add _enabled to the end of some boolean flags
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (11 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 12/19] ipmi: Fix SSIF ACPI handling to use the right CRS minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 14/19] pc: Add an SMB0 ACPI device to q35 minyard
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

This makes the function of the variable more clear and avoids
some conflicts in later patches.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i386/pc.c         | 37 +++++++++++++++++++------------------
 hw/i386/pc_piix.c    |  3 ++-
 hw/i386/pc_q35.c     |  6 +++---
 include/hw/i386/pc.h |  6 +++---
 4 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 25e8586..56a535d 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -2160,46 +2160,46 @@ static void pc_machine_set_nvdimm(Object *obj, bool value, Error **errp)
     pcms->acpi_nvdimm_state.is_enabled = value;
 }
 
-static bool pc_machine_get_smbus(Object *obj, Error **errp)
+static bool pc_machine_get_smbus_enabled(Object *obj, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(obj);
 
-    return pcms->smbus;
+    return pcms->smbus_enabled;
 }
 
-static void pc_machine_set_smbus(Object *obj, bool value, Error **errp)
+static void pc_machine_set_smbus_enabled(Object *obj, bool value, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(obj);
 
-    pcms->smbus = value;
+    pcms->smbus_enabled = value;
 }
 
-static bool pc_machine_get_sata(Object *obj, Error **errp)
+static bool pc_machine_get_sata_enabled(Object *obj, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(obj);
 
-    return pcms->sata;
+    return pcms->sata_enabled;
 }
 
-static void pc_machine_set_sata(Object *obj, bool value, Error **errp)
+static void pc_machine_set_sata_enabled(Object *obj, bool value, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(obj);
 
-    pcms->sata = value;
+    pcms->sata_enabled = value;
 }
 
-static bool pc_machine_get_pit(Object *obj, Error **errp)
+static bool pc_machine_get_pit_enabled(Object *obj, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(obj);
 
-    return pcms->pit;
+    return pcms->pit_enabled;
 }
 
-static void pc_machine_set_pit(Object *obj, bool value, Error **errp)
+static void pc_machine_set_pit_enabled(Object *obj, bool value, Error **errp)
 {
     PCMachineState *pcms = PC_MACHINE(obj);
 
-    pcms->pit = value;
+    pcms->pit_enabled = value;
 }
 
 static void pc_machine_initfn(Object *obj)
@@ -2213,9 +2213,9 @@ static void pc_machine_initfn(Object *obj)
     pcms->acpi_nvdimm_state.is_enabled = false;
     /* acpi build is enabled by default if machine supports it */
     pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build;
-    pcms->smbus = true;
-    pcms->sata = true;
-    pcms->pit = true;
+    pcms->smbus_enabled = true;
+    pcms->sata_enabled = true;
+    pcms->pit_enabled = true;
 }
 
 static void pc_machine_reset(void)
@@ -2378,13 +2378,14 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
         pc_machine_get_nvdimm, pc_machine_set_nvdimm, &error_abort);
 
     object_class_property_add_bool(oc, PC_MACHINE_SMBUS,
-        pc_machine_get_smbus, pc_machine_set_smbus, &error_abort);
+        pc_machine_get_smbus_enabled, pc_machine_set_smbus_enabled,
+        &error_abort);
 
     object_class_property_add_bool(oc, PC_MACHINE_SATA,
-        pc_machine_get_sata, pc_machine_set_sata, &error_abort);
+        pc_machine_get_sata_enabled, pc_machine_set_sata_enabled, &error_abort);
 
     object_class_property_add_bool(oc, PC_MACHINE_PIT,
-        pc_machine_get_pit, pc_machine_set_pit, &error_abort);
+        pc_machine_get_pit_enabled, pc_machine_set_pit_enabled, &error_abort);
 }
 
 static const TypeInfo pc_machine_info = {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 5e1adbe..3bfe464 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -235,7 +235,8 @@ static void pc_init1(MachineState *machine,
 
     /* init basic PC hardware */
     pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true,
-                         (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4);
+                         (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled,
+                         0x4);
 
     pc_nic_init(isa_bus, pci_bus);
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index d042fe0..5f67c45 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -227,13 +227,13 @@ static void pc_q35_init(MachineState *machine)
 
     /* init basic PC hardware */
     pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy,
-                         (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit,
+                         (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled,
                          0xff0104);
 
     /* connect pm stuff to lpc */
     ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
 
-    if (pcms->sata) {
+    if (pcms->sata_enabled) {
         /* ahci and SATA device, for q35 1 ahci controller is built-in */
         ahci = pci_create_simple_multifunction(host_bus,
                                                PCI_DEVFN(ICH9_SATA1_DEV,
@@ -253,7 +253,7 @@ static void pc_q35_init(MachineState *machine)
         ehci_create_ich9_with_companions(host_bus, 0x1d);
     }
 
-    if (pcms->smbus) {
+    if (pcms->smbus_enabled) {
         /* TODO: Populate SPD eeprom data.  */
         smbus_eeprom_init(ich9_smb_init(host_bus,
                                         PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index b22e699..f165f69 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -63,9 +63,9 @@ struct PCMachineState {
     AcpiNVDIMMState acpi_nvdimm_state;
 
     bool acpi_build_enabled;
-    bool smbus;
-    bool sata;
-    bool pit;
+    bool smbus_enabled;
+    bool sata_enabled;
+    bool pit_enabled;
 
     /* RAM information (sizes, addresses, configuration): */
     ram_addr_t below_4g_mem_size, above_4g_mem_size;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 14/19] pc: Add an SMB0 ACPI device to q35
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (12 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 13/19] pc: Add _enabled to the end of some boolean flags minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 15/19] hw: Add an IRQ interface minyard
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

This is so I2C devices can be found in the ACPI namespace.  Currently
that's only IPMI, but devices can be easily added now.

Adding the devices required some PCI information, and the bus itself
to be added to the PCMachineState structure.

Note that this only works on Q35, the ACPI for PIIX4 is not capable
of handling an SMBus device.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i386/acpi-build.c                 |  15 +++++++++++++++
 hw/i386/pc_piix.c                    |  12 ++++++------
 hw/i386/pc_q35.c                     |   9 +++++----
 include/hw/i386/pc.h                 |   2 ++
 tests/acpi-test-data/q35/DSDT        | Bin 8770 -> 8808 bytes
 tests/acpi-test-data/q35/DSDT.bridge | Bin 8787 -> 8825 bytes
 tests/acpi-test-data/q35/DSDT.cphp   | Bin 9233 -> 9271 bytes
 tests/acpi-test-data/q35/DSDT.ipmibt | Bin 8845 -> 8883 bytes
 8 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b8a16cf..d7fbef4 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1975,6 +1975,18 @@ static Aml *build_q35_osc_method(void)
     return method;
 }
 
+static void build_smb0(Aml *table, I2CBus *smbus, int devnr, int func)
+{
+    Aml *scope = aml_scope("_SB.PCI0");
+    Aml *dev = aml_device("SMB0");
+
+    aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0005")));
+    aml_append(dev, aml_name_decl("_ADR", aml_int(devnr << 16 | func)));
+    build_acpi_ipmi_devices(dev, BUS(smbus), "\\_SB.PCI0.SMB0");
+    aml_append(scope, dev);
+    aml_append(table, scope);
+}
+
 static void
 build_dsdt(GArray *table_data, BIOSLinker *linker,
            AcpiPmInfo *pm, AcpiMiscInfo *misc,
@@ -2038,6 +2050,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
         build_q35_isa_bridge(dsdt);
         build_isa_devices_aml(dsdt);
         build_q35_pci0_int(dsdt);
+        if (pcms->smbus && !pcmc->do_not_add_smb_acpi) {
+            build_smb0(dsdt, pcms->smbus, ICH9_SMB_DEV, ICH9_SMB_FUNC);
+        }
     }
 
     if (pcmc->legacy_cpu_hotplug) {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 3bfe464..4dfb5d5 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -274,15 +274,14 @@ static void pc_init1(MachineState *machine,
 
     if (pcmc->pci_enabled && acpi_enabled) {
         DeviceState *piix4_pm;
-        I2CBus *smbus;
 
         smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
         /* TODO: Populate SPD eeprom data.  */
-        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
-                              pcms->gsi[9], smi_irq,
-                              pc_machine_is_smm_enabled(pcms),
-                              &piix4_pm);
-        smbus_eeprom_init(smbus, 8, NULL, 0);
+        pcms->smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+                                    pcms->gsi[9], smi_irq,
+                                    pc_machine_is_smm_enabled(pcms),
+                                    &piix4_pm);
+        smbus_eeprom_init(pcms->smbus, 8, NULL, 0);
 
         object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
                                  TYPE_HOTPLUG_HANDLER,
@@ -466,6 +465,7 @@ static void pc_i440fx_2_6_machine_options(MachineClass *m)
     PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     pc_i440fx_2_7_machine_options(m);
     pcmc->legacy_cpu_hotplug = true;
+    pcmc->do_not_add_smb_acpi = true;
     SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
 }
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 5f67c45..7976480 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -255,10 +255,10 @@ static void pc_q35_init(MachineState *machine)
 
     if (pcms->smbus_enabled) {
         /* TODO: Populate SPD eeprom data.  */
-        smbus_eeprom_init(ich9_smb_init(host_bus,
-                                        PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
-                                        0xb100),
-                          8, NULL, 0);
+        pcms->smbus = ich9_smb_init(host_bus,
+                                    PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
+                                    0xb100);
+        smbus_eeprom_init(pcms->smbus, 8, NULL, 0);
     }
 
     pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
@@ -326,6 +326,7 @@ static void pc_q35_2_6_machine_options(MachineClass *m)
     PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
     pc_q35_2_7_machine_options(m);
     pcmc->legacy_cpu_hotplug = true;
+    pcmc->do_not_add_smb_acpi = true;
     SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
 }
 
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index f165f69..90ba3d8 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -52,6 +52,7 @@ struct PCMachineState {
     HotplugHandler *acpi_dev;
     ISADevice *rtc;
     PCIBus *bus;
+    I2CBus *smbus;
     FWCfgState *fw_cfg;
     qemu_irq *gsi;
 
@@ -136,6 +137,7 @@ struct PCMachineClass {
     bool rsdp_in_ram;
     int legacy_acpi_table_size;
     unsigned acpi_data_size;
+    bool do_not_add_smb_acpi;
 
     /* SMBIOS compat: */
     bool smbios_defaults;
diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT
index 58fbb3d2e2dc8e8256984744bfb9411feb2e35fe..113fb3a860c9465edb4cae69318fe8c063ce3077 100644
GIT binary patch
delta 62
zcmX@)^1_A7CD<h-Ly3Wbv2G(*qok^;UVN}qe1Nm3L3ER3u&<K=N4$rp3lEzB11m?o
Rqe~DEGlM+C<}S${8~_;u4~_r;

delta 24
fcmaFia>#|tCD<jzNr{1h(RL$OqvYm|lG`}|Vsi(d

diff --git a/tests/acpi-test-data/q35/DSDT.bridge b/tests/acpi-test-data/q35/DSDT.bridge
index c392802a95cb5690c6719b7909c9f8fa2213e503..2f31562df229dbec6a17e5eafbc549d7fb6f179e 100644
GIT binary patch
delta 62
zcmccY^3#ROCD<jTQi*|qQEnqwqok^;UVN}qe1Nm3L3ER3u&<K=N4$rp3lEzB11m?o
Rqe~DEGlM+C<}S&T8~_r;4{`ti

delta 24
gcmezAa@mE;CD<h-Sc!pw@$N>hM#;?^B~New0Bqt2g8%>k

diff --git a/tests/acpi-test-data/q35/DSDT.cphp b/tests/acpi-test-data/q35/DSDT.cphp
index a0ce6b3264c69999c6e82a8ae7bab49338e4819b..f309211c279b562a5649458ccf0c078c4660d247 100644
GIT binary patch
delta 62
zcmbQ}vE75qCD<jzT!n#w@%u)uMoCpwz4&0K_yA{5gXkv7U|%N#j(87G7aleN23C%E
RN0%TTW(IkN&0Ui1TmTRp4^IF9

delta 24
fcmdn)G0}s|CD<iIP=$ekaoa|&M#;?^CEK_FTkHp5

diff --git a/tests/acpi-test-data/q35/DSDT.ipmibt b/tests/acpi-test-data/q35/DSDT.ipmibt
index 0ea38e1e72977e82053b087a6bd2e4ea21373420..7777de5996292205e1a365298db7f31291a24cfa 100644
GIT binary patch
delta 62
zcmeBm-R#Qc66_MPS&4yxaq&j3Gm@&Rdhx+d@d3`B2GLED!M;ug9Pu8WE<9`k46GdS
SjxIqw%nb4jo3Bdl-~a$63lJ;-

delta 24
fcmdn&+Uv^Y66_MvtHi*-n6#1WjO6A&lG`}|Vkrnc

-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 15/19] hw: Add an IRQ interface
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (13 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 14/19] pc: Add an SMB0 ACPI device to q35 minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 16/19] isa: Add an irq device minyard
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

This allows IRQs to be created that can be found by other devices
so they can be used without having a direct tie to the irq.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/core/Makefile.objs |  1 +
 hw/core/irqif.c       | 39 +++++++++++++++++++++++++++++++++++++++
 include/hw/irqif.h    | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+)
 create mode 100644 hw/core/irqif.c
 create mode 100644 include/hw/irqif.h

diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index a4c94e5..764af1c 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -6,6 +6,7 @@ common-obj-y += fw-path-provider.o
 common-obj-y += irq.o
 common-obj-y += hotplug.o
 obj-y += nmi.o
+common-obj-y += irqif.o
 
 common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
 common-obj-$(CONFIG_XILINX_AXI) += stream.o
diff --git a/hw/core/irqif.c b/hw/core/irqif.c
new file mode 100644
index 0000000..12449af
--- /dev/null
+++ b/hw/core/irqif.c
@@ -0,0 +1,39 @@
+/*
+ * Interrupt Interface class
+ *
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/irqif.h"
+
+static TypeInfo irq_interface_type_info = {
+    .name = TYPE_IRQ_INTERFACE,
+    .parent = TYPE_INTERFACE,
+    .class_size = sizeof(IRQInterfaceClass),
+};
+
+static void ipmi_register_types(void)
+{
+    type_register_static(&irq_interface_type_info);
+}
+
+type_init(ipmi_register_types)
diff --git a/include/hw/irqif.h b/include/hw/irqif.h
new file mode 100644
index 0000000..d733363
--- /dev/null
+++ b/include/hw/irqif.h
@@ -0,0 +1,49 @@
+/*
+ * Interrupt Interface class
+ *
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
+ *
+ * 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.
+ */
+
+#ifndef HW_IRQIF_H
+#define HW_IRQIF_H
+
+#include "hw/hw.h"
+#include "hw/irq.h"
+
+#define TYPE_IRQ_INTERFACE "irq-interface"
+#define IRQ_INTERFACE(obj) \
+     INTERFACE_CHECK(IRQInterface, (obj), TYPE_IRQ_INTERFACE)
+#define IRQ_INTERFACE_CLASS(class) \
+     OBJECT_CLASS_CHECK(IRQInterfaceClass, (class), TYPE_IRQ_INTERFACE)
+#define IRQ_INTERFACE_GET_CLASS(class) \
+     OBJECT_GET_CLASS(IRQInterfaceClass, (class), TYPE_IRQ_INTERFACE)
+
+typedef struct IRQInterface {
+    Object parent;
+} IRQInterface;
+
+typedef struct IRQInterfaceClass {
+    InterfaceClass parent;
+
+    qemu_irq *(*get_irq)(struct IRQInterface *ii);
+} IRQInterfaceClass;
+
+#endif /* HW_IRQIF_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 16/19] isa: Add an irq device.
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (14 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 15/19] hw: Add an IRQ interface minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 17/19] i2c: Allow SMBus device to NAK start events minyard
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

This uses the new irq interface to allow an ISA irq to be specified
by name.  This will let other things (like the upcoming smbus alert
device) to specify ISA irqs by name.

To create an name ISA irq, add:
  -device isa-irq,irq=<name>,irq=<n>
where you will use the name to look up the irq on a following device.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/isa/Makefile.objs |  2 +-
 hw/isa/isa-irq.c     | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+), 1 deletion(-)
 create mode 100644 hw/isa/isa-irq.c

diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs
index 9164556..338dd08 100644
--- a/hw/isa/Makefile.objs
+++ b/hw/isa/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-y += isa-bus.o
+common-obj-y += isa-bus.o isa-irq.o
 common-obj-$(CONFIG_APM) += apm.o
 common-obj-$(CONFIG_I82378) += i82378.o
 common-obj-$(CONFIG_PC87312) += pc87312.o
diff --git a/hw/isa/isa-irq.c b/hw/isa/isa-irq.c
new file mode 100644
index 0000000..eee6c0e
--- /dev/null
+++ b/hw/isa/isa-irq.c
@@ -0,0 +1,84 @@
+/*
+ * QEMU ISA named IRQ
+ *
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/irqif.h"
+#include "hw/isa/isa.h"
+
+/* This is the type the user specifies on the -device command line */
+#define TYPE_ISA_IRQ           "isa-irq"
+#define ISA_IRQ(obj) OBJECT_CHECK(ISAIRQDevice, (obj), TYPE_ISA_IRQ)
+
+typedef struct ISAIRQDevice {
+    ISADevice dev;
+    int32_t isairq;
+    qemu_irq irq;
+} ISAIRQDevice;
+
+static qemu_irq *irq_isa_get_irq(IRQInterface *ii)
+{
+    ISAIRQDevice *iid = ISA_IRQ(ii);
+
+    return &iid->irq;
+}
+
+static void irq_isa_realizefn(DeviceState *dev, Error **errp)
+{
+    ISADevice *isadev = ISA_DEVICE(dev);
+    ISAIRQDevice *iid = ISA_IRQ(dev);
+
+    isa_init_irq(isadev, &iid->irq, iid->isairq);
+}
+
+static Property irq_isa_properties[] = {
+    DEFINE_PROP_INT32("irq",   ISAIRQDevice, isairq,  5),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void irq_isa_class_initfn(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    IRQInterfaceClass *ii = IRQ_INTERFACE_CLASS(oc);
+
+    dc->realize = irq_isa_realizefn;
+    dc->props = irq_isa_properties;
+    ii->get_irq = irq_isa_get_irq;
+}
+
+static const TypeInfo irq_isa_info = {
+    .name          = TYPE_ISA_IRQ,
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAIRQDevice),
+    .class_init    = irq_isa_class_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_IRQ_INTERFACE },
+        { }
+    }
+};
+
+static void irq_register_types(void)
+{
+    type_register_static(&irq_isa_info);
+}
+
+type_init(irq_register_types)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 17/19] i2c: Allow SMBus device to NAK start events
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (15 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 16/19] isa: Add an irq device minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 18/19] i2c: Add an SMBus alert device minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 19/19] ipmi_smbus: Add alert capability to the IPMI SSIF code minyard
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

The I2C code has been modified to allow devices to NAK start
events, the SMBus code should, too.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/smbus.c         | 11 +++++++++++
 include/hw/i2c/smbus.h |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index 4cb651e..87a1669 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -71,6 +71,17 @@ static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
 {
     SMBusDevice *dev = SMBUS_DEVICE(s);
 
+    if (event == I2C_START_SEND || event == I2C_START_RECV) {
+        /* Allow the device to NAK the start event. */
+        SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
+
+        if (sc->event) {
+            int rv = sc->event(dev, event);
+            if (rv)
+                return rv;
+        }
+    }
+
     switch (event) {
     case I2C_START_SEND:
         switch (dev->mode) {
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index f1b8078..fc995eb 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -39,6 +39,8 @@ typedef struct SMBusDeviceClass
 {
     I2CSlaveClass parent_class;
     int (*init)(SMBusDevice *dev);
+    /* Allow the device to get start and stop events so they can NAK them. */
+    int (*event)(SMBusDevice *dev, enum i2c_event event);
     void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
     void (*send_byte)(SMBusDevice *dev, uint8_t val);
     uint8_t (*receive_byte)(SMBusDevice *dev);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 18/19] i2c: Add an SMBus alert device.
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (16 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 17/19] i2c: Allow SMBus device to NAK start events minyard
@ 2016-12-30 15:21 ` minyard
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 19/19] ipmi_smbus: Add alert capability to the IPMI SSIF code minyard
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

This adds a device that conforms to the SMBus alert extension.  This
allows other I2C devices to register with this device so that when
they have data ready, it will interrupt the processor and allow the
processor to read from the alert device to see which i2c device has
data.

To use this, you must first create a named irq and then create
this device with:
  -device smbus-alert,name=<name>,irqname=<irqname>,address=..,bus=..
where the name is the value that other I2C devices will use to attach
to this device and the irqname is the name of the named irq that will
be raised when the data is ready.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/i2c/Makefile.objs         |   2 +-
 hw/i2c/smbus_alert.c         | 130 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/i2c/smbus.h       |   1 +
 include/hw/i2c/smbus_alert.h |  65 ++++++++++++++++++++++
 4 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 hw/i2c/smbus_alert.c
 create mode 100644 include/hw/i2c/smbus_alert.h

diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index a081b8e..7ad3d04 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-y += core.o smbus.o smbus_eeprom.o
+common-obj-y += core.o smbus.o smbus_eeprom.o smbus_alert.o
 common-obj-$(CONFIG_DDC) += i2c-ddc.o
 common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
 common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
diff --git a/hw/i2c/smbus_alert.c b/hw/i2c/smbus_alert.c
new file mode 100644
index 0000000..5be83e7
--- /dev/null
+++ b/hw/i2c/smbus_alert.c
@@ -0,0 +1,130 @@
+/*
+ * QEMU SMBus alert
+ *
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/i2c/smbus_alert.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+
+static void smbus_alert(SMBusAlertDevice *sad, SMBusAlertEntry *alert)
+{
+    if (alert->enqueued) {
+        return;
+    }
+
+    alert->enqueued = true;
+    QSIMPLEQ_INSERT_TAIL(&sad->alert_queue, alert, link);
+    qemu_irq_raise(*sad->irq);
+}
+
+static uint8_t alert_receive_byte(SMBusDevice *dev)
+{
+    SMBusAlertDevice *sad = (SMBusAlertDevice *) dev;
+    SMBusAlertEntry *alert = QSIMPLEQ_FIRST(&sad->alert_queue);
+
+    if (!alert) {
+        return -1;
+    }
+
+    alert->enqueued = false;
+    QSIMPLEQ_REMOVE_HEAD(&sad->alert_queue, link);
+
+    if (QSIMPLEQ_EMPTY(&sad->alert_queue)) {
+            qemu_irq_lower(*sad->irq);
+    }
+
+    return alert->val;
+}
+
+static int smbus_alert_event(SMBusDevice *dev, enum i2c_event event)
+{
+    SMBusAlertDevice *sad = (SMBusAlertDevice *) dev;
+
+    if (event == I2C_START_RECV && QSIMPLEQ_EMPTY(&sad->alert_queue)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static void smbus_alert_realize(DeviceState *dev, Error **errp)
+{
+    SMBusAlertDevice *sad = SMBUS_ALERT_DEVICE(dev);
+    IRQInterfaceClass *iic;
+
+    if (!sad->irqdev) {
+        error_setg(errp, "SMBus alert device created without irqid");
+        return;
+    }
+
+    iic = IRQ_INTERFACE_GET_CLASS(sad->irqdev);
+
+    sad->irq = iic->get_irq(sad->irqdev);
+}
+
+static void irq_check(Object *obj, const char *name,
+                      Object *val, Error **errp)
+{
+    /* Always succeed. */
+}
+
+static void smbus_alert_init(Object *obj)
+{
+    SMBusAlertDevice *sad = SMBUS_ALERT_DEVICE(obj);
+
+    QSIMPLEQ_INIT(&sad->alert_queue);
+
+    object_property_add_link(obj, "irqid", TYPE_IRQ_INTERFACE,
+                             (Object **) &sad->irqdev, irq_check,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                             &error_abort);
+}
+
+static void smbus_alert_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(oc);
+    SMBusAlertDeviceClass *sadc = SMBUS_ALERT_DEVICE_CLASS(oc);
+
+    dc->realize = smbus_alert_realize;
+    sc->receive_byte = alert_receive_byte;
+    sc->event = smbus_alert_event;
+    sadc->alert = smbus_alert;
+}
+
+static const TypeInfo smbus_alert_info = {
+    .name          = TYPE_SMBUS_ALERT_DEVICE,
+    .parent        = TYPE_SMBUS_DEVICE,
+    .instance_size = sizeof(SMBusAlertDevice),
+    .instance_init = smbus_alert_init,
+    .class_init    = smbus_alert_class_init,
+    .class_size    = sizeof(SMBusAlertDeviceClass),
+};
+
+static void smbus_alert_register_types(void)
+{
+    type_register_static(&smbus_alert_info);
+}
+
+type_init(smbus_alert_register_types)
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index fc995eb..b6e149a 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -26,6 +26,7 @@
  */
 
 #include "hw/i2c/i2c.h"
+#include "qemu/queue.h"
 
 #define TYPE_SMBUS_DEVICE "smbus-device"
 #define SMBUS_DEVICE(obj) \
diff --git a/include/hw/i2c/smbus_alert.h b/include/hw/i2c/smbus_alert.h
new file mode 100644
index 0000000..0b01be7
--- /dev/null
+++ b/include/hw/i2c/smbus_alert.h
@@ -0,0 +1,65 @@
+/*
+ * QEMU SMBus alert
+ *
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
+ *
+ * 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 "hw/irqif.h"
+#include "qemu/queue.h"
+#include "hw/i2c/smbus.h"
+
+#ifndef HW_I2C_SMBUS_ALERT
+#define HW_I2C_SMBUS_ALERT
+
+typedef struct SMBusAlertEntry {
+    uint8_t val;
+
+    /* Internal use */
+    bool enqueued;
+    QSIMPLEQ_ENTRY(SMBusAlertEntry) link;
+} SMBusAlertEntry;
+
+typedef struct SMBusAlertDevice {
+    SMBusDevice parent;
+
+    IRQInterface *irqdev;
+    qemu_irq *irq;
+
+    QSIMPLEQ_HEAD(, SMBusAlertEntry) alert_queue;
+} SMBusAlertDevice;
+
+typedef struct SMBusAlertDeviceClass {
+    SMBusDeviceClass parent;
+
+    void (*alert)(SMBusAlertDevice *sad, SMBusAlertEntry *alert);
+} SMBusAlertDeviceClass;
+
+#define TYPE_SMBUS_ALERT_DEVICE "smbus-alert"
+#define SMBUS_ALERT_DEVICE(obj) OBJECT_CHECK(SMBusAlertDevice, (obj),    \
+                                             TYPE_SMBUS_ALERT_DEVICE)
+#define SMBUS_ALERT_DEVICE_CLASS(obj) OBJECT_CLASS_CHECK(SMBusAlertDeviceClass,\
+                                             (obj),            \
+                                             TYPE_SMBUS_ALERT_DEVICE)
+#define SMBUS_ALERT_DEVICE_GET_CLASS(obj) \
+                OBJECT_GET_CLASS(SMBusAlertDeviceClass,  (obj),            \
+                                 TYPE_SMBUS_ALERT_DEVICE)
+
+#endif /* HW_I2C_SMBUS_ALERT */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH 19/19] ipmi_smbus: Add alert capability to the IPMI SSIF code
  2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
                   ` (17 preceding siblings ...)
  2016-12-30 15:21 ` [Qemu-devel] [PATCH 18/19] i2c: Add an SMBus alert device minyard
@ 2016-12-30 15:21 ` minyard
  18 siblings, 0 replies; 20+ messages in thread
From: minyard @ 2016-12-30 15:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: minyard, Corey Minyard

From: Corey Minyard <cminyard@mvista.com>

This lets you add "alertname=<name>" to specify an alert device
to use for letting the host know that the IPMI device has data
ready.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 hw/ipmi/smbus_ipmi.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c
index 4d99b48..5c7b7c2 100644
--- a/hw/ipmi/smbus_ipmi.c
+++ b/hw/ipmi/smbus_ipmi.c
@@ -24,6 +24,7 @@
 #include "qemu/osdep.h"
 #include "hw/hw.h"
 #include "hw/i2c/smbus.h"
+#include "hw/i2c/smbus_alert.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "hw/ipmi/ipmi.h"
@@ -49,6 +50,8 @@ typedef struct SMBusIPMIDevice {
     uint8_t inmsg[MAX_IPMI_MSG_SIZE];
     uint32_t inlen;
 
+    bool irqs_enabled;
+
     /*
      * This is a response number that we send with the command to make
      * sure that the response matches the command.
@@ -56,11 +59,15 @@ typedef struct SMBusIPMIDevice {
     uint8_t waiting_rsp;
 
     uint32_t uuid;
+
+    SMBusAlertEntry alert_entry;
+    SMBusAlertDevice *alertdev;
+    SMBusAlertDeviceClass *alertdevclass;
 } SMBusIPMIDevice;
 
 static void smbus_ipmi_handle_event(IPMIInterface *ii)
 {
-    /* No interrupts, so nothing to do here. */
+    /* Nothing to do here, we don't use events for SMBus. */
 }
 
 static void smbus_ipmi_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
@@ -74,16 +81,27 @@ static void smbus_ipmi_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
         memcpy(sid->outmsg, rsp, rsp_len);
         sid->outlen = rsp_len;
         sid->outpos = 0;
+
+        if (sid->alertdev && sid->irqs_enabled) {
+            sid->alertdevclass->alert(sid->alertdev, &sid->alert_entry);
+        }
     }
 }
 
 static void smbus_ipmi_set_atn(IPMIInterface *ii, int val, int irq)
 {
-    /* This is where PEC would go. */
+    SMBusIPMIDevice *sid = SMBUS_IPMI(ii);
+
+    if (sid->alertdev && sid->irqs_enabled) {
+        sid->alertdevclass->alert(sid->alertdev, &sid->alert_entry);
+    }
 }
 
 static void smbus_ipmi_set_irq_enable(IPMIInterface *ii, int val)
 {
+    SMBusIPMIDevice *sid = SMBUS_IPMI(ii);
+
+    sid->irqs_enabled = val;
 }
 
 static void ipmi_quick_cmd(SMBusDevice *dev, uint8_t read)
@@ -149,6 +167,12 @@ static const VMStateDescription vmstate_smbus_ipmi = {
     .minimum_version_id = 1,
     .fields      = (VMStateField[]) {
         VMSTATE_UINT8(waiting_rsp, SMBusIPMIDevice),
+        VMSTATE_BOOL(irqs_enabled, SMBusIPMIDevice),
+        VMSTATE_UINT32(outpos, SMBusIPMIDevice),
+        VMSTATE_VBUFFER_UINT32(outmsg, SMBusIPMIDevice, 1, NULL, 0,
+                               outlen),
+        VMSTATE_VBUFFER_UINT32(inmsg, SMBusIPMIDevice, 1, NULL, 0,
+                               inlen),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -165,14 +189,31 @@ static void smbus_ipmi_realize(DeviceState *dev, Error **errp)
 
     sid->uuid = ipmi_next_uuid();
 
+    if (sid->alertdev) {
+        sid->alertdevclass = SMBUS_ALERT_DEVICE_GET_CLASS(sid->alertdev);
+    }
+
+    sid->alert_entry.val = sid->parent.i2c.address << 1;
+
     sid->bmc->intf = ii;
 }
 
+static void alert_check(Object *obj, const char *name,
+                        Object *val, Error **errp)
+{
+    /* Always succeed. */
+}
+
 static void smbus_ipmi_init(Object *obj)
 {
     SMBusIPMIDevice *sid = SMBUS_IPMI(obj);
 
     ipmi_bmc_find_and_link(OBJECT(obj), (Object **) &sid->bmc);
+
+    object_property_add_link(obj, "alert", TYPE_SMBUS_ALERT_DEVICE,
+                             (Object **) &sid->alertdev, alert_check,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                             &error_abort);
 }
 
 static void smbus_ipmi_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2016-12-30 15:22 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-12-30 15:21 [Qemu-devel] [PATCH 01/18] Patch set to get full IPMI over SMBus minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 01/19] i2c: Allow I2C devices to NAK start events minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 02/19] i2c-smbus: Use a int for return minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 03/19] i2c:pm_smbus: Clean up some style issues minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 04/19] i2c:pm_smbus: Fix the semantics of block I2C transfers minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 05/19] i2c:pm_smbus: Make the I2C block read command read-only minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 06/19] i2c:pm_smbus: Add block transfer capability minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 07/19] i2c:pm_smbus: Fix state transfer minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 08/19] i2c:pm_smbus: Add interrupt handling minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 09/19] i2c:pm_smbus: Add the ability to force block transfer enable minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 10/19] ipmi: Add an SMBus IPMI interface minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 11/19] acpi: Add i2c serial bus CRS handling minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 12/19] ipmi: Fix SSIF ACPI handling to use the right CRS minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 13/19] pc: Add _enabled to the end of some boolean flags minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 14/19] pc: Add an SMB0 ACPI device to q35 minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 15/19] hw: Add an IRQ interface minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 16/19] isa: Add an irq device minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 17/19] i2c: Allow SMBus device to NAK start events minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 18/19] i2c: Add an SMBus alert device minyard
2016-12-30 15:21 ` [Qemu-devel] [PATCH 19/19] ipmi_smbus: Add alert capability to the IPMI SSIF code minyard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).