* [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device
@ 2016-06-01 16:26 minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 1/7] i2c: Fix the PM SMBus driver so it actually works correctly minyard
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:26 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
This set of patches requires the previous IPMI ACPI patches, at least
starting with patch 4.
This set of patches fixes some fairly significant bugs with the
pm_smbus device, which basically just wasn't functional beyond
some very basic things. It's close to a rewrite of the state
machine.
After that, it adds an IPMI device on the SMBus.
Then it cleans up a few small things in the IPMI ACPI handling
that were SMBus specific, and adds the SMBus itself to the
ACPI tables. This required adding a 2.7 machine, though I've
seen a patch for that on the mailing list it has not been
added to the main repository yet.
-corey
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v2 1/7] i2c: Fix the PM SMBus driver so it actually works correctly
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
@ 2016-06-01 16:26 ` minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 2/7] pm_smbus: Add the ability to force block transfer enable minyard
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:26 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
From: Corey Minyard <cminyard@mvista.com>
The PM SMBus driver really just didn't work. This patch fixes it
to be fairly hardware compliant with the actual hardware. Plus
it adds interrupts and working block transfers.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i2c/pm_smbus.c | 212 +++++++++++++++++++++++++++++++++++++++-------
hw/i2c/smbus.c | 25 ++++--
hw/i2c/smbus_ich9.c | 28 +++++-
include/hw/i2c/pm_smbus.h | 23 ++++-
include/hw/i2c/smbus.h | 5 +-
5 files changed, 245 insertions(+), 48 deletions(-)
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 6fc3923..17d253f 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
@@ -32,23 +30,42 @@
#define SMBHSTDAT0 0x05
#define SMBHSTDAT1 0x06
#define SMBBLKDAT 0x07
+#define SMBAUXCTL 0x0d
-#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 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 AUX_PEC (1 << 0)
+#define AUX_BLK (1 << 1)
+#define AUX_MASK 0x3
+
+/*#define DEBUG*/
#ifdef DEBUG
-# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
+# define SMBUS_DPRINTF(format, ...) fprintf(stderr, format, ## __VA_ARGS__)
#else
# define SMBUS_DPRINTF(format, ...) do { } while (0)
#endif
@@ -61,6 +78,7 @@ static void smb_transaction(PMSMBus *s)
uint8_t cmd = s->smb_cmd;
uint8_t addr = s->smb_addr >> 1;
I2CBus *bus = s->smbus;
+ bool i2c_enable = s->i2c_enable;
int ret;
SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
@@ -68,11 +86,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 +99,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,22 +108,58 @@ 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:
+ cmd = s->smb_data1;
+ if (s->smb_ctl & CTL_LAST_BYTE) {
+ s->smb_data0 = 1;
+ } else {
+ s->smb_data0 = PM_SMBUS_MAX_MSG_SIZE;
+ }
+ read = true;
+ i2c_enable = true;
+ /* Fallthrough */
+ case PROT_BLOCK_DATA:
if (read) {
- ret = smbus_read_block(bus, addr, cmd, s->smb_data);
- goto data8;
+ ret = smbus_read_block(bus, addr, cmd, s->smb_data,
+ sizeof(s->smb_data), !i2c_enable);
+ s->smb_index = 0;
+ s->op_done = false;
+ if (s->smb_auxctl & AUX_BLK) {
+ s->smb_stat |= STS_INTR;
+ } else {
+ s->smb_stat |= STS_HOST_BUSY;
+ }
+ goto datablk;
} else {
- ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
- goto done;
+ if (s->smb_auxctl & AUX_BLK || s->smb_index == s->smb_data0) {
+ 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. */
+ ret = smbus_write_block(bus, addr, cmd, s->smb_data,
+ s->smb_data0, !i2c_enable);
+ s->op_done = true;
+ s->smb_index = 0;
+ s->smb_stat |= STS_INTR;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ } else {
+ s->op_done = false;
+ s->smb_stat |= STS_HOST_BUSY;
+ ret = 0;
+ }
+ goto doneblk;
}
break;
default:
@@ -128,11 +183,27 @@ done:
}
s->smb_stat |= STS_BYTE_DONE | STS_INTR;
return;
+datablk:
+ if (ret < 0) {
+ goto error;
+ }
+ s->smb_data0 = ret;
+doneblk:
+ if (ret < 0) {
+ goto error;
+ }
+ s->smb_stat |= STS_BYTE_DONE;
+ return;
error:
s->smb_stat |= STS_DEV_ERR;
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,
@@ -140,17 +211,30 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
{
PMSMBus *s = opaque;
- SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx
- " val=0x%02" PRIx64 "\n", addr, val);
+ SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx " 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)) {
+ s->smb_stat |= STS_BYTE_DONE;
+ }
break;
case SMBHSTCNT:
s->smb_ctl = val;
- if (val & 0x40)
+ if (s->smb_ctl & 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;
@@ -165,13 +249,28 @@ 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;
+ }
+ s->smb_data[s->smb_index++] = val;
+ if (!(s->smb_auxctl & AUX_BLK) && s->smb_ctl & CTL_START &&
+ !s->op_done && s->smb_index == s->smb_data0) {
+ smb_transaction(s);
+ s->op_done = true;
+ s->smb_stat |= STS_INTR;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ }
+ break;
+ case SMBAUXCTL:
+ s->smb_auxctl = val & AUX_MASK;
break;
default:
break;
}
+
+ if (s->set_irq) {
+ s->set_irq(s, smb_irq_value(s));
+ }
}
static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
@@ -184,7 +283,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 & 0x1f;
break;
case SMBHSTCMD:
@@ -200,18 +298,47 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
val = s->smb_data1;
break;
case SMBBLKDAT:
+ if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
+ s->smb_index = 0;
+ }
val = s->smb_data[s->smb_index++];
- if (s->smb_index > 31)
+ if (s->smb_ctl & CTL_START && !s->op_done &&
+ s->smb_index == s->smb_data0) {
+ s->op_done = true;
+ s->smb_index = 0;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ }
+ if (s->smb_ctl & CTL_LAST_BYTE) {
+ s->op_done = true;
s->smb_index = 0;
+ s->smb_stat |= STS_INTR;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ }
+ break;
+ case SMBAUXCTL:
+ val = s->smb_auxctl;
break;
default:
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);
+
+ if (s->set_irq) {
+ s->set_irq(s, smb_irq_value(s));
+ }
+
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,
@@ -220,8 +347,29 @@ 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;
+ 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.c b/hw/i2c/smbus.c
index 3979b3d..c984bd7 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -293,9 +293,10 @@ 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)
{
- int len;
+ int rlen;
int i;
if (i2c_start_transfer(bus, addr, 0)) {
@@ -303,20 +304,24 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
}
i2c_send(bus, command);
i2c_start_transfer(bus, addr, 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;
@@ -327,7 +332,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/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 498f03e..a01cb92 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -42,6 +42,8 @@
typedef struct ICH9SMBState {
PCIDevice dev;
+ bool irq_enabled;
+
PMSMBus smb;
} ICH9SMBState;
@@ -50,7 +52,9 @@ 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_BOOL(irq_enabled, ICH9SMBState),
+ VMSTATE_STRUCT(smb, ICH9SMBState, 1, pmsmb_vmstate, struct PMSMBus),
VMSTATE_END_OF_LIST()
}
};
@@ -63,12 +67,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;
+ }
}
}
@@ -107,11 +115,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 926603f..bfe740a 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,10 +13,27 @@ 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_auxctl;
+ uint32_t smb_index;
+
+ /* Set by pm_smbus.c */
+ void (*reset)(struct PMSMBus *s);
+
+ /* Set by the user. */
+ bool i2c_enable;
+ void (*set_irq)(struct PMSMBus *s, bool enabled);
+ void *opaque;
+
+ /* 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);
+extern const VMStateDescription pmsmb_vmstate;
+
#endif /* !PM_SMBUS_H */
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index 544bbc1..1270691 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -73,9 +73,10 @@ 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);
+int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+ int len, bool recv_len);
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] 8+ messages in thread
* [Qemu-devel] [PATCH v2 2/7] pm_smbus: Add the ability to force block transfer enable
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 1/7] i2c: Fix the PM SMBus driver so it actually works correctly minyard
@ 2016-06-01 16:26 ` minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 3/7] ipmi: Add an SMBus IPMI interface minyard
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:26 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
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 | 111 +++++++++++++++++++++++++++++-----------------
hw/i2c/smbus_ich9.c | 2 +-
include/hw/i2c/pm_smbus.h | 3 +-
4 files changed, 74 insertions(+), 44 deletions(-)
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index b3e3bb3..d4ae836 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -467,7 +467,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 17d253f..4099c07 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -132,34 +132,44 @@ static void smb_transaction(PMSMBus *s)
if (read) {
ret = smbus_read_block(bus, addr, cmd, s->smb_data,
sizeof(s->smb_data), !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_stat |= STS_HOST_BUSY;
+ s->smb_blkdata = s->smb_data[0];
+ s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
}
- goto datablk;
+ s->smb_data0 = ret;
+ goto out;
} else {
- if (s->smb_auxctl & AUX_BLK || s->smb_index == s->smb_data0) {
+ 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, !i2c_enable);
+ if (ret < 0) {
+ goto error;
+ }
s->op_done = true;
- s->smb_index = 0;
s->smb_stat |= STS_INTR;
s->smb_stat &= ~STS_HOST_BUSY;
} else {
s->op_done = false;
- s->smb_stat |= STS_HOST_BUSY;
+ s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
+ s->smb_data[0] = s->smb_blkdata;
+ s->smb_index = 0;
ret = 0;
}
- goto doneblk;
+ goto out;
}
break;
default:
@@ -181,18 +191,8 @@ done:
if (ret < 0) {
goto error;
}
- s->smb_stat |= STS_BYTE_DONE | STS_INTR;
- return;
-datablk:
- if (ret < 0) {
- goto error;
- }
- s->smb_data0 = ret;
-doneblk:
- if (ret < 0) {
- goto error;
- }
- s->smb_stat |= STS_BYTE_DONE;
+ s->smb_stat |= STS_INTR;
+out:
return;
error:
@@ -217,12 +217,43 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
case SMBHSTSTS:
s->smb_stat &= ~(val & ~STS_HOST_BUSY);
if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) {
- s->smb_stat |= STS_BYTE_DONE;
+ 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;
+
+ ret = smbus_write_block(s->smbus, addr, cmd, s->smb_data,
+ s->smb_data0,
+ prot != PROT_I2C_BLOCK_DATA);
+ 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;
+ } 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;
@@ -252,13 +283,10 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
s->smb_index = 0;
}
- s->smb_data[s->smb_index++] = val;
- if (!(s->smb_auxctl & AUX_BLK) && s->smb_ctl & CTL_START &&
- !s->op_done && s->smb_index == s->smb_data0) {
- smb_transaction(s);
- s->op_done = true;
- s->smb_stat |= STS_INTR;
- s->smb_stat &= ~STS_HOST_BUSY;
+ if (s->smb_auxctl & AUX_BLK) {
+ s->smb_data[s->smb_index++] = val;
+ } else {
+ s->smb_blkdata = val;
}
break;
case SMBAUXCTL:
@@ -268,6 +296,7 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
break;
}
+ out:
if (s->set_irq) {
s->set_irq(s, smb_irq_value(s));
}
@@ -301,18 +330,15 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
s->smb_index = 0;
}
- val = s->smb_data[s->smb_index++];
- if (s->smb_ctl & CTL_START && !s->op_done &&
- s->smb_index == s->smb_data0) {
- s->op_done = true;
- s->smb_index = 0;
- s->smb_stat &= ~STS_HOST_BUSY;
- }
- if (s->smb_ctl & CTL_LAST_BYTE) {
- s->op_done = true;
- s->smb_index = 0;
- s->smb_stat |= STS_INTR;
- s->smb_stat &= ~STS_HOST_BUSY;
+ 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:
@@ -366,11 +392,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 a01cb92..2c4f297 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -90,7 +90,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/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index bfe740a..1005d1f 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -14,6 +14,7 @@ typedef struct PMSMBus {
uint8_t smb_data0;
uint8_t smb_data1;
uint8_t smb_data[PM_SMBUS_MAX_MSG_SIZE];
+ uint8_t smb_blkdata;
uint8_t smb_auxctl;
uint32_t smb_index;
@@ -32,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] 8+ messages in thread
* [Qemu-devel] [PATCH v2 3/7] ipmi: Add an SMBus IPMI interface
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 1/7] i2c: Fix the PM SMBus driver so it actually works correctly minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 2/7] pm_smbus: Add the ability to force block transfer enable minyard
@ 2016-06-01 16:26 ` minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 4/7] acpi: Add i2c serial bus CRS handling minyard
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:26 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
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 b177e52..397d4e6 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 6e3b312..864d70c 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 a90318d..6a17912 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_LOCAL) += 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] 8+ messages in thread
* [Qemu-devel] [PATCH v2 4/7] acpi: Add i2c serial bus CRS handling
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
` (2 preceding siblings ...)
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 3/7] ipmi: Add an SMBus IPMI interface minyard
@ 2016-06-01 16:26 ` minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 5/7] ipmi: Fix SSIF ACPI handling to use the right CRS minyard
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:26 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
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 cedb74e..cd5569e 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1574,3 +1574,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 7eb51c7..c8904e4 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -213,6 +213,23 @@ struct AcpiBuildTables {
GArray *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:
*
@@ -334,6 +351,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] 8+ messages in thread
* [Qemu-devel] [PATCH v2 5/7] ipmi: Fix SSIF ACPI handling to use the right CRS
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
` (3 preceding siblings ...)
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 4/7] acpi: Add i2c serial bus CRS handling minyard
@ 2016-06-01 16:26 ` minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 6/7] pc: Add 2.7 machine options minyard
2016-06-01 16:27 ` [Qemu-devel] [PATCH v2 7/7] pc: Add an SMB0 ACPI device to q35 minyard
6 siblings, 0 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:26 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
From: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/acpi/ipmi.c | 13 +++++++------
hw/acpi/noipmi.c | 2 +-
hw/i386/acpi-build.c | 2 +-
include/hw/acpi/ipmi.h | 2 +-
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/hw/acpi/ipmi.c b/hw/acpi/ipmi.c
index 7e74ce4..628130a 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;
@@ -100,6 +101,6 @@ void build_acpi_ipmi_devices(Aml *scope, BusState *bus)
ii = IPMI_INTERFACE(obj);
iic = IPMI_INTERFACE_GET_CLASS(obj);
iic->get_fwinfo(ii, &info);
- aml_append(scope, aml_ipmi_device(&info));
+ aml_append(scope, aml_ipmi_device(&info, resource));
}
}
diff --git a/hw/acpi/noipmi.c b/hw/acpi/noipmi.c
index 98b6dce..6c71d6c 100644
--- a/hw/acpi/noipmi.c
+++ b/hw/acpi/noipmi.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)
{
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 4b05bc2..b11fd3b 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1470,7 +1470,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 */
--
2.7.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v2 6/7] pc: Add 2.7 machine options
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
` (4 preceding siblings ...)
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 5/7] ipmi: Fix SSIF ACPI handling to use the right CRS minyard
@ 2016-06-01 16:26 ` minyard
2016-06-01 16:27 ` [Qemu-devel] [PATCH v2 7/7] pc: Add an SMB0 ACPI device to q35 minyard
6 siblings, 0 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:26 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
From: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
hw/i386/pc_piix.c | 16 +++++++++++++---
hw/i386/pc_q35.c | 13 +++++++++++--
include/hw/i386/pc.h | 3 +++
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 24e7042..bf44093 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -416,13 +416,25 @@ static void pc_i440fx_machine_options(MachineClass *m)
m->default_display = "std";
}
-static void pc_i440fx_2_6_machine_options(MachineClass *m)
+static void pc_i440fx_2_7_machine_options(MachineClass *m)
{
pc_i440fx_machine_options(m);
m->alias = "pc";
m->is_default = 1;
}
+DEFINE_I440FX_MACHINE(v2_7, "pc-i440fx-2.7", NULL,
+ pc_i440fx_2_7_machine_options);
+
+
+static void pc_i440fx_2_6_machine_options(MachineClass *m)
+{
+ pc_i440fx_2_7_machine_options(m);
+ m->alias = NULL;
+ m->is_default = 0;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
+}
+
DEFINE_I440FX_MACHINE(v2_6, "pc-i440fx-2.6", NULL,
pc_i440fx_2_6_machine_options);
@@ -431,8 +443,6 @@ static void pc_i440fx_2_5_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_2_6_machine_options(m);
- m->alias = NULL;
- m->is_default = 0;
pcmc->save_tsc_khz = false;
m->legacy_fw_cfg_order = 1;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 04aae89..4787df1 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -283,12 +283,22 @@ static void pc_q35_machine_options(MachineClass *m)
m->no_floppy = 1;
}
-static void pc_q35_2_6_machine_options(MachineClass *m)
+static void pc_q35_2_7_machine_options(MachineClass *m)
{
pc_q35_machine_options(m);
m->alias = "q35";
}
+DEFINE_Q35_MACHINE(v2_7, "pc-q35-2.7", NULL,
+ pc_q35_2_7_machine_options);
+
+static void pc_q35_2_6_machine_options(MachineClass *m)
+{
+ pc_q35_2_7_machine_options(m);
+ m->alias = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
+}
+
DEFINE_Q35_MACHINE(v2_6, "pc-q35-2.6", NULL,
pc_q35_2_6_machine_options);
@@ -296,7 +306,6 @@ static void pc_q35_2_5_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_2_6_machine_options(m);
- m->alias = NULL;
pcmc->save_tsc_khz = false;
m->legacy_fw_cfg_order = 1;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 9ca2309..dd6d644 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -356,6 +356,9 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
+#define PC_COMPAT_2_6 \
+ HW_COMPAT_2_6
+
#define PC_COMPAT_2_5 \
HW_COMPAT_2_5
--
2.7.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v2 7/7] pc: Add an SMB0 ACPI device to q35
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
` (5 preceding siblings ...)
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 6/7] pc: Add 2.7 machine options minyard
@ 2016-06-01 16:27 ` minyard
6 siblings, 0 replies; 8+ messages in thread
From: minyard @ 2016-06-01 16:27 UTC (permalink / raw)
To: Igor Mammedov, Michael S . Tsirkin, Paolo Bonzini, qemu-devel,
minyard, cminyard
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 | 16 ++++++++++++++++
hw/i386/pc_piix.c | 13 +++++++------
hw/i386/pc_q35.c | 10 ++++++----
include/hw/i386/pc.h | 2 ++
tests/acpi-test-data/q35/DSDT | Bin 8357 -> 8395 bytes
tests/acpi-test-data/q35/DSDT.bridge | Bin 8374 -> 8412 bytes
tests/acpi-test-data/q35/DSDT.ipmibt | Bin 8432 -> 8470 bytes
7 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b11fd3b..cbc922d 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1990,6 +1990,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, GArray *linker,
AcpiPmInfo *pm, AcpiMiscInfo *misc,
@@ -2000,6 +2012,7 @@ build_dsdt(GArray *table_data, GArray *linker,
GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
PCMachineState *pcms = PC_MACHINE(machine);
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
uint32_t nr_mem = machine->ram_slots;
int root_bus_limit = 0xFF;
PCIBus *bus = NULL;
@@ -2053,6 +2066,9 @@ build_dsdt(GArray *table_data, GArray *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);
+ }
}
build_cpu_hotplug_aml(dsdt);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index bf44093..4e0ed1f 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -252,15 +252,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,
- 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,
+ 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,
@@ -429,9 +428,11 @@ DEFINE_I440FX_MACHINE(v2_7, "pc-i440fx-2.7", NULL,
static void pc_i440fx_2_6_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_2_7_machine_options(m);
m->alias = NULL;
m->is_default = 0;
+ 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 4787df1..2742bb2 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -240,10 +240,10 @@ static void pc_q35_init(MachineState *machine)
}
/* 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);
@@ -294,8 +294,10 @@ DEFINE_Q35_MACHINE(v2_7, "pc-q35-2.7", NULL,
static void pc_q35_2_6_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_2_7_machine_options(m);
m->alias = NULL;
+ 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 dd6d644..6737efc 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -51,6 +51,7 @@ struct PCMachineState {
HotplugHandler *acpi_dev;
ISADevice *rtc;
PCIBus *bus;
+ I2CBus *smbus;
FWCfgState *fw_cfg;
/* Configuration options: */
@@ -122,6 +123,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 1c089c34b06c9f2ea9fe67abb45498021319303c..9f3d165c756f6efc875e5364a157051e4ac929a5 100644
GIT binary patch
delta 62
zcmZ4Lc-oQ6CD<k8v;qSIW8p@wMoCpwz4&0K_yA{5gXkv7U|%N#j(87G7aleN23C%E
RN0%TTW(IkN&0Uhx>;M`y4+H=J
delta 24
fcmX@@xYUu$CD<iosR9E7qrpb5M#;?^C8gK_V66ug
diff --git a/tests/acpi-test-data/q35/DSDT.bridge b/tests/acpi-test-data/q35/DSDT.bridge
index b29fcda0bb1717ff708668c6e98f3ded3f34a96c..11ce6a8ddc7042ac7079549a8502467514d49ff8 100644
GIT binary patch
delta 62
zcmdnyc*l{;CD<k8jsgP%qu@raMoCpwz4&0K_yA{5gXkv7U|%N#j(87G7aleN23C%E
RN0%TTW(IkN&0Uf@>;Mz?4(I>?
delta 24
gcmccPxXqEvCD<ion*sv^<Ase}jgp%;N@}wM0Balv`2YX_
diff --git a/tests/acpi-test-data/q35/DSDT.ipmibt b/tests/acpi-test-data/q35/DSDT.ipmibt
index 74fc9b69204df80de3855657d3a4ff74e0eb964c..a25bd8c11d074a3b96513768987da5d1d40f9249 100644
GIT binary patch
delta 62
zcmez1IL(R6CD<iIOp$?saq32{Gm@&Rdhx+d@d3`B2GLED!M;ug9Pu8WE<9`k46GdS
SjxIqw%nb4jo3BbrvjYGS1P>tq
delta 24
gcmbQ{^udwKCD<k8g8~BsW9UY%Gm@MCNJ_B-0BcSNG5`Po
--
2.7.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-06-01 16:27 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-06-01 16:26 [Qemu-devel] [PATCH v2 0/7] An IPMI over SMBus device minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 1/7] i2c: Fix the PM SMBus driver so it actually works correctly minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 2/7] pm_smbus: Add the ability to force block transfer enable minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 3/7] ipmi: Add an SMBus IPMI interface minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 4/7] acpi: Add i2c serial bus CRS handling minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 5/7] ipmi: Fix SSIF ACPI handling to use the right CRS minyard
2016-06-01 16:26 ` [Qemu-devel] [PATCH v2 6/7] pc: Add 2.7 machine options minyard
2016-06-01 16:27 ` [Qemu-devel] [PATCH v2 7/7] pc: Add an SMB0 ACPI device to q35 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).