xref: /qemu/hw/ipmi/smbus_ipmi.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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