2 * QEMU IPMI SMBus (SSIF) emulation
4 * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "qemu/osdep.h"
25 #include "migration/vmstate.h"
26 #include "hw/i2c/smbus_slave.h"
27 #include "qapi/error.h"
28 #include "qemu/error-report.h"
29 #include "hw/ipmi/ipmi.h"
30 #include "qom/object.h"
31 #include "hw/acpi/ipmi.h"
33 #define TYPE_SMBUS_IPMI "smbus-ipmi"
34 OBJECT_DECLARE_SIMPLE_TYPE(SMBusIPMIDevice
, SMBUS_IPMI
)
36 #define SSIF_IPMI_REQUEST 2
37 #define SSIF_IPMI_MULTI_PART_REQUEST_START 6
38 #define SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE 7
39 #define SSIF_IPMI_MULTI_PART_REQUEST_END 8
40 #define SSIF_IPMI_RESPONSE 3
41 #define SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE 9
42 #define SSIF_IPMI_MULTI_PART_RETRY 0xa
44 #define MAX_SSIF_IPMI_MSG_SIZE 255
45 #define MAX_SSIF_IPMI_MSG_CHUNK 32
47 #define IPMI_GET_SYS_INTF_CAP_CMD 0x57
49 struct SMBusIPMIDevice
{
54 uint8_t outmsg
[MAX_SSIF_IPMI_MSG_SIZE
];
58 /* Holds the SMBUS message currently being sent to the host. */
59 uint8_t outbuf
[MAX_SSIF_IPMI_MSG_CHUNK
+ 1]; /* len + message. */
62 uint8_t inmsg
[MAX_SSIF_IPMI_MSG_SIZE
];
66 * This is a response number that we send with the command to make
67 * sure that the response matches the command.
74 static void smbus_ipmi_handle_event(IPMIInterface
*ii
)
76 /* No interrupts, so nothing to do here. */
79 static void smbus_ipmi_handle_rsp(IPMIInterface
*ii
, uint8_t msg_id
,
80 unsigned char *rsp
, unsigned int rsp_len
)
82 SMBusIPMIDevice
*sid
= SMBUS_IPMI(ii
);
84 if (sid
->waiting_rsp
== msg_id
) {
87 if (rsp_len
> MAX_SSIF_IPMI_MSG_SIZE
) {
88 rsp
[2] = IPMI_CC_REQUEST_DATA_TRUNCATED
;
89 rsp_len
= MAX_SSIF_IPMI_MSG_SIZE
;
91 memcpy(sid
->outmsg
, rsp
, rsp_len
);
92 sid
->outlen
= rsp_len
;
98 static void smbus_ipmi_set_atn(IPMIInterface
*ii
, int val
, int irq
)
100 /* This is where PEC would go. */
103 static void smbus_ipmi_set_irq_enable(IPMIInterface
*ii
, int val
)
107 static void smbus_ipmi_send_msg(SMBusIPMIDevice
*sid
)
109 uint8_t *msg
= sid
->inmsg
;
110 uint32_t len
= sid
->inlen
;
111 IPMIBmcClass
*bk
= IPMI_BMC_GET_CLASS(sid
->bmc
);
117 if (msg
[0] == (IPMI_NETFN_APP
<< 2) && msg
[1] == IPMI_GET_SYS_INTF_CAP_CMD
)
119 /* We handle this ourself. */
120 sid
->outmsg
[0] = (IPMI_NETFN_APP
+ 1) << 2;
121 sid
->outmsg
[1] = msg
[1];
123 sid
->outmsg
[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID
;
125 } else if ((msg
[2] & 0x0f) != 0) {
126 sid
->outmsg
[2] = IPMI_CC_INVALID_DATA_FIELD
;
131 sid
->outmsg
[4] = (2 << 6); /* Multi-part supported. */
132 sid
->outmsg
[5] = MAX_SSIF_IPMI_MSG_SIZE
;
133 sid
->outmsg
[6] = MAX_SSIF_IPMI_MSG_SIZE
;
139 bk
->handle_command(sid
->bmc
, sid
->inmsg
, sid
->inlen
, sizeof(sid
->inmsg
),
143 static uint8_t ipmi_receive_byte(SMBusDevice
*dev
)
145 SMBusIPMIDevice
*sid
= SMBUS_IPMI(dev
);
147 if (sid
->outpos
>= sizeof(sid
->outbuf
)) {
151 return sid
->outbuf
[sid
->outpos
++];
154 static int ipmi_load_readbuf(SMBusIPMIDevice
*sid
)
156 unsigned int block
= sid
->currblk
, pos
, len
;
158 if (sid
->outlen
== 0) {
162 if (sid
->outlen
<= 32) {
166 sid
->outbuf
[0] = sid
->outlen
;
167 memcpy(sid
->outbuf
+ 1, sid
->outmsg
, sid
->outlen
);
176 memcpy(sid
->outbuf
+ 3, sid
->outmsg
, 30);
182 * Calculate the position in outmsg. 30 for the first block, 31
183 * for the rest of the blocks.
185 pos
= 30 + (block
- 1) * 31;
187 if (pos
>= sid
->outlen
) {
191 len
= sid
->outlen
- pos
;
193 /* More chunks after this. */
195 /* Blocks start at 0 for the first middle transaction. */
196 sid
->outbuf
[1] = block
- 1;
198 sid
->outbuf
[1] = 0xff; /* End of message marker. */
201 sid
->outbuf
[0] = len
+ 1;
202 memcpy(sid
->outbuf
+ 2, sid
->outmsg
+ pos
, len
);
207 static int ipmi_write_data(SMBusDevice
*dev
, uint8_t *buf
, uint8_t len
)
209 SMBusIPMIDevice
*sid
= SMBUS_IPMI(dev
);
214 /* length is guaranteed to be >= 1. */
218 /* Handle read request, which don't have any data in the write part. */
220 case SSIF_IPMI_RESPONSE
:
222 ret
= ipmi_load_readbuf(sid
);
225 case SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE
:
227 ret
= ipmi_load_readbuf(sid
);
230 case SSIF_IPMI_MULTI_PART_RETRY
:
232 sid
->currblk
= buf
[0];
233 ret
= ipmi_load_readbuf(sid
);
243 /* This should be a message write, make the length is there and correct. */
245 if (*buf
!= len
- 1 || *buf
> MAX_SSIF_IPMI_MSG_CHUNK
) {
246 return -1; /* Bogus message */
253 case SSIF_IPMI_REQUEST
:
256 case SSIF_IPMI_MULTI_PART_REQUEST_START
:
258 return -1; /* Bogus. */
260 memcpy(sid
->inmsg
, buf
, len
);
264 case SSIF_IPMI_MULTI_PART_REQUEST_END
:
267 case SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE
:
269 return -1; /* Bogus. */
271 if (sid
->inlen
+ len
> MAX_SSIF_IPMI_MSG_SIZE
) {
272 sid
->inlen
= 0; /* Discard the message. */
273 return -1; /* Bogus. */
277 * Special hack, a multi-part middle that is less than 32 bytes
278 * marks the end of a message. The specification is fairly
279 * confusing, so some systems to this, even sending a zero
280 * length end message to mark the end.
285 memcpy(sid
->inmsg
+ sid
->inlen
, buf
, len
);
291 if (send
&& sid
->inlen
) {
292 smbus_ipmi_send_msg(sid
);
298 static const VMStateDescription vmstate_smbus_ipmi
= {
299 .name
= TYPE_SMBUS_IPMI
,
301 .minimum_version_id
= 1,
302 .fields
= (VMStateField
[]) {
303 VMSTATE_SMBUS_DEVICE(parent
, SMBusIPMIDevice
),
304 VMSTATE_UINT8(waiting_rsp
, SMBusIPMIDevice
),
305 VMSTATE_UINT32(outlen
, SMBusIPMIDevice
),
306 VMSTATE_UINT32(currblk
, SMBusIPMIDevice
),
307 VMSTATE_UINT8_ARRAY(outmsg
, SMBusIPMIDevice
, MAX_SSIF_IPMI_MSG_SIZE
),
308 VMSTATE_UINT32(outpos
, SMBusIPMIDevice
),
309 VMSTATE_UINT8_ARRAY(outbuf
, SMBusIPMIDevice
,
310 MAX_SSIF_IPMI_MSG_CHUNK
+ 1),
311 VMSTATE_UINT32(inlen
, SMBusIPMIDevice
),
312 VMSTATE_UINT8_ARRAY(inmsg
, SMBusIPMIDevice
, MAX_SSIF_IPMI_MSG_SIZE
),
313 VMSTATE_END_OF_LIST()
317 static void smbus_ipmi_realize(DeviceState
*dev
, Error
**errp
)
319 SMBusIPMIDevice
*sid
= SMBUS_IPMI(dev
);
320 IPMIInterface
*ii
= IPMI_INTERFACE(dev
);
323 error_setg(errp
, "IPMI device requires a bmc attribute to be set");
327 sid
->uuid
= ipmi_next_uuid();
332 static void smbus_ipmi_init(Object
*obj
)
334 SMBusIPMIDevice
*sid
= SMBUS_IPMI(obj
);
336 ipmi_bmc_find_and_link(obj
, (Object
**) &sid
->bmc
);
339 static void smbus_ipmi_get_fwinfo(struct IPMIInterface
*ii
, IPMIFwInfo
*info
)
341 SMBusIPMIDevice
*sid
= SMBUS_IPMI(ii
);
343 info
->interface_name
= "smbus";
344 info
->interface_type
= IPMI_SMBIOS_SSIF
;
345 info
->ipmi_spec_major_revision
= 2;
346 info
->ipmi_spec_minor_revision
= 0;
347 info
->i2c_slave_address
= sid
->bmc
->slave_addr
;
348 info
->base_address
= sid
->parent
.i2c
.address
;
349 info
->memspace
= IPMI_MEMSPACE_SMBUS
;
350 info
->register_spacing
= 1;
351 info
->uuid
= sid
->uuid
;
354 static void smbus_ipmi_class_init(ObjectClass
*oc
, void *data
)
356 DeviceClass
*dc
= DEVICE_CLASS(oc
);
357 IPMIInterfaceClass
*iic
= IPMI_INTERFACE_CLASS(oc
);
358 SMBusDeviceClass
*sc
= SMBUS_DEVICE_CLASS(oc
);
359 AcpiDevAmlIfClass
*adevc
= ACPI_DEV_AML_IF_CLASS(oc
);
361 sc
->receive_byte
= ipmi_receive_byte
;
362 sc
->write_data
= ipmi_write_data
;
363 dc
->vmsd
= &vmstate_smbus_ipmi
;
364 dc
->realize
= smbus_ipmi_realize
;
365 iic
->set_atn
= smbus_ipmi_set_atn
;
366 iic
->handle_rsp
= smbus_ipmi_handle_rsp
;
367 iic
->handle_if_event
= smbus_ipmi_handle_event
;
368 iic
->set_irq_enable
= smbus_ipmi_set_irq_enable
;
369 iic
->get_fwinfo
= smbus_ipmi_get_fwinfo
;
370 adevc
->build_dev_aml
= build_ipmi_dev_aml
;
373 static const TypeInfo smbus_ipmi_info
= {
374 .name
= TYPE_SMBUS_IPMI
,
375 .parent
= TYPE_SMBUS_DEVICE
,
376 .instance_size
= sizeof(SMBusIPMIDevice
),
377 .instance_init
= smbus_ipmi_init
,
378 .class_init
= smbus_ipmi_class_init
,
379 .interfaces
= (InterfaceInfo
[]) {
380 { TYPE_IPMI_INTERFACE
},
381 { TYPE_ACPI_DEV_AML_IF
},
386 static void smbus_ipmi_register_types(void)
388 type_register_static(&smbus_ipmi_info
);
391 type_init(smbus_ipmi_register_types
)