138033052SCorey Minyard /*
238033052SCorey Minyard * QEMU IPMI SMBus (SSIF) emulation
338033052SCorey Minyard *
438033052SCorey Minyard * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
538033052SCorey Minyard *
638033052SCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy
738033052SCorey Minyard * of this software and associated documentation files (the "Software"), to deal
838033052SCorey Minyard * in the Software without restriction, including without limitation the rights
938033052SCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1038033052SCorey Minyard * copies of the Software, and to permit persons to whom the Software is
1138033052SCorey Minyard * furnished to do so, subject to the following conditions:
1238033052SCorey Minyard *
1338033052SCorey Minyard * The above copyright notice and this permission notice shall be included in
1438033052SCorey Minyard * all copies or substantial portions of the Software.
1538033052SCorey Minyard *
1638033052SCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1738033052SCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1838033052SCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1938033052SCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2038033052SCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2138033052SCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2238033052SCorey Minyard * THE SOFTWARE.
2338033052SCorey Minyard */
2438033052SCorey Minyard #include "qemu/osdep.h"
2538033052SCorey Minyard #include "migration/vmstate.h"
2638033052SCorey Minyard #include "hw/i2c/smbus_slave.h"
2738033052SCorey Minyard #include "qapi/error.h"
2838033052SCorey Minyard #include "qemu/error-report.h"
2938033052SCorey Minyard #include "hw/ipmi/ipmi.h"
30db1015e9SEduardo Habkost #include "qom/object.h"
315876d9b5SIgor Mammedov #include "hw/acpi/ipmi.h"
3238033052SCorey Minyard
3338033052SCorey Minyard #define TYPE_SMBUS_IPMI "smbus-ipmi"
348063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(SMBusIPMIDevice, SMBUS_IPMI)
3538033052SCorey Minyard
3638033052SCorey Minyard #define SSIF_IPMI_REQUEST 2
3738033052SCorey Minyard #define SSIF_IPMI_MULTI_PART_REQUEST_START 6
3838033052SCorey Minyard #define SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE 7
3938033052SCorey Minyard #define SSIF_IPMI_MULTI_PART_REQUEST_END 8
4038033052SCorey Minyard #define SSIF_IPMI_RESPONSE 3
4138033052SCorey Minyard #define SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE 9
4238033052SCorey Minyard #define SSIF_IPMI_MULTI_PART_RETRY 0xa
4338033052SCorey Minyard
4438033052SCorey Minyard #define MAX_SSIF_IPMI_MSG_SIZE 255
4538033052SCorey Minyard #define MAX_SSIF_IPMI_MSG_CHUNK 32
4638033052SCorey Minyard
4738033052SCorey Minyard #define IPMI_GET_SYS_INTF_CAP_CMD 0x57
4838033052SCorey Minyard
49db1015e9SEduardo Habkost struct SMBusIPMIDevice {
5038033052SCorey Minyard SMBusDevice parent;
5138033052SCorey Minyard
5238033052SCorey Minyard IPMIBmc *bmc;
5338033052SCorey Minyard
5438033052SCorey Minyard uint8_t outmsg[MAX_SSIF_IPMI_MSG_SIZE];
5538033052SCorey Minyard uint32_t outlen;
5638033052SCorey Minyard uint32_t currblk;
5738033052SCorey Minyard
5838033052SCorey Minyard /* Holds the SMBUS message currently being sent to the host. */
5938033052SCorey Minyard uint8_t outbuf[MAX_SSIF_IPMI_MSG_CHUNK + 1]; /* len + message. */
6038033052SCorey Minyard uint32_t outpos;
6138033052SCorey Minyard
6238033052SCorey Minyard uint8_t inmsg[MAX_SSIF_IPMI_MSG_SIZE];
6338033052SCorey Minyard uint32_t inlen;
6438033052SCorey Minyard
6538033052SCorey Minyard /*
6638033052SCorey Minyard * This is a response number that we send with the command to make
6738033052SCorey Minyard * sure that the response matches the command.
6838033052SCorey Minyard */
6938033052SCorey Minyard uint8_t waiting_rsp;
7038033052SCorey Minyard
7138033052SCorey Minyard uint32_t uuid;
72db1015e9SEduardo Habkost };
7338033052SCorey Minyard
smbus_ipmi_handle_event(IPMIInterface * ii)7438033052SCorey Minyard static void smbus_ipmi_handle_event(IPMIInterface *ii)
7538033052SCorey Minyard {
7638033052SCorey Minyard /* No interrupts, so nothing to do here. */
7738033052SCorey Minyard }
7838033052SCorey Minyard
smbus_ipmi_handle_rsp(IPMIInterface * ii,uint8_t msg_id,unsigned char * rsp,unsigned int rsp_len)7938033052SCorey Minyard static void smbus_ipmi_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
8038033052SCorey Minyard unsigned char *rsp, unsigned int rsp_len)
8138033052SCorey Minyard {
8238033052SCorey Minyard SMBusIPMIDevice *sid = SMBUS_IPMI(ii);
8338033052SCorey Minyard
8438033052SCorey Minyard if (sid->waiting_rsp == msg_id) {
8538033052SCorey Minyard sid->waiting_rsp++;
8638033052SCorey Minyard
8738033052SCorey Minyard if (rsp_len > MAX_SSIF_IPMI_MSG_SIZE) {
8838033052SCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
8938033052SCorey Minyard rsp_len = MAX_SSIF_IPMI_MSG_SIZE;
9038033052SCorey Minyard }
9138033052SCorey Minyard memcpy(sid->outmsg, rsp, rsp_len);
9238033052SCorey Minyard sid->outlen = rsp_len;
9338033052SCorey Minyard sid->outpos = 0;
9438033052SCorey Minyard sid->currblk = 0;
9538033052SCorey Minyard }
9638033052SCorey Minyard }
9738033052SCorey Minyard
smbus_ipmi_set_atn(IPMIInterface * ii,int val,int irq)9838033052SCorey Minyard static void smbus_ipmi_set_atn(IPMIInterface *ii, int val, int irq)
9938033052SCorey Minyard {
10038033052SCorey Minyard /* This is where PEC would go. */
10138033052SCorey Minyard }
10238033052SCorey Minyard
smbus_ipmi_set_irq_enable(IPMIInterface * ii,int val)10338033052SCorey Minyard static void smbus_ipmi_set_irq_enable(IPMIInterface *ii, int val)
10438033052SCorey Minyard {
10538033052SCorey Minyard }
10638033052SCorey Minyard
smbus_ipmi_send_msg(SMBusIPMIDevice * sid)10738033052SCorey Minyard static void smbus_ipmi_send_msg(SMBusIPMIDevice *sid)
10838033052SCorey Minyard {
10938033052SCorey Minyard uint8_t *msg = sid->inmsg;
11038033052SCorey Minyard uint32_t len = sid->inlen;
11138033052SCorey Minyard IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(sid->bmc);
11238033052SCorey Minyard
11338033052SCorey Minyard sid->outlen = 0;
11438033052SCorey Minyard sid->outpos = 0;
11538033052SCorey Minyard sid->currblk = 0;
11638033052SCorey Minyard
11738033052SCorey Minyard if (msg[0] == (IPMI_NETFN_APP << 2) && msg[1] == IPMI_GET_SYS_INTF_CAP_CMD)
11838033052SCorey Minyard {
11938033052SCorey Minyard /* We handle this ourself. */
12038033052SCorey Minyard sid->outmsg[0] = (IPMI_NETFN_APP + 1) << 2;
12138033052SCorey Minyard sid->outmsg[1] = msg[1];
12238033052SCorey Minyard if (len < 3) {
12338033052SCorey Minyard sid->outmsg[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
12438033052SCorey Minyard sid->outlen = 3;
12538033052SCorey Minyard } else if ((msg[2] & 0x0f) != 0) {
12638033052SCorey Minyard sid->outmsg[2] = IPMI_CC_INVALID_DATA_FIELD;
12738033052SCorey Minyard sid->outlen = 3;
12838033052SCorey Minyard } else {
12938033052SCorey Minyard sid->outmsg[2] = 0;
13038033052SCorey Minyard sid->outmsg[3] = 0;
13138033052SCorey Minyard sid->outmsg[4] = (2 << 6); /* Multi-part supported. */
13238033052SCorey Minyard sid->outmsg[5] = MAX_SSIF_IPMI_MSG_SIZE;
13338033052SCorey Minyard sid->outmsg[6] = MAX_SSIF_IPMI_MSG_SIZE;
13438033052SCorey Minyard sid->outlen = 7;
13538033052SCorey Minyard }
13638033052SCorey Minyard return;
13738033052SCorey Minyard }
13838033052SCorey Minyard
13938033052SCorey Minyard bk->handle_command(sid->bmc, sid->inmsg, sid->inlen, sizeof(sid->inmsg),
14038033052SCorey Minyard sid->waiting_rsp);
14138033052SCorey Minyard }
14238033052SCorey Minyard
ipmi_receive_byte(SMBusDevice * dev)14338033052SCorey Minyard static uint8_t ipmi_receive_byte(SMBusDevice *dev)
14438033052SCorey Minyard {
14538033052SCorey Minyard SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
14638033052SCorey Minyard
14738033052SCorey Minyard if (sid->outpos >= sizeof(sid->outbuf)) {
14838033052SCorey Minyard return 0xff;
14938033052SCorey Minyard }
15038033052SCorey Minyard
15138033052SCorey Minyard return sid->outbuf[sid->outpos++];
15238033052SCorey Minyard }
15338033052SCorey Minyard
ipmi_load_readbuf(SMBusIPMIDevice * sid)15438033052SCorey Minyard static int ipmi_load_readbuf(SMBusIPMIDevice *sid)
15538033052SCorey Minyard {
15638033052SCorey Minyard unsigned int block = sid->currblk, pos, len;
15738033052SCorey Minyard
15838033052SCorey Minyard if (sid->outlen == 0) {
15938033052SCorey Minyard return -1;
16038033052SCorey Minyard }
16138033052SCorey Minyard
16238033052SCorey Minyard if (sid->outlen <= 32) {
16338033052SCorey Minyard if (block != 0) {
16438033052SCorey Minyard return -1;
16538033052SCorey Minyard }
16638033052SCorey Minyard sid->outbuf[0] = sid->outlen;
16738033052SCorey Minyard memcpy(sid->outbuf + 1, sid->outmsg, sid->outlen);
16838033052SCorey Minyard sid->outpos = 0;
16938033052SCorey Minyard return 0;
17038033052SCorey Minyard }
17138033052SCorey Minyard
17238033052SCorey Minyard if (block == 0) {
17338033052SCorey Minyard sid->outbuf[0] = 32;
17438033052SCorey Minyard sid->outbuf[1] = 0;
17538033052SCorey Minyard sid->outbuf[2] = 1;
17638033052SCorey Minyard memcpy(sid->outbuf + 3, sid->outmsg, 30);
17738033052SCorey Minyard sid->outpos = 0;
17838033052SCorey Minyard return 0;
17938033052SCorey Minyard }
18038033052SCorey Minyard
18138033052SCorey Minyard /*
18238033052SCorey Minyard * Calculate the position in outmsg. 30 for the first block, 31
18338033052SCorey Minyard * for the rest of the blocks.
18438033052SCorey Minyard */
18538033052SCorey Minyard pos = 30 + (block - 1) * 31;
18638033052SCorey Minyard
18738033052SCorey Minyard if (pos >= sid->outlen) {
18838033052SCorey Minyard return -1;
18938033052SCorey Minyard }
19038033052SCorey Minyard
19138033052SCorey Minyard len = sid->outlen - pos;
19238033052SCorey Minyard if (len > 31) {
19338033052SCorey Minyard /* More chunks after this. */
19438033052SCorey Minyard len = 31;
19538033052SCorey Minyard /* Blocks start at 0 for the first middle transaction. */
19638033052SCorey Minyard sid->outbuf[1] = block - 1;
19738033052SCorey Minyard } else {
19838033052SCorey Minyard sid->outbuf[1] = 0xff; /* End of message marker. */
19938033052SCorey Minyard }
20038033052SCorey Minyard
20138033052SCorey Minyard sid->outbuf[0] = len + 1;
20238033052SCorey Minyard memcpy(sid->outbuf + 2, sid->outmsg + pos, len);
20338033052SCorey Minyard sid->outpos = 0;
20438033052SCorey Minyard return 0;
20538033052SCorey Minyard }
20638033052SCorey Minyard
ipmi_write_data(SMBusDevice * dev,uint8_t * buf,uint8_t len)20738033052SCorey Minyard static int ipmi_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
20838033052SCorey Minyard {
20938033052SCorey Minyard SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
21038033052SCorey Minyard bool send = false;
21138033052SCorey Minyard uint8_t cmd;
21238033052SCorey Minyard int ret = 0;
21338033052SCorey Minyard
21438033052SCorey Minyard /* length is guaranteed to be >= 1. */
21538033052SCorey Minyard cmd = *buf++;
21638033052SCorey Minyard len--;
21738033052SCorey Minyard
21838033052SCorey Minyard /* Handle read request, which don't have any data in the write part. */
21938033052SCorey Minyard switch (cmd) {
22038033052SCorey Minyard case SSIF_IPMI_RESPONSE:
22138033052SCorey Minyard sid->currblk = 0;
22238033052SCorey Minyard ret = ipmi_load_readbuf(sid);
22338033052SCorey Minyard break;
22438033052SCorey Minyard
22538033052SCorey Minyard case SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE:
22638033052SCorey Minyard sid->currblk++;
22738033052SCorey Minyard ret = ipmi_load_readbuf(sid);
22838033052SCorey Minyard break;
22938033052SCorey Minyard
23038033052SCorey Minyard case SSIF_IPMI_MULTI_PART_RETRY:
23138033052SCorey Minyard if (len >= 1) {
23238033052SCorey Minyard sid->currblk = buf[0];
23338033052SCorey Minyard ret = ipmi_load_readbuf(sid);
23438033052SCorey Minyard } else {
23538033052SCorey Minyard ret = -1;
23638033052SCorey Minyard }
23738033052SCorey Minyard break;
23838033052SCorey Minyard
23938033052SCorey Minyard default:
24038033052SCorey Minyard break;
24138033052SCorey Minyard }
24238033052SCorey Minyard
24338033052SCorey Minyard /* This should be a message write, make the length is there and correct. */
24438033052SCorey Minyard if (len >= 1) {
24538033052SCorey Minyard if (*buf != len - 1 || *buf > MAX_SSIF_IPMI_MSG_CHUNK) {
24638033052SCorey Minyard return -1; /* Bogus message */
24738033052SCorey Minyard }
24838033052SCorey Minyard buf++;
24938033052SCorey Minyard len--;
25038033052SCorey Minyard }
25138033052SCorey Minyard
25238033052SCorey Minyard switch (cmd) {
25338033052SCorey Minyard case SSIF_IPMI_REQUEST:
25438033052SCorey Minyard send = true;
25538033052SCorey Minyard /* FALLTHRU */
25638033052SCorey Minyard case SSIF_IPMI_MULTI_PART_REQUEST_START:
25738033052SCorey Minyard if (len < 2) {
25838033052SCorey Minyard return -1; /* Bogus. */
25938033052SCorey Minyard }
26038033052SCorey Minyard memcpy(sid->inmsg, buf, len);
26138033052SCorey Minyard sid->inlen = len;
26238033052SCorey Minyard break;
26338033052SCorey Minyard
26438033052SCorey Minyard case SSIF_IPMI_MULTI_PART_REQUEST_END:
26538033052SCorey Minyard send = true;
26638033052SCorey Minyard /* FALLTHRU */
26738033052SCorey Minyard case SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE:
26838033052SCorey Minyard if (!sid->inlen) {
26938033052SCorey Minyard return -1; /* Bogus. */
27038033052SCorey Minyard }
27138033052SCorey Minyard if (sid->inlen + len > MAX_SSIF_IPMI_MSG_SIZE) {
27238033052SCorey Minyard sid->inlen = 0; /* Discard the message. */
27338033052SCorey Minyard return -1; /* Bogus. */
27438033052SCorey Minyard }
27538033052SCorey Minyard if (len < 32) {
27638033052SCorey Minyard /*
27738033052SCorey Minyard * Special hack, a multi-part middle that is less than 32 bytes
27838033052SCorey Minyard * marks the end of a message. The specification is fairly
27938033052SCorey Minyard * confusing, so some systems to this, even sending a zero
28038033052SCorey Minyard * length end message to mark the end.
28138033052SCorey Minyard */
28238033052SCorey Minyard send = true;
28338033052SCorey Minyard }
2843fde641eSCorey Minyard if (len > 0) {
28538033052SCorey Minyard memcpy(sid->inmsg + sid->inlen, buf, len);
2863fde641eSCorey Minyard }
28738033052SCorey Minyard sid->inlen += len;
28838033052SCorey Minyard break;
28938033052SCorey Minyard }
29038033052SCorey Minyard
29138033052SCorey Minyard if (send && sid->inlen) {
29238033052SCorey Minyard smbus_ipmi_send_msg(sid);
29338033052SCorey Minyard }
29438033052SCorey Minyard
29538033052SCorey Minyard return ret;
29638033052SCorey Minyard }
29738033052SCorey Minyard
29838033052SCorey Minyard static const VMStateDescription vmstate_smbus_ipmi = {
29938033052SCorey Minyard .name = TYPE_SMBUS_IPMI,
30038033052SCorey Minyard .version_id = 1,
30138033052SCorey Minyard .minimum_version_id = 1,
30209c6ac6dSRichard Henderson .fields = (const VMStateField[]) {
30338033052SCorey Minyard VMSTATE_SMBUS_DEVICE(parent, SMBusIPMIDevice),
30438033052SCorey Minyard VMSTATE_UINT8(waiting_rsp, SMBusIPMIDevice),
30538033052SCorey Minyard VMSTATE_UINT32(outlen, SMBusIPMIDevice),
30638033052SCorey Minyard VMSTATE_UINT32(currblk, SMBusIPMIDevice),
30738033052SCorey Minyard VMSTATE_UINT8_ARRAY(outmsg, SMBusIPMIDevice, MAX_SSIF_IPMI_MSG_SIZE),
30838033052SCorey Minyard VMSTATE_UINT32(outpos, SMBusIPMIDevice),
30938033052SCorey Minyard VMSTATE_UINT8_ARRAY(outbuf, SMBusIPMIDevice,
31038033052SCorey Minyard MAX_SSIF_IPMI_MSG_CHUNK + 1),
31138033052SCorey Minyard VMSTATE_UINT32(inlen, SMBusIPMIDevice),
31238033052SCorey Minyard VMSTATE_UINT8_ARRAY(inmsg, SMBusIPMIDevice, MAX_SSIF_IPMI_MSG_SIZE),
31338033052SCorey Minyard VMSTATE_END_OF_LIST()
31438033052SCorey Minyard }
31538033052SCorey Minyard };
31638033052SCorey Minyard
smbus_ipmi_realize(DeviceState * dev,Error ** errp)31738033052SCorey Minyard static void smbus_ipmi_realize(DeviceState *dev, Error **errp)
31838033052SCorey Minyard {
31938033052SCorey Minyard SMBusIPMIDevice *sid = SMBUS_IPMI(dev);
32038033052SCorey Minyard IPMIInterface *ii = IPMI_INTERFACE(dev);
32138033052SCorey Minyard
32238033052SCorey Minyard if (!sid->bmc) {
32338033052SCorey Minyard error_setg(errp, "IPMI device requires a bmc attribute to be set");
32438033052SCorey Minyard return;
32538033052SCorey Minyard }
32638033052SCorey Minyard
32738033052SCorey Minyard sid->uuid = ipmi_next_uuid();
32838033052SCorey Minyard
32938033052SCorey Minyard sid->bmc->intf = ii;
33038033052SCorey Minyard }
33138033052SCorey Minyard
smbus_ipmi_init(Object * obj)33238033052SCorey Minyard static void smbus_ipmi_init(Object *obj)
33338033052SCorey Minyard {
33438033052SCorey Minyard SMBusIPMIDevice *sid = SMBUS_IPMI(obj);
33538033052SCorey Minyard
336688ffbb4SPhilippe Mathieu-Daudé ipmi_bmc_find_and_link(obj, (Object **) &sid->bmc);
33738033052SCorey Minyard }
33838033052SCorey Minyard
smbus_ipmi_get_fwinfo(struct IPMIInterface * ii,IPMIFwInfo * info)33938033052SCorey Minyard static void smbus_ipmi_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
34038033052SCorey Minyard {
34138033052SCorey Minyard SMBusIPMIDevice *sid = SMBUS_IPMI(ii);
34238033052SCorey Minyard
34338033052SCorey Minyard info->interface_name = "smbus";
34438033052SCorey Minyard info->interface_type = IPMI_SMBIOS_SSIF;
34538033052SCorey Minyard info->ipmi_spec_major_revision = 2;
34638033052SCorey Minyard info->ipmi_spec_minor_revision = 0;
34738033052SCorey Minyard info->i2c_slave_address = sid->bmc->slave_addr;
34838033052SCorey Minyard info->base_address = sid->parent.i2c.address;
34938033052SCorey Minyard info->memspace = IPMI_MEMSPACE_SMBUS;
35038033052SCorey Minyard info->register_spacing = 1;
35138033052SCorey Minyard info->uuid = sid->uuid;
35238033052SCorey Minyard }
35338033052SCorey Minyard
smbus_ipmi_class_init(ObjectClass * oc,const void * data)35412d1a768SPhilippe Mathieu-Daudé static void smbus_ipmi_class_init(ObjectClass *oc, const void *data)
35538033052SCorey Minyard {
35638033052SCorey Minyard DeviceClass *dc = DEVICE_CLASS(oc);
35738033052SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
35838033052SCorey Minyard SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(oc);
3595876d9b5SIgor Mammedov AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc);
36038033052SCorey Minyard
36138033052SCorey Minyard sc->receive_byte = ipmi_receive_byte;
36238033052SCorey Minyard sc->write_data = ipmi_write_data;
36338033052SCorey Minyard dc->vmsd = &vmstate_smbus_ipmi;
36438033052SCorey Minyard dc->realize = smbus_ipmi_realize;
36538033052SCorey Minyard iic->set_atn = smbus_ipmi_set_atn;
36638033052SCorey Minyard iic->handle_rsp = smbus_ipmi_handle_rsp;
36738033052SCorey Minyard iic->handle_if_event = smbus_ipmi_handle_event;
36838033052SCorey Minyard iic->set_irq_enable = smbus_ipmi_set_irq_enable;
36938033052SCorey Minyard iic->get_fwinfo = smbus_ipmi_get_fwinfo;
3705876d9b5SIgor Mammedov adevc->build_dev_aml = build_ipmi_dev_aml;
37138033052SCorey Minyard }
37238033052SCorey Minyard
37338033052SCorey Minyard static const TypeInfo smbus_ipmi_info = {
37438033052SCorey Minyard .name = TYPE_SMBUS_IPMI,
37538033052SCorey Minyard .parent = TYPE_SMBUS_DEVICE,
37638033052SCorey Minyard .instance_size = sizeof(SMBusIPMIDevice),
37738033052SCorey Minyard .instance_init = smbus_ipmi_init,
37838033052SCorey Minyard .class_init = smbus_ipmi_class_init,
379*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
38038033052SCorey Minyard { TYPE_IPMI_INTERFACE },
3815876d9b5SIgor Mammedov { TYPE_ACPI_DEV_AML_IF },
38238033052SCorey Minyard { }
38338033052SCorey Minyard }
38438033052SCorey Minyard };
38538033052SCorey Minyard
smbus_ipmi_register_types(void)38638033052SCorey Minyard static void smbus_ipmi_register_types(void)
38738033052SCorey Minyard {
38838033052SCorey Minyard type_register_static(&smbus_ipmi_info);
38938033052SCorey Minyard }
39038033052SCorey Minyard
39138033052SCorey Minyard type_init(smbus_ipmi_register_types)
392