]> git.proxmox.com Git - mirror_qemu.git/blame - hw/misc/aspeed_peci.c
hw/nvme: check maximum copy length (MCL) for COPY
[mirror_qemu.git] / hw / misc / aspeed_peci.c
CommitLineData
55c57023
PD
1/*
2 * Aspeed PECI Controller
3 *
4 * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
5 *
6 * This code is licensed under the GPL version 2 or later. See the COPYING
7 * file in the top-level directory.
8 */
9
10#include "qemu/osdep.h"
11#include "qemu/log.h"
12#include "hw/irq.h"
13#include "hw/misc/aspeed_peci.h"
14#include "hw/registerfields.h"
15#include "trace.h"
16
17#define ASPEED_PECI_CC_RSP_SUCCESS (0x40U)
18
19/* Command Register */
20REG32(PECI_CMD, 0x08)
21 FIELD(PECI_CMD, FIRE, 0, 1)
22
23/* Interrupt Control Register */
24REG32(PECI_INT_CTRL, 0x18)
25
26/* Interrupt Status Register */
27REG32(PECI_INT_STS, 0x1C)
28 FIELD(PECI_INT_STS, CMD_DONE, 0, 1)
29
30/* Rx/Tx Data Buffer Registers */
31REG32(PECI_WR_DATA0, 0x20)
32REG32(PECI_RD_DATA0, 0x30)
33
34static void aspeed_peci_raise_interrupt(AspeedPECIState *s, uint32_t status)
35{
36 trace_aspeed_peci_raise_interrupt(s->regs[R_PECI_INT_CTRL], status);
37
38 s->regs[R_PECI_INT_STS] = s->regs[R_PECI_INT_CTRL] & status;
39 if (!s->regs[R_PECI_INT_STS]) {
40 return;
41 }
42 qemu_irq_raise(s->irq);
43}
44
45static uint64_t aspeed_peci_read(void *opaque, hwaddr offset, unsigned size)
46{
47 AspeedPECIState *s = ASPEED_PECI(opaque);
48 uint64_t data;
49
50 if (offset >= ASPEED_PECI_NR_REGS << 2) {
51 qemu_log_mask(LOG_GUEST_ERROR,
52 "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
53 __func__, offset);
54 return 0;
55 }
56 data = s->regs[offset >> 2];
57
58 trace_aspeed_peci_read(offset, data);
59 return data;
60}
61
62static void aspeed_peci_write(void *opaque, hwaddr offset, uint64_t data,
63 unsigned size)
64{
65 AspeedPECIState *s = ASPEED_PECI(opaque);
66
67 trace_aspeed_peci_write(offset, data);
68
69 if (offset >= ASPEED_PECI_NR_REGS << 2) {
70 qemu_log_mask(LOG_GUEST_ERROR,
71 "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
72 __func__, offset);
73 return;
74 }
75
76 switch (offset) {
77 case A_PECI_INT_STS:
78 s->regs[R_PECI_INT_STS] &= ~data;
79 if (!s->regs[R_PECI_INT_STS]) {
80 qemu_irq_lower(s->irq);
81 }
82 break;
83 case A_PECI_CMD:
84 /*
85 * Only the FIRE bit is writable. Once the command is complete, it
86 * should be cleared. Since we complete the command immediately, the
87 * value is not stored in the register array.
88 */
89 if (!FIELD_EX32(data, PECI_CMD, FIRE)) {
90 break;
91 }
92 if (s->regs[R_PECI_INT_STS]) {
93 qemu_log_mask(LOG_GUEST_ERROR, "%s: Interrupt status must be "
94 "cleared before firing another command: 0x%08x\n",
95 __func__, s->regs[R_PECI_INT_STS]);
96 break;
97 }
98 s->regs[R_PECI_RD_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
99 s->regs[R_PECI_WR_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
100 aspeed_peci_raise_interrupt(s,
101 FIELD_DP32(0, PECI_INT_STS, CMD_DONE, 1));
102 break;
103 default:
104 s->regs[offset / sizeof(s->regs[0])] = data;
105 break;
106 }
107}
108
109static const MemoryRegionOps aspeed_peci_ops = {
110 .read = aspeed_peci_read,
111 .write = aspeed_peci_write,
112 .endianness = DEVICE_LITTLE_ENDIAN,
113};
114
115static void aspeed_peci_realize(DeviceState *dev, Error **errp)
116{
117 AspeedPECIState *s = ASPEED_PECI(dev);
118 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
119
120 memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_peci_ops, s,
121 TYPE_ASPEED_PECI, 0x1000);
122 sysbus_init_mmio(sbd, &s->mmio);
123 sysbus_init_irq(sbd, &s->irq);
124}
125
126static void aspeed_peci_reset(DeviceState *dev)
127{
128 AspeedPECIState *s = ASPEED_PECI(dev);
129
130 memset(s->regs, 0, sizeof(s->regs));
131}
132
133static void aspeed_peci_class_init(ObjectClass *klass, void *data)
134{
135 DeviceClass *dc = DEVICE_CLASS(klass);
136
137 dc->realize = aspeed_peci_realize;
138 dc->reset = aspeed_peci_reset;
139 dc->desc = "Aspeed PECI Controller";
140}
141
142static const TypeInfo aspeed_peci_types[] = {
143 {
144 .name = TYPE_ASPEED_PECI,
145 .parent = TYPE_SYS_BUS_DEVICE,
146 .instance_size = sizeof(AspeedPECIState),
147 .class_init = aspeed_peci_class_init,
148 .abstract = false,
149 },
150};
151
152DEFINE_TYPES(aspeed_peci_types);