]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ppc/pnv_sbe.c
bulk: Remove pointless QOM casts
[mirror_qemu.git] / hw / ppc / pnv_sbe.c
CommitLineData
0bf4d77e
NP
1/*
2 * QEMU PowerPC PowerNV Emulation of some SBE behaviour
3 *
4 * Copyright (c) 2022, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "qemu/osdep.h"
20#include "target/ppc/cpu.h"
21#include "qapi/error.h"
22#include "qemu/log.h"
23#include "qemu/module.h"
24#include "hw/irq.h"
25#include "hw/qdev-properties.h"
26#include "hw/ppc/pnv.h"
27#include "hw/ppc/pnv_xscom.h"
28#include "hw/ppc/pnv_sbe.h"
29#include "trace.h"
30
31/*
32 * Most register and command definitions come from skiboot.
33 *
34 * xscom addresses are adjusted to be relative to xscom subregion bases
35 */
36
37/*
38 * SBE MBOX register address
39 * Reg 0 - 3 : Host to send command packets to SBE
40 * Reg 4 - 7 : SBE to send response packets to Host
41 */
42#define PSU_HOST_SBE_MBOX_REG0 0x00000000
43#define PSU_HOST_SBE_MBOX_REG1 0x00000001
44#define PSU_HOST_SBE_MBOX_REG2 0x00000002
45#define PSU_HOST_SBE_MBOX_REG3 0x00000003
46#define PSU_HOST_SBE_MBOX_REG4 0x00000004
47#define PSU_HOST_SBE_MBOX_REG5 0x00000005
48#define PSU_HOST_SBE_MBOX_REG6 0x00000006
49#define PSU_HOST_SBE_MBOX_REG7 0x00000007
50#define PSU_SBE_DOORBELL_REG_RW 0x00000010
51#define PSU_SBE_DOORBELL_REG_AND 0x00000011
52#define PSU_SBE_DOORBELL_REG_OR 0x00000012
53#define PSU_HOST_DOORBELL_REG_RW 0x00000013
54#define PSU_HOST_DOORBELL_REG_AND 0x00000014
55#define PSU_HOST_DOORBELL_REG_OR 0x00000015
56
57/*
58 * Doorbell register to trigger SBE interrupt. Set by OPAL to inform
59 * the SBE about a waiting message in the Host/SBE mailbox registers
60 */
61#define HOST_SBE_MSG_WAITING PPC_BIT(0)
62
63/*
64 * Doorbell register for host bridge interrupt. Set by the SBE to inform
65 * host about a response message in the Host/SBE mailbox registers
66 */
67#define SBE_HOST_RESPONSE_WAITING PPC_BIT(0)
68#define SBE_HOST_MSG_READ PPC_BIT(1)
69#define SBE_HOST_STOP15_EXIT PPC_BIT(2)
70#define SBE_HOST_RESET PPC_BIT(3)
71#define SBE_HOST_PASSTHROUGH PPC_BIT(4)
72#define SBE_HOST_TIMER_EXPIRY PPC_BIT(14)
73#define SBE_HOST_RESPONSE_MASK (PPC_BITMASK(0, 4) | \
74 SBE_HOST_TIMER_EXPIRY)
75
76/* SBE Control Register */
77#define SBE_CONTROL_REG_RW 0x00000000
78
79/* SBE interrupt s0/s1 bits */
80#define SBE_CONTROL_REG_S0 PPC_BIT(14)
81#define SBE_CONTROL_REG_S1 PPC_BIT(15)
82
83struct sbe_msg {
84 uint64_t reg[4];
85};
86
87static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque, hwaddr addr,
88 unsigned size)
89{
90 uint32_t offset = addr >> 3;
91 uint64_t val = 0;
92
93 switch (offset) {
94 default:
95 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
96 HWADDR_PRIx "\n", addr >> 3);
97 }
98
99 trace_pnv_sbe_xscom_ctrl_read(addr, val);
100
101 return val;
102}
103
104static void pnv_sbe_power9_xscom_ctrl_write(void *opaque, hwaddr addr,
105 uint64_t val, unsigned size)
106{
107 uint32_t offset = addr >> 3;
108
109 trace_pnv_sbe_xscom_ctrl_write(addr, val);
110
111 switch (offset) {
112 default:
113 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
114 HWADDR_PRIx "\n", addr >> 3);
115 }
116}
117
118static const MemoryRegionOps pnv_sbe_power9_xscom_ctrl_ops = {
119 .read = pnv_sbe_power9_xscom_ctrl_read,
120 .write = pnv_sbe_power9_xscom_ctrl_write,
121 .valid.min_access_size = 8,
122 .valid.max_access_size = 8,
123 .impl.min_access_size = 8,
124 .impl.max_access_size = 8,
125 .endianness = DEVICE_BIG_ENDIAN,
126};
127
128static void pnv_sbe_set_host_doorbell(PnvSBE *sbe, uint64_t val)
129{
130 val &= SBE_HOST_RESPONSE_MASK; /* Is this right? What does HW do? */
131 sbe->host_doorbell = val;
132
133 trace_pnv_sbe_reg_set_host_doorbell(val);
134 qemu_set_irq(sbe->psi_irq, !!val);
135}
136
137/* SBE Target Type */
138#define SBE_TARGET_TYPE_PROC 0x00
139#define SBE_TARGET_TYPE_EX 0x01
140#define SBE_TARGET_TYPE_PERV 0x02
141#define SBE_TARGET_TYPE_MCS 0x03
142#define SBE_TARGET_TYPE_EQ 0x04
143#define SBE_TARGET_TYPE_CORE 0x05
144
145/* SBE MBOX command class */
146#define SBE_MCLASS_FIRST 0xD1
147#define SBE_MCLASS_CORE_STATE 0xD1
148#define SBE_MCLASS_SCOM 0xD2
149#define SBE_MCLASS_RING 0xD3
150#define SBE_MCLASS_TIMER 0xD4
151#define SBE_MCLASS_MPIPL 0xD5
152#define SBE_MCLASS_SECURITY 0xD6
153#define SBE_MCLASS_GENERIC 0xD7
154#define SBE_MCLASS_LAST 0xD7
155
156/*
157 * Commands are provided in xxyy form where:
158 * - xx : command class
159 * - yy : command
160 *
161 * Both request and response message uses same seq ID,
162 * command class and command.
163 */
164#define SBE_CMD_CTRL_DEADMAN_LOOP 0xD101
165#define SBE_CMD_MULTI_SCOM 0xD201
166#define SBE_CMD_PUT_RING_FORM_IMAGE 0xD301
167#define SBE_CMD_CONTROL_TIMER 0xD401
168#define SBE_CMD_GET_ARCHITECTED_REG 0xD501
169#define SBE_CMD_CLR_ARCHITECTED_REG 0xD502
170#define SBE_CMD_SET_UNSEC_MEM_WINDOW 0xD601
171#define SBE_CMD_GET_SBE_FFDC 0xD701
172#define SBE_CMD_GET_CAPABILITY 0xD702
173#define SBE_CMD_READ_SBE_SEEPROM 0xD703
174#define SBE_CMD_SET_FFDC_ADDR 0xD704
175#define SBE_CMD_QUIESCE_SBE 0xD705
176#define SBE_CMD_SET_FABRIC_ID_MAP 0xD706
177#define SBE_CMD_STASH_MPIPL_CONFIG 0xD707
178
179/* SBE MBOX control flags */
180
181/* Generic flags */
182#define SBE_CMD_CTRL_RESP_REQ 0x0100
183#define SBE_CMD_CTRL_ACK_REQ 0x0200
184
185/* Deadman loop */
186#define CTRL_DEADMAN_LOOP_START 0x0001
187#define CTRL_DEADMAN_LOOP_STOP 0x0002
188
189/* Control timer */
190#define CONTROL_TIMER_START 0x0001
191#define CONTROL_TIMER_STOP 0x0002
192
193/* Stash MPIPL config */
194#define SBE_STASH_KEY_SKIBOOT_BASE 0x03
195
196static void sbe_timer(void *opaque)
197{
198 PnvSBE *sbe = opaque;
199
200 trace_pnv_sbe_cmd_timer_expired();
201
202 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_TIMER_EXPIRY);
203}
204
205static void do_sbe_msg(PnvSBE *sbe)
206{
207 struct sbe_msg msg;
208 uint16_t cmd, ctrl_flags, seq_id;
209 int i;
210
211 memset(&msg, 0, sizeof(msg));
212
213 for (i = 0; i < 4; i++) {
214 msg.reg[i] = sbe->mbox[i];
215 }
216
217 cmd = msg.reg[0];
218 seq_id = msg.reg[0] >> 16;
219 ctrl_flags = msg.reg[0] >> 32;
220
221 trace_pnv_sbe_msg_recv(cmd, seq_id, ctrl_flags);
222
223 if (ctrl_flags & SBE_CMD_CTRL_ACK_REQ) {
224 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_MSG_READ);
225 }
226
227 switch (cmd) {
228 case SBE_CMD_CONTROL_TIMER:
229 if (ctrl_flags & CONTROL_TIMER_START) {
230 uint64_t us = msg.reg[1];
231 trace_pnv_sbe_cmd_timer_start(us);
232 timer_mod(sbe->timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + us);
233 }
234 if (ctrl_flags & CONTROL_TIMER_STOP) {
235 trace_pnv_sbe_cmd_timer_stop();
236 timer_del(sbe->timer);
237 }
238 break;
239 default:
240 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented command: 0x%x\n", cmd);
241 }
242}
243
244static void pnv_sbe_set_sbe_doorbell(PnvSBE *sbe, uint64_t val)
245{
246 val &= HOST_SBE_MSG_WAITING;
247 sbe->sbe_doorbell = val;
248
249 if (val & HOST_SBE_MSG_WAITING) {
250 sbe->sbe_doorbell &= ~HOST_SBE_MSG_WAITING;
251 do_sbe_msg(sbe);
252 }
253}
254
255static uint64_t pnv_sbe_power9_xscom_mbox_read(void *opaque, hwaddr addr,
256 unsigned size)
257{
258 PnvSBE *sbe = PNV_SBE(opaque);
259 uint32_t offset = addr >> 3;
260 uint64_t val = 0;
261
262 if (offset <= PSU_HOST_SBE_MBOX_REG7) {
263 uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
264 val = sbe->mbox[idx];
265 } else {
266 switch (offset) {
267 case PSU_SBE_DOORBELL_REG_RW:
268 val = sbe->sbe_doorbell;
269 break;
270 case PSU_HOST_DOORBELL_REG_RW:
271 val = sbe->host_doorbell;
272 break;
273 default:
274 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
275 HWADDR_PRIx "\n", addr >> 3);
276 }
277 }
278
279 trace_pnv_sbe_xscom_mbox_read(addr, val);
280
281 return val;
282}
283
284static void pnv_sbe_power9_xscom_mbox_write(void *opaque, hwaddr addr,
285 uint64_t val, unsigned size)
286{
287 PnvSBE *sbe = PNV_SBE(opaque);
288 uint32_t offset = addr >> 3;
289
290 trace_pnv_sbe_xscom_mbox_write(addr, val);
291
292 if (offset <= PSU_HOST_SBE_MBOX_REG7) {
293 uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
294 sbe->mbox[idx] = val;
295 } else {
296 switch (offset) {
297 case PSU_SBE_DOORBELL_REG_RW:
298 pnv_sbe_set_sbe_doorbell(sbe, val);
299 break;
300 case PSU_SBE_DOORBELL_REG_AND:
301 pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell & val);
302 break;
303 case PSU_SBE_DOORBELL_REG_OR:
304 pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell | val);
305 break;
306
307 case PSU_HOST_DOORBELL_REG_RW:
308 pnv_sbe_set_host_doorbell(sbe, val);
309 break;
310 case PSU_HOST_DOORBELL_REG_AND:
311 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell & val);
312 break;
313 case PSU_HOST_DOORBELL_REG_OR:
314 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | val);
315 break;
316
317 default:
318 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
319 HWADDR_PRIx "\n", addr >> 3);
320 }
321 }
322}
323
324static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops = {
325 .read = pnv_sbe_power9_xscom_mbox_read,
326 .write = pnv_sbe_power9_xscom_mbox_write,
327 .valid.min_access_size = 8,
328 .valid.max_access_size = 8,
329 .impl.min_access_size = 8,
330 .impl.max_access_size = 8,
331 .endianness = DEVICE_BIG_ENDIAN,
332};
333
334static void pnv_sbe_power9_class_init(ObjectClass *klass, void *data)
335{
336 PnvSBEClass *psc = PNV_SBE_CLASS(klass);
337 DeviceClass *dc = DEVICE_CLASS(klass);
338
339 dc->desc = "PowerNV SBE Controller (POWER9)";
340 psc->xscom_ctrl_size = PNV9_XSCOM_SBE_CTRL_SIZE;
341 psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
342 psc->xscom_mbox_size = PNV9_XSCOM_SBE_MBOX_SIZE;
343 psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
344}
345
346static const TypeInfo pnv_sbe_power9_type_info = {
347 .name = TYPE_PNV9_SBE,
348 .parent = TYPE_PNV_SBE,
349 .instance_size = sizeof(PnvSBE),
350 .class_init = pnv_sbe_power9_class_init,
351};
352
353static void pnv_sbe_power10_class_init(ObjectClass *klass, void *data)
354{
355 PnvSBEClass *psc = PNV_SBE_CLASS(klass);
356 DeviceClass *dc = DEVICE_CLASS(klass);
357
358 dc->desc = "PowerNV SBE Controller (POWER10)";
359 psc->xscom_ctrl_size = PNV10_XSCOM_SBE_CTRL_SIZE;
360 psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
361 psc->xscom_mbox_size = PNV10_XSCOM_SBE_MBOX_SIZE;
362 psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
363}
364
365static const TypeInfo pnv_sbe_power10_type_info = {
366 .name = TYPE_PNV10_SBE,
367 .parent = TYPE_PNV9_SBE,
368 .class_init = pnv_sbe_power10_class_init,
369};
370
371static void pnv_sbe_realize(DeviceState *dev, Error **errp)
372{
373 PnvSBE *sbe = PNV_SBE(dev);
374 PnvSBEClass *psc = PNV_SBE_GET_CLASS(sbe);
375
376 /* XScom regions for SBE registers */
377 pnv_xscom_region_init(&sbe->xscom_ctrl_regs, OBJECT(dev),
378 psc->xscom_ctrl_ops, sbe, "xscom-sbe-ctrl",
379 psc->xscom_ctrl_size);
380 pnv_xscom_region_init(&sbe->xscom_mbox_regs, OBJECT(dev),
381 psc->xscom_mbox_ops, sbe, "xscom-sbe-mbox",
382 psc->xscom_mbox_size);
383
7d5b0d68 384 qdev_init_gpio_out(dev, &sbe->psi_irq, 1);
0bf4d77e
NP
385
386 sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe);
387}
388
389static void pnv_sbe_class_init(ObjectClass *klass, void *data)
390{
391 DeviceClass *dc = DEVICE_CLASS(klass);
392
393 dc->realize = pnv_sbe_realize;
394 dc->desc = "PowerNV SBE Controller";
395 dc->user_creatable = false;
396}
397
398static const TypeInfo pnv_sbe_type_info = {
399 .name = TYPE_PNV_SBE,
400 .parent = TYPE_DEVICE,
401 .instance_size = sizeof(PnvSBE),
402 .class_init = pnv_sbe_class_init,
403 .class_size = sizeof(PnvSBEClass),
404 .abstract = true,
405};
406
407static void pnv_sbe_register_types(void)
408{
409 type_register_static(&pnv_sbe_type_info);
410 type_register_static(&pnv_sbe_power9_type_info);
411 type_register_static(&pnv_sbe_power10_type_info);
412}
413
414type_init(pnv_sbe_register_types);