10f310cd6SCorey Minyard /*
20f310cd6SCorey Minyard * QEMU IPMI KCS emulation
30f310cd6SCorey Minyard *
40f310cd6SCorey Minyard * Copyright (c) 2015,2017 Corey Minyard, MontaVista Software, LLC
50f310cd6SCorey Minyard *
60f310cd6SCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy
70f310cd6SCorey Minyard * of this software and associated documentation files (the "Software"), to deal
80f310cd6SCorey Minyard * in the Software without restriction, including without limitation the rights
90f310cd6SCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100f310cd6SCorey Minyard * copies of the Software, and to permit persons to whom the Software is
110f310cd6SCorey Minyard * furnished to do so, subject to the following conditions:
120f310cd6SCorey Minyard *
130f310cd6SCorey Minyard * The above copyright notice and this permission notice shall be included in
140f310cd6SCorey Minyard * all copies or substantial portions of the Software.
150f310cd6SCorey Minyard *
160f310cd6SCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170f310cd6SCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180f310cd6SCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
190f310cd6SCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200f310cd6SCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
210f310cd6SCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
220f310cd6SCorey Minyard * THE SOFTWARE.
230f310cd6SCorey Minyard */
240f310cd6SCorey Minyard #include "qemu/osdep.h"
250f310cd6SCorey Minyard #include "migration/vmstate.h"
260f310cd6SCorey Minyard #include "qemu/log.h"
270f310cd6SCorey Minyard #include "qapi/error.h"
280f310cd6SCorey Minyard #include "hw/ipmi/ipmi_kcs.h"
290f310cd6SCorey Minyard
300f310cd6SCorey Minyard #define IPMI_KCS_OBF_BIT 0
310f310cd6SCorey Minyard #define IPMI_KCS_IBF_BIT 1
320f310cd6SCorey Minyard #define IPMI_KCS_SMS_ATN_BIT 2
330f310cd6SCorey Minyard #define IPMI_KCS_CD_BIT 3
340f310cd6SCorey Minyard
350f310cd6SCorey Minyard #define IPMI_KCS_OBF_MASK (1 << IPMI_KCS_OBF_BIT)
360f310cd6SCorey Minyard #define IPMI_KCS_GET_OBF(d) (((d) >> IPMI_KCS_OBF_BIT) & 0x1)
370f310cd6SCorey Minyard #define IPMI_KCS_SET_OBF(d, v) (d) = (((d) & ~IPMI_KCS_OBF_MASK) | \
380f310cd6SCorey Minyard (((v) & 1) << IPMI_KCS_OBF_BIT))
390f310cd6SCorey Minyard #define IPMI_KCS_IBF_MASK (1 << IPMI_KCS_IBF_BIT)
400f310cd6SCorey Minyard #define IPMI_KCS_GET_IBF(d) (((d) >> IPMI_KCS_IBF_BIT) & 0x1)
410f310cd6SCorey Minyard #define IPMI_KCS_SET_IBF(d, v) (d) = (((d) & ~IPMI_KCS_IBF_MASK) | \
420f310cd6SCorey Minyard (((v) & 1) << IPMI_KCS_IBF_BIT))
430f310cd6SCorey Minyard #define IPMI_KCS_SMS_ATN_MASK (1 << IPMI_KCS_SMS_ATN_BIT)
440f310cd6SCorey Minyard #define IPMI_KCS_GET_SMS_ATN(d) (((d) >> IPMI_KCS_SMS_ATN_BIT) & 0x1)
450f310cd6SCorey Minyard #define IPMI_KCS_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_KCS_SMS_ATN_MASK) | \
460f310cd6SCorey Minyard (((v) & 1) << IPMI_KCS_SMS_ATN_BIT))
470f310cd6SCorey Minyard #define IPMI_KCS_CD_MASK (1 << IPMI_KCS_CD_BIT)
480f310cd6SCorey Minyard #define IPMI_KCS_GET_CD(d) (((d) >> IPMI_KCS_CD_BIT) & 0x1)
490f310cd6SCorey Minyard #define IPMI_KCS_SET_CD(d, v) (d) = (((d) & ~IPMI_KCS_CD_MASK) | \
500f310cd6SCorey Minyard (((v) & 1) << IPMI_KCS_CD_BIT))
510f310cd6SCorey Minyard
520f310cd6SCorey Minyard #define IPMI_KCS_IDLE_STATE 0
530f310cd6SCorey Minyard #define IPMI_KCS_READ_STATE 1
540f310cd6SCorey Minyard #define IPMI_KCS_WRITE_STATE 2
550f310cd6SCorey Minyard #define IPMI_KCS_ERROR_STATE 3
560f310cd6SCorey Minyard
570f310cd6SCorey Minyard #define IPMI_KCS_GET_STATE(d) (((d) >> 6) & 0x3)
580f310cd6SCorey Minyard #define IPMI_KCS_SET_STATE(d, v) ((d) = ((d) & ~0xc0) | (((v) & 0x3) << 6))
590f310cd6SCorey Minyard
600f310cd6SCorey Minyard #define IPMI_KCS_ABORT_STATUS_CMD 0x60
610f310cd6SCorey Minyard #define IPMI_KCS_WRITE_START_CMD 0x61
620f310cd6SCorey Minyard #define IPMI_KCS_WRITE_END_CMD 0x62
630f310cd6SCorey Minyard #define IPMI_KCS_READ_CMD 0x68
640f310cd6SCorey Minyard
650f310cd6SCorey Minyard #define IPMI_KCS_STATUS_NO_ERR 0x00
660f310cd6SCorey Minyard #define IPMI_KCS_STATUS_ABORTED_ERR 0x01
670f310cd6SCorey Minyard #define IPMI_KCS_STATUS_BAD_CC_ERR 0x02
680f310cd6SCorey Minyard #define IPMI_KCS_STATUS_LENGTH_ERR 0x06
690f310cd6SCorey Minyard
ipmi_kcs_raise_irq(IPMIKCS * ik)700f310cd6SCorey Minyard static void ipmi_kcs_raise_irq(IPMIKCS *ik)
710f310cd6SCorey Minyard {
720f310cd6SCorey Minyard if (ik->use_irq && ik->irqs_enabled && ik->raise_irq) {
730f310cd6SCorey Minyard ik->raise_irq(ik);
740f310cd6SCorey Minyard }
750f310cd6SCorey Minyard }
760f310cd6SCorey Minyard
ipmi_kcs_lower_irq(IPMIKCS * ik)770f310cd6SCorey Minyard static void ipmi_kcs_lower_irq(IPMIKCS *ik)
780f310cd6SCorey Minyard {
790f310cd6SCorey Minyard if (ik->lower_irq) {
800f310cd6SCorey Minyard ik->lower_irq(ik);
810f310cd6SCorey Minyard }
820f310cd6SCorey Minyard }
830f310cd6SCorey Minyard
840f310cd6SCorey Minyard #define SET_OBF() \
850f310cd6SCorey Minyard do { \
860f310cd6SCorey Minyard IPMI_KCS_SET_OBF(ik->status_reg, 1); \
870f310cd6SCorey Minyard if (!ik->obf_irq_set) { \
880f310cd6SCorey Minyard ik->obf_irq_set = 1; \
890f310cd6SCorey Minyard if (!ik->atn_irq_set) { \
900f310cd6SCorey Minyard ipmi_kcs_raise_irq(ik); \
910f310cd6SCorey Minyard } \
920f310cd6SCorey Minyard } \
930f310cd6SCorey Minyard } while (0)
940f310cd6SCorey Minyard
ipmi_kcs_signal(IPMIKCS * ik,IPMIInterface * ii)950f310cd6SCorey Minyard static void ipmi_kcs_signal(IPMIKCS *ik, IPMIInterface *ii)
960f310cd6SCorey Minyard {
970f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
980f310cd6SCorey Minyard
990f310cd6SCorey Minyard ik->do_wake = 1;
1000f310cd6SCorey Minyard while (ik->do_wake) {
1010f310cd6SCorey Minyard ik->do_wake = 0;
1020f310cd6SCorey Minyard iic->handle_if_event(ii);
1030f310cd6SCorey Minyard }
1040f310cd6SCorey Minyard }
1050f310cd6SCorey Minyard
ipmi_kcs_handle_event(IPMIInterface * ii)1060f310cd6SCorey Minyard static void ipmi_kcs_handle_event(IPMIInterface *ii)
1070f310cd6SCorey Minyard {
1080f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
1090f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii);
1100f310cd6SCorey Minyard
1110f310cd6SCorey Minyard if (ik->cmd_reg == IPMI_KCS_ABORT_STATUS_CMD) {
1120f310cd6SCorey Minyard if (IPMI_KCS_GET_STATE(ik->status_reg) != IPMI_KCS_ERROR_STATE) {
1130f310cd6SCorey Minyard ik->waiting_rsp++; /* Invalidate the message */
1140f310cd6SCorey Minyard ik->outmsg[0] = IPMI_KCS_STATUS_ABORTED_ERR;
1150f310cd6SCorey Minyard ik->outlen = 1;
1160f310cd6SCorey Minyard ik->outpos = 0;
1170f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
1180f310cd6SCorey Minyard SET_OBF();
1190f310cd6SCorey Minyard }
1200f310cd6SCorey Minyard goto out;
1210f310cd6SCorey Minyard }
1220f310cd6SCorey Minyard
1230f310cd6SCorey Minyard switch (IPMI_KCS_GET_STATE(ik->status_reg)) {
1240f310cd6SCorey Minyard case IPMI_KCS_IDLE_STATE:
1250f310cd6SCorey Minyard if (ik->cmd_reg == IPMI_KCS_WRITE_START_CMD) {
1260f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_WRITE_STATE);
1270f310cd6SCorey Minyard ik->cmd_reg = -1;
1280f310cd6SCorey Minyard ik->write_end = 0;
1290f310cd6SCorey Minyard ik->inlen = 0;
1300f310cd6SCorey Minyard SET_OBF();
1310f310cd6SCorey Minyard }
1320f310cd6SCorey Minyard break;
1330f310cd6SCorey Minyard
1340f310cd6SCorey Minyard case IPMI_KCS_READ_STATE:
1350f310cd6SCorey Minyard handle_read:
1360f310cd6SCorey Minyard if (ik->outpos >= ik->outlen) {
1370f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_IDLE_STATE);
1380f310cd6SCorey Minyard SET_OBF();
1390f310cd6SCorey Minyard } else if (ik->data_in_reg == IPMI_KCS_READ_CMD) {
1400f310cd6SCorey Minyard ik->data_out_reg = ik->outmsg[ik->outpos];
1410f310cd6SCorey Minyard ik->outpos++;
1420f310cd6SCorey Minyard SET_OBF();
1430f310cd6SCorey Minyard } else {
1440f310cd6SCorey Minyard ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
1450f310cd6SCorey Minyard ik->outlen = 1;
1460f310cd6SCorey Minyard ik->outpos = 0;
1470f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
1480f310cd6SCorey Minyard SET_OBF();
1490f310cd6SCorey Minyard goto out;
1500f310cd6SCorey Minyard }
1510f310cd6SCorey Minyard break;
1520f310cd6SCorey Minyard
1530f310cd6SCorey Minyard case IPMI_KCS_WRITE_STATE:
1540f310cd6SCorey Minyard if (ik->data_in_reg != -1) {
1550f310cd6SCorey Minyard /*
1560f310cd6SCorey Minyard * Don't worry about input overrun here, that will be
1570f310cd6SCorey Minyard * handled in the BMC.
1580f310cd6SCorey Minyard */
1590f310cd6SCorey Minyard if (ik->inlen < sizeof(ik->inmsg)) {
1600f310cd6SCorey Minyard ik->inmsg[ik->inlen] = ik->data_in_reg;
1610f310cd6SCorey Minyard }
1620f310cd6SCorey Minyard ik->inlen++;
1630f310cd6SCorey Minyard }
1640f310cd6SCorey Minyard if (ik->write_end) {
1650f310cd6SCorey Minyard IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ik->bmc);
1660f310cd6SCorey Minyard ik->outlen = 0;
1670f310cd6SCorey Minyard ik->write_end = 0;
1680f310cd6SCorey Minyard ik->outpos = 0;
1690f310cd6SCorey Minyard bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg),
1700f310cd6SCorey Minyard ik->waiting_rsp);
171*abb55b1aSMarkus Armbruster return;
1720f310cd6SCorey Minyard } else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) {
1730f310cd6SCorey Minyard ik->cmd_reg = -1;
1740f310cd6SCorey Minyard ik->write_end = 1;
1750f310cd6SCorey Minyard }
1760f310cd6SCorey Minyard SET_OBF();
1770f310cd6SCorey Minyard break;
1780f310cd6SCorey Minyard
1790f310cd6SCorey Minyard case IPMI_KCS_ERROR_STATE:
1800f310cd6SCorey Minyard if (ik->data_in_reg != -1) {
1810f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
1820f310cd6SCorey Minyard ik->data_in_reg = IPMI_KCS_READ_CMD;
1830f310cd6SCorey Minyard goto handle_read;
1840f310cd6SCorey Minyard }
1850f310cd6SCorey Minyard break;
1860f310cd6SCorey Minyard }
1870f310cd6SCorey Minyard
1880f310cd6SCorey Minyard if (ik->cmd_reg != -1) {
1890f310cd6SCorey Minyard /* Got an invalid command */
1900f310cd6SCorey Minyard ik->outmsg[0] = IPMI_KCS_STATUS_BAD_CC_ERR;
1910f310cd6SCorey Minyard ik->outlen = 1;
1920f310cd6SCorey Minyard ik->outpos = 0;
1930f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_ERROR_STATE);
1940f310cd6SCorey Minyard }
1950f310cd6SCorey Minyard
1960f310cd6SCorey Minyard out:
1970f310cd6SCorey Minyard ik->cmd_reg = -1;
1980f310cd6SCorey Minyard ik->data_in_reg = -1;
1990f310cd6SCorey Minyard IPMI_KCS_SET_IBF(ik->status_reg, 0);
2000f310cd6SCorey Minyard }
2010f310cd6SCorey Minyard
ipmi_kcs_handle_rsp(IPMIInterface * ii,uint8_t msg_id,unsigned char * rsp,unsigned int rsp_len)2020f310cd6SCorey Minyard static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
2030f310cd6SCorey Minyard unsigned char *rsp, unsigned int rsp_len)
2040f310cd6SCorey Minyard {
2050f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
2060f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii);
2070f310cd6SCorey Minyard
2080f310cd6SCorey Minyard if (ik->waiting_rsp == msg_id) {
2090f310cd6SCorey Minyard ik->waiting_rsp++;
2100f310cd6SCorey Minyard if (rsp_len > sizeof(ik->outmsg)) {
2110f310cd6SCorey Minyard ik->outmsg[0] = rsp[0];
2120f310cd6SCorey Minyard ik->outmsg[1] = rsp[1];
2130f310cd6SCorey Minyard ik->outmsg[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
2140f310cd6SCorey Minyard ik->outlen = 3;
2150f310cd6SCorey Minyard } else {
2160f310cd6SCorey Minyard memcpy(ik->outmsg, rsp, rsp_len);
2170f310cd6SCorey Minyard ik->outlen = rsp_len;
2180f310cd6SCorey Minyard }
2190f310cd6SCorey Minyard IPMI_KCS_SET_STATE(ik->status_reg, IPMI_KCS_READ_STATE);
2200f310cd6SCorey Minyard ik->data_in_reg = IPMI_KCS_READ_CMD;
2210f310cd6SCorey Minyard ipmi_kcs_signal(ik, ii);
2220f310cd6SCorey Minyard }
2230f310cd6SCorey Minyard }
2240f310cd6SCorey Minyard
2250f310cd6SCorey Minyard
ipmi_kcs_ioport_read(void * opaque,hwaddr addr,unsigned size)2260f310cd6SCorey Minyard static uint64_t ipmi_kcs_ioport_read(void *opaque, hwaddr addr, unsigned size)
2270f310cd6SCorey Minyard {
2280f310cd6SCorey Minyard IPMIInterface *ii = opaque;
2290f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
2300f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii);
2310f310cd6SCorey Minyard uint32_t ret;
2320f310cd6SCorey Minyard
23379d29a9dSCorey Minyard switch (addr & ik->size_mask) {
2340f310cd6SCorey Minyard case 0:
2350f310cd6SCorey Minyard ret = ik->data_out_reg;
2360f310cd6SCorey Minyard IPMI_KCS_SET_OBF(ik->status_reg, 0);
2370f310cd6SCorey Minyard if (ik->obf_irq_set) {
2380f310cd6SCorey Minyard ik->obf_irq_set = 0;
2390f310cd6SCorey Minyard if (!ik->atn_irq_set) {
2400f310cd6SCorey Minyard ipmi_kcs_lower_irq(ik);
2410f310cd6SCorey Minyard }
2420f310cd6SCorey Minyard }
2430f310cd6SCorey Minyard break;
24479d29a9dSCorey Minyard
2450f310cd6SCorey Minyard case 1:
2460f310cd6SCorey Minyard ret = ik->status_reg;
2470f310cd6SCorey Minyard if (ik->atn_irq_set) {
2480f310cd6SCorey Minyard ik->atn_irq_set = 0;
2490f310cd6SCorey Minyard if (!ik->obf_irq_set) {
2500f310cd6SCorey Minyard ipmi_kcs_lower_irq(ik);
2510f310cd6SCorey Minyard }
2520f310cd6SCorey Minyard }
2530f310cd6SCorey Minyard break;
25479d29a9dSCorey Minyard
25579d29a9dSCorey Minyard default:
25679d29a9dSCorey Minyard ret = 0xff;
2570f310cd6SCorey Minyard }
2580f310cd6SCorey Minyard return ret;
2590f310cd6SCorey Minyard }
2600f310cd6SCorey Minyard
ipmi_kcs_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)2610f310cd6SCorey Minyard static void ipmi_kcs_ioport_write(void *opaque, hwaddr addr, uint64_t val,
2620f310cd6SCorey Minyard unsigned size)
2630f310cd6SCorey Minyard {
2640f310cd6SCorey Minyard IPMIInterface *ii = opaque;
2650f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
2660f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii);
2670f310cd6SCorey Minyard
2680f310cd6SCorey Minyard if (IPMI_KCS_GET_IBF(ik->status_reg)) {
2690f310cd6SCorey Minyard return;
2700f310cd6SCorey Minyard }
2710f310cd6SCorey Minyard
27279d29a9dSCorey Minyard switch (addr & ik->size_mask) {
2730f310cd6SCorey Minyard case 0:
2740f310cd6SCorey Minyard ik->data_in_reg = val;
2750f310cd6SCorey Minyard break;
2760f310cd6SCorey Minyard
2770f310cd6SCorey Minyard case 1:
2780f310cd6SCorey Minyard ik->cmd_reg = val;
2790f310cd6SCorey Minyard break;
28079d29a9dSCorey Minyard
28179d29a9dSCorey Minyard default:
28279d29a9dSCorey Minyard /* Ignore. */
28379d29a9dSCorey Minyard break;
2840f310cd6SCorey Minyard }
2850f310cd6SCorey Minyard IPMI_KCS_SET_IBF(ik->status_reg, 1);
2860f310cd6SCorey Minyard ipmi_kcs_signal(ik, ii);
2870f310cd6SCorey Minyard }
2880f310cd6SCorey Minyard
2890f310cd6SCorey Minyard const MemoryRegionOps ipmi_kcs_io_ops = {
2900f310cd6SCorey Minyard .read = ipmi_kcs_ioport_read,
2910f310cd6SCorey Minyard .write = ipmi_kcs_ioport_write,
2920f310cd6SCorey Minyard .impl = {
2930f310cd6SCorey Minyard .min_access_size = 1,
2940f310cd6SCorey Minyard .max_access_size = 1,
2950f310cd6SCorey Minyard },
2960f310cd6SCorey Minyard .endianness = DEVICE_LITTLE_ENDIAN,
2970f310cd6SCorey Minyard };
2980f310cd6SCorey Minyard
ipmi_kcs_set_atn(IPMIInterface * ii,int val,int irq)2990f310cd6SCorey Minyard static void ipmi_kcs_set_atn(IPMIInterface *ii, int val, int irq)
3000f310cd6SCorey Minyard {
3010f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
3020f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii);
3030f310cd6SCorey Minyard
3040f310cd6SCorey Minyard IPMI_KCS_SET_SMS_ATN(ik->status_reg, val);
3050f310cd6SCorey Minyard if (val) {
3060f310cd6SCorey Minyard if (irq && !ik->atn_irq_set) {
3070f310cd6SCorey Minyard ik->atn_irq_set = 1;
3080f310cd6SCorey Minyard if (!ik->obf_irq_set) {
3090f310cd6SCorey Minyard ipmi_kcs_raise_irq(ik);
3100f310cd6SCorey Minyard }
3110f310cd6SCorey Minyard }
3120f310cd6SCorey Minyard } else {
3130f310cd6SCorey Minyard if (ik->atn_irq_set) {
3140f310cd6SCorey Minyard ik->atn_irq_set = 0;
3150f310cd6SCorey Minyard if (!ik->obf_irq_set) {
3160f310cd6SCorey Minyard ipmi_kcs_lower_irq(ik);
3170f310cd6SCorey Minyard }
3180f310cd6SCorey Minyard }
3190f310cd6SCorey Minyard }
3200f310cd6SCorey Minyard }
3210f310cd6SCorey Minyard
ipmi_kcs_set_irq_enable(IPMIInterface * ii,int val)3220f310cd6SCorey Minyard static void ipmi_kcs_set_irq_enable(IPMIInterface *ii, int val)
3230f310cd6SCorey Minyard {
3240f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
3250f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii);
3260f310cd6SCorey Minyard
3270f310cd6SCorey Minyard ik->irqs_enabled = val;
3280f310cd6SCorey Minyard }
3290f310cd6SCorey Minyard
33079d29a9dSCorey Minyard /* min_size must be a power of 2. */
ipmi_kcs_init(IPMIInterface * ii,unsigned int min_size,Error ** errp)33179d29a9dSCorey Minyard static void ipmi_kcs_init(IPMIInterface *ii, unsigned int min_size,
33279d29a9dSCorey Minyard Error **errp)
3330f310cd6SCorey Minyard {
3340f310cd6SCorey Minyard IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
3350f310cd6SCorey Minyard IPMIKCS *ik = iic->get_backend_data(ii);
3360f310cd6SCorey Minyard
33779d29a9dSCorey Minyard if (min_size == 0) {
33879d29a9dSCorey Minyard min_size = 2;
33979d29a9dSCorey Minyard }
34079d29a9dSCorey Minyard ik->size_mask = min_size - 1;
3410f310cd6SCorey Minyard ik->io_length = 2;
34279d29a9dSCorey Minyard memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs",
34379d29a9dSCorey Minyard min_size);
3440f310cd6SCorey Minyard }
3450f310cd6SCorey Minyard
ipmi_kcs_vmstate_post_load(void * opaque,int version)3460f310cd6SCorey Minyard int ipmi_kcs_vmstate_post_load(void *opaque, int version)
3470f310cd6SCorey Minyard {
3480f310cd6SCorey Minyard IPMIKCS *ik = opaque;
3490f310cd6SCorey Minyard
3500f310cd6SCorey Minyard /* Make sure all the values are sane. */
3510f310cd6SCorey Minyard if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE ||
3520f310cd6SCorey Minyard ik->outpos >= ik->outlen) {
3530f310cd6SCorey Minyard qemu_log_mask(LOG_GUEST_ERROR,
3540f310cd6SCorey Minyard "ipmi:kcs: vmstate transfer received bad out values: %d %d\n",
3550f310cd6SCorey Minyard ik->outpos, ik->outlen);
3560f310cd6SCorey Minyard ik->outpos = 0;
3570f310cd6SCorey Minyard ik->outlen = 0;
3580f310cd6SCorey Minyard }
3590f310cd6SCorey Minyard
3600f310cd6SCorey Minyard if (ik->inlen >= MAX_IPMI_MSG_SIZE) {
3610f310cd6SCorey Minyard qemu_log_mask(LOG_GUEST_ERROR,
3620f310cd6SCorey Minyard "ipmi:kcs: vmstate transfer received bad in value: %d\n",
3630f310cd6SCorey Minyard ik->inlen);
3640f310cd6SCorey Minyard ik->inlen = 0;
3650f310cd6SCorey Minyard }
3660f310cd6SCorey Minyard
3670f310cd6SCorey Minyard return 0;
3680f310cd6SCorey Minyard }
3690f310cd6SCorey Minyard
vmstate_kcs_before_version2(void * opaque,int version)3700f310cd6SCorey Minyard static bool vmstate_kcs_before_version2(void *opaque, int version)
3710f310cd6SCorey Minyard {
3720f310cd6SCorey Minyard return version <= 1;
3730f310cd6SCorey Minyard }
3740f310cd6SCorey Minyard
3750f310cd6SCorey Minyard const VMStateDescription vmstate_IPMIKCS = {
3760f310cd6SCorey Minyard .name = TYPE_IPMI_INTERFACE_PREFIX "kcs",
3770f310cd6SCorey Minyard .version_id = 2,
3780f310cd6SCorey Minyard .minimum_version_id = 1,
3790f310cd6SCorey Minyard .post_load = ipmi_kcs_vmstate_post_load,
38009c6ac6dSRichard Henderson .fields = (const VMStateField[]) {
3810f310cd6SCorey Minyard VMSTATE_BOOL(obf_irq_set, IPMIKCS),
3820f310cd6SCorey Minyard VMSTATE_BOOL(atn_irq_set, IPMIKCS),
3830f310cd6SCorey Minyard VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */
3840f310cd6SCorey Minyard VMSTATE_BOOL(irqs_enabled, IPMIKCS),
3850f310cd6SCorey Minyard VMSTATE_UINT32(outpos, IPMIKCS),
3860f310cd6SCorey Minyard VMSTATE_UINT32_V(outlen, IPMIKCS, 2),
3870f310cd6SCorey Minyard VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
3880f310cd6SCorey Minyard VMSTATE_UINT32_V(inlen, IPMIKCS, 2),
3890f310cd6SCorey Minyard VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
3900f310cd6SCorey Minyard VMSTATE_BOOL(write_end, IPMIKCS),
3910f310cd6SCorey Minyard VMSTATE_UINT8(status_reg, IPMIKCS),
3920f310cd6SCorey Minyard VMSTATE_UINT8(data_out_reg, IPMIKCS),
3930f310cd6SCorey Minyard VMSTATE_INT16(data_in_reg, IPMIKCS),
3940f310cd6SCorey Minyard VMSTATE_INT16(cmd_reg, IPMIKCS),
3950f310cd6SCorey Minyard VMSTATE_UINT8(waiting_rsp, IPMIKCS),
3960f310cd6SCorey Minyard VMSTATE_END_OF_LIST()
3970f310cd6SCorey Minyard }
3980f310cd6SCorey Minyard };
3990f310cd6SCorey Minyard
ipmi_kcs_get_fwinfo(IPMIKCS * ik,IPMIFwInfo * info)4000f310cd6SCorey Minyard void ipmi_kcs_get_fwinfo(IPMIKCS *ik, IPMIFwInfo *info)
4010f310cd6SCorey Minyard {
4020f310cd6SCorey Minyard info->interface_name = "kcs";
4030f310cd6SCorey Minyard info->interface_type = IPMI_SMBIOS_KCS;
4040f310cd6SCorey Minyard info->ipmi_spec_major_revision = 2;
4050f310cd6SCorey Minyard info->ipmi_spec_minor_revision = 0;
4067f9e7af4SNicholas Piggin info->ipmi_channel_protocol = IPMI_CHANNEL_PROTOCOL_KCS;
4070f310cd6SCorey Minyard info->base_address = ik->io_base;
4080f310cd6SCorey Minyard info->i2c_slave_address = ik->bmc->slave_addr;
4090f310cd6SCorey Minyard info->register_length = ik->io_length;
4100f310cd6SCorey Minyard info->register_spacing = 1;
4110f310cd6SCorey Minyard info->memspace = IPMI_MEMSPACE_IO;
4120f310cd6SCorey Minyard info->irq_type = IPMI_LEVEL_IRQ;
4130f310cd6SCorey Minyard }
4140f310cd6SCorey Minyard
ipmi_kcs_class_init(IPMIInterfaceClass * iic)4150f310cd6SCorey Minyard void ipmi_kcs_class_init(IPMIInterfaceClass *iic)
4160f310cd6SCorey Minyard {
4170f310cd6SCorey Minyard iic->init = ipmi_kcs_init;
4180f310cd6SCorey Minyard iic->set_atn = ipmi_kcs_set_atn;
4190f310cd6SCorey Minyard iic->handle_rsp = ipmi_kcs_handle_rsp;
4200f310cd6SCorey Minyard iic->handle_if_event = ipmi_kcs_handle_event;
4210f310cd6SCorey Minyard iic->set_irq_enable = ipmi_kcs_set_irq_enable;
4220f310cd6SCorey Minyard }
423