master
c 481 lines 15 KB
Raw
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/core/irq.h"
25 #include "hw/core/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 "hw/ppc/pnv_mpipl.h"
30 #include "system/cpus.h"
31 #include "system/runstate.h"
32 #include "trace.h"
33
34 /*
35 * Most register and command definitions come from skiboot.
36 *
37 * xscom addresses are adjusted to be relative to xscom subregion bases
38 */
39
40 /*
41 * SBE MBOX register address
42 * Reg 0 - 3 : Host to send command packets to SBE
43 * Reg 4 - 7 : SBE to send response packets to Host
44 */
45 #define PSU_HOST_SBE_MBOX_REG0 0x00000000
46 #define PSU_HOST_SBE_MBOX_REG1 0x00000001
47 #define PSU_HOST_SBE_MBOX_REG2 0x00000002
48 #define PSU_HOST_SBE_MBOX_REG3 0x00000003
49 #define PSU_HOST_SBE_MBOX_REG4 0x00000004
50 #define PSU_HOST_SBE_MBOX_REG5 0x00000005
51 #define PSU_HOST_SBE_MBOX_REG6 0x00000006
52 #define PSU_HOST_SBE_MBOX_REG7 0x00000007
53 #define PSU_SBE_DOORBELL_REG_RW 0x00000010
54 #define PSU_SBE_DOORBELL_REG_AND 0x00000011
55 #define PSU_SBE_DOORBELL_REG_OR 0x00000012
56 #define PSU_HOST_DOORBELL_REG_RW 0x00000013
57 #define PSU_HOST_DOORBELL_REG_AND 0x00000014
58 #define PSU_HOST_DOORBELL_REG_OR 0x00000015
59
60 /*
61 * Doorbell register to trigger SBE interrupt. Set by OPAL to inform
62 * the SBE about a waiting message in the Host/SBE mailbox registers
63 */
64 #define HOST_SBE_MSG_WAITING PPC_BIT(0)
65
66 /*
67 * Doorbell register for host bridge interrupt. Set by the SBE to inform
68 * host about a response message in the Host/SBE mailbox registers
69 */
70 #define SBE_HOST_RESPONSE_WAITING PPC_BIT(0)
71 #define SBE_HOST_MSG_READ PPC_BIT(1)
72 #define SBE_HOST_STOP15_EXIT PPC_BIT(2)
73 #define SBE_HOST_RESET PPC_BIT(3)
74 #define SBE_HOST_PASSTHROUGH PPC_BIT(4)
75 #define SBE_HOST_TIMER_EXPIRY PPC_BIT(14)
76 #define SBE_HOST_RESPONSE_MASK (PPC_BITMASK(0, 4) | \
77 SBE_HOST_TIMER_EXPIRY)
78
79 /* SBE Control Register */
80 #define SBE_CONTROL_REG_RW 0x00000000
81
82 /* SBE interrupt s0/s1 bits */
83 #define SBE_CONTROL_REG_S0 PPC_BIT(14)
84 #define SBE_CONTROL_REG_S1 PPC_BIT(15)
85
86 static void pnv_sbe_set_host_doorbell(PnvSBE *sbe, uint64_t val)
87 {
88 val &= SBE_HOST_RESPONSE_MASK; /* Is this right? What does HW do? */
89 sbe->host_doorbell = val;
90
91 trace_pnv_sbe_reg_set_host_doorbell(val);
92 qemu_set_irq(sbe->psi_irq, !!val);
93 }
94
95 struct sbe_msg {
96 uint64_t reg[4];
97 };
98
99 static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque, hwaddr addr,
100 unsigned size)
101 {
102 uint32_t offset = addr >> 3;
103 uint64_t val = 0;
104
105 switch (offset) {
106 default:
107 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
108 HWADDR_PRIx "\n", addr >> 3);
109 }
110
111 trace_pnv_sbe_xscom_ctrl_read(addr, val);
112
113 return val;
114 }
115
116 static void pnv_sbe_power9_xscom_ctrl_write(void *opaque, hwaddr addr,
117 uint64_t val, unsigned size)
118 {
119 PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
120 PnvSBE *sbe = opaque;
121 uint32_t offset = addr >> 3;
122
123 trace_pnv_sbe_xscom_ctrl_write(addr, val);
124
125 switch (offset) {
126 case SBE_CONTROL_REG_RW:
127 switch (val) {
128 case SBE_CONTROL_REG_S0:
129 qemu_log_mask(LOG_UNIMP, "SBE: S0 Interrupt triggered\n");
130
131 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_RESPONSE_MASK);
132
133 /* Preserve memory regions and CPU state, if MPIPL is registered */
134 do_mpipl_preserve(pnv);
135
136 /*
137 * Control may not come back here as 'do_mpipl_preserve' triggers
138 * a guest reboot
139 */
140 break;
141 case SBE_CONTROL_REG_S1:
142 qemu_log_mask(LOG_UNIMP, "SBE: S1 Interrupt triggered\n");
143 break;
144 default:
145 qemu_log_mask(LOG_UNIMP,
146 "SBE: CONTROL_REG_RW: Unknown value: Ox%."
147 HWADDR_PRIx "\n", val);
148 }
149 break;
150 default:
151 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
152 HWADDR_PRIx "\n", addr >> 3);
153 }
154 }
155
156 static const MemoryRegionOps pnv_sbe_power9_xscom_ctrl_ops = {
157 .read = pnv_sbe_power9_xscom_ctrl_read,
158 .write = pnv_sbe_power9_xscom_ctrl_write,
159 .valid.min_access_size = 8,
160 .valid.max_access_size = 8,
161 .impl.min_access_size = 8,
162 .impl.max_access_size = 8,
163 .endianness = DEVICE_BIG_ENDIAN,
164 };
165
166 /* SBE Target Type */
167 #define SBE_TARGET_TYPE_PROC 0x00
168 #define SBE_TARGET_TYPE_EX 0x01
169 #define SBE_TARGET_TYPE_PERV 0x02
170 #define SBE_TARGET_TYPE_MCS 0x03
171 #define SBE_TARGET_TYPE_EQ 0x04
172 #define SBE_TARGET_TYPE_CORE 0x05
173
174 /* SBE MBOX command class */
175 #define SBE_MCLASS_FIRST 0xD1
176 #define SBE_MCLASS_CORE_STATE 0xD1
177 #define SBE_MCLASS_SCOM 0xD2
178 #define SBE_MCLASS_RING 0xD3
179 #define SBE_MCLASS_TIMER 0xD4
180 #define SBE_MCLASS_MPIPL 0xD5
181 #define SBE_MCLASS_SECURITY 0xD6
182 #define SBE_MCLASS_GENERIC 0xD7
183 #define SBE_MCLASS_LAST 0xD7
184
185 /*
186 * Commands are provided in xxyy form where:
187 * - xx : command class
188 * - yy : command
189 *
190 * Both request and response message uses same seq ID,
191 * command class and command.
192 */
193 #define SBE_CMD_CTRL_DEADMAN_LOOP 0xD101
194 #define SBE_CMD_MULTI_SCOM 0xD201
195 #define SBE_CMD_PUT_RING_FORM_IMAGE 0xD301
196 #define SBE_CMD_CONTROL_TIMER 0xD401
197 #define SBE_CMD_GET_ARCHITECTED_REG 0xD501
198 #define SBE_CMD_CLR_ARCHITECTED_REG 0xD502
199 #define SBE_CMD_SET_UNSEC_MEM_WINDOW 0xD601
200 #define SBE_CMD_GET_SBE_FFDC 0xD701
201 #define SBE_CMD_GET_CAPABILITY 0xD702
202 #define SBE_CMD_READ_SBE_SEEPROM 0xD703
203 #define SBE_CMD_SET_FFDC_ADDR 0xD704
204 #define SBE_CMD_QUIESCE_SBE 0xD705
205 #define SBE_CMD_SET_FABRIC_ID_MAP 0xD706
206 #define SBE_CMD_STASH_MPIPL_CONFIG 0xD707
207
208 /* SBE MBOX control flags */
209
210 /* Generic flags */
211 #define SBE_CMD_CTRL_RESP_REQ 0x0100
212 #define SBE_CMD_CTRL_ACK_REQ 0x0200
213
214 /* Deadman loop */
215 #define CTRL_DEADMAN_LOOP_START 0x0001
216 #define CTRL_DEADMAN_LOOP_STOP 0x0002
217
218 /* Control timer */
219 #define CONTROL_TIMER_START 0x0001
220 #define CONTROL_TIMER_STOP 0x0002
221
222 /* Stash MPIPL config */
223 #define SBE_STASH_KEY_SKIBOOT_BASE 0x03
224
225 static void sbe_timer(void *opaque)
226 {
227 PnvSBE *sbe = opaque;
228
229 trace_pnv_sbe_cmd_timer_expired();
230
231 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_TIMER_EXPIRY);
232 }
233
234 static void do_sbe_msg(PnvSBE *sbe)
235 {
236 PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
237 MachineState *machine = MACHINE(pnv);
238 struct sbe_msg msg;
239 uint16_t cmd, ctrl_flags, seq_id;
240 uint64_t mbox_val;
241 int i;
242
243 memset(&msg, 0, sizeof(msg));
244
245 for (i = 0; i < 4; i++) {
246 msg.reg[i] = sbe->mbox[i];
247 }
248
249 cmd = msg.reg[0];
250 seq_id = msg.reg[0] >> 16;
251 ctrl_flags = msg.reg[0] >> 32;
252
253 trace_pnv_sbe_msg_recv(cmd, seq_id, ctrl_flags);
254
255 if (ctrl_flags & SBE_CMD_CTRL_ACK_REQ) {
256 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_MSG_READ);
257 }
258
259 switch (cmd) {
260 case SBE_CMD_CONTROL_TIMER:
261 if (ctrl_flags & CONTROL_TIMER_START) {
262 uint64_t us = msg.reg[1];
263 trace_pnv_sbe_cmd_timer_start(us);
264 timer_mod(sbe->timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + us);
265 }
266 if (ctrl_flags & CONTROL_TIMER_STOP) {
267 trace_pnv_sbe_cmd_timer_stop();
268 timer_del(sbe->timer);
269 }
270 break;
271 case SBE_CMD_STASH_MPIPL_CONFIG:
272 /* key = sbe->mbox[1] */
273 switch (sbe->mbox[1]) {
274 case SBE_STASH_KEY_SKIBOOT_BASE:
275 mbox_val = sbe->mbox[2];
276 if (mbox_val >= machine->ram_size) {
277 qemu_log_mask(LOG_GUEST_ERROR,
278 "SBE: skiboot_base 0x%" PRIx64 \
279 "exceeds RAM size 0x" RAM_ADDR_FMT "\n",
280 mbox_val, machine->ram_size);
281 return;
282 }
283
284 pnv->mpipl_state.skiboot_base = mbox_val;
285 qemu_log_mask(LOG_UNIMP,
286 "Stashing skiboot base: 0x%" HWADDR_PRIx "\n",
287 pnv->mpipl_state.skiboot_base);
288
289 /*
290 * Set the response register.
291 *
292 * Currently setting the same sequence number in
293 * response as we got in the request.
294 */
295 sbe->mbox[4] = sbe->mbox[0]; /* sequence number */
296 pnv_sbe_set_host_doorbell(sbe,
297 sbe->host_doorbell | SBE_HOST_RESPONSE_WAITING);
298
299 break;
300 default:
301 qemu_log_mask(LOG_UNIMP,
302 "SBE: CMD_STASH_MPIPL_CONFIG: Unimplemented key: 0x" TARGET_FMT_lx "\n",
303 sbe->mbox[1]);
304 }
305 break;
306 default:
307 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented command: 0x%x\n", cmd);
308 }
309 }
310
311 static void pnv_sbe_set_sbe_doorbell(PnvSBE *sbe, uint64_t val)
312 {
313 val &= HOST_SBE_MSG_WAITING;
314 sbe->sbe_doorbell = val;
315
316 if (val & HOST_SBE_MSG_WAITING) {
317 sbe->sbe_doorbell &= ~HOST_SBE_MSG_WAITING;
318 do_sbe_msg(sbe);
319 }
320 }
321
322 static uint64_t pnv_sbe_power9_xscom_mbox_read(void *opaque, hwaddr addr,
323 unsigned size)
324 {
325 PnvSBE *sbe = PNV_SBE(opaque);
326 uint32_t offset = addr >> 3;
327 uint64_t val = 0;
328
329 if (offset <= PSU_HOST_SBE_MBOX_REG7) {
330 uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
331 val = sbe->mbox[idx];
332 } else {
333 switch (offset) {
334 case PSU_SBE_DOORBELL_REG_RW:
335 val = sbe->sbe_doorbell;
336 break;
337 case PSU_HOST_DOORBELL_REG_RW:
338 val = sbe->host_doorbell;
339 break;
340 default:
341 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
342 HWADDR_PRIx "\n", addr >> 3);
343 }
344 }
345
346 trace_pnv_sbe_xscom_mbox_read(addr, val);
347
348 return val;
349 }
350
351 static void pnv_sbe_power9_xscom_mbox_write(void *opaque, hwaddr addr,
352 uint64_t val, unsigned size)
353 {
354 PnvSBE *sbe = PNV_SBE(opaque);
355 uint32_t offset = addr >> 3;
356
357 trace_pnv_sbe_xscom_mbox_write(addr, val);
358
359 if (offset <= PSU_HOST_SBE_MBOX_REG7) {
360 uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
361 sbe->mbox[idx] = val;
362 } else {
363 switch (offset) {
364 case PSU_SBE_DOORBELL_REG_RW:
365 pnv_sbe_set_sbe_doorbell(sbe, val);
366 break;
367 case PSU_SBE_DOORBELL_REG_AND:
368 pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell & val);
369 break;
370 case PSU_SBE_DOORBELL_REG_OR:
371 pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell | val);
372 break;
373
374 case PSU_HOST_DOORBELL_REG_RW:
375 pnv_sbe_set_host_doorbell(sbe, val);
376 break;
377 case PSU_HOST_DOORBELL_REG_AND:
378 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell & val);
379 break;
380 case PSU_HOST_DOORBELL_REG_OR:
381 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | val);
382 break;
383
384 default:
385 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
386 HWADDR_PRIx "\n", addr >> 3);
387 }
388 }
389 }
390
391 static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops = {
392 .read = pnv_sbe_power9_xscom_mbox_read,
393 .write = pnv_sbe_power9_xscom_mbox_write,
394 .valid.min_access_size = 8,
395 .valid.max_access_size = 8,
396 .impl.min_access_size = 8,
397 .impl.max_access_size = 8,
398 .endianness = DEVICE_BIG_ENDIAN,
399 };
400
401 static void pnv_sbe_power9_class_init(ObjectClass *klass, const void *data)
402 {
403 PnvSBEClass *psc = PNV_SBE_CLASS(klass);
404 DeviceClass *dc = DEVICE_CLASS(klass);
405
406 dc->desc = "PowerNV SBE Controller (POWER9)";
407 psc->xscom_ctrl_size = PNV9_XSCOM_SBE_CTRL_SIZE;
408 psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
409 psc->xscom_mbox_size = PNV9_XSCOM_SBE_MBOX_SIZE;
410 psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
411 }
412
413 static const TypeInfo pnv_sbe_power9_type_info = {
414 .name = TYPE_PNV9_SBE,
415 .parent = TYPE_PNV_SBE,
416 .instance_size = sizeof(PnvSBE),
417 .class_init = pnv_sbe_power9_class_init,
418 };
419
420 static void pnv_sbe_power10_class_init(ObjectClass *klass, const void *data)
421 {
422 PnvSBEClass *psc = PNV_SBE_CLASS(klass);
423 DeviceClass *dc = DEVICE_CLASS(klass);
424
425 dc->desc = "PowerNV SBE Controller (POWER10)";
426 psc->xscom_ctrl_size = PNV10_XSCOM_SBE_CTRL_SIZE;
427 psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
428 psc->xscom_mbox_size = PNV10_XSCOM_SBE_MBOX_SIZE;
429 psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
430 }
431
432 static const TypeInfo pnv_sbe_power10_type_info = {
433 .name = TYPE_PNV10_SBE,
434 .parent = TYPE_PNV9_SBE,
435 .class_init = pnv_sbe_power10_class_init,
436 };
437
438 static void pnv_sbe_realize(DeviceState *dev, Error **errp)
439 {
440 PnvSBE *sbe = PNV_SBE(dev);
441 PnvSBEClass *psc = PNV_SBE_GET_CLASS(sbe);
442
443 /* XScom regions for SBE registers */
444 pnv_xscom_region_init(&sbe->xscom_ctrl_regs, OBJECT(dev),
445 psc->xscom_ctrl_ops, sbe, "xscom-sbe-ctrl",
446 psc->xscom_ctrl_size);
447 pnv_xscom_region_init(&sbe->xscom_mbox_regs, OBJECT(dev),
448 psc->xscom_mbox_ops, sbe, "xscom-sbe-mbox",
449 psc->xscom_mbox_size);
450
451 qdev_init_gpio_out(dev, &sbe->psi_irq, 1);
452
453 sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe);
454 }
455
456 static void pnv_sbe_class_init(ObjectClass *klass, const void *data)
457 {
458 DeviceClass *dc = DEVICE_CLASS(klass);
459
460 dc->realize = pnv_sbe_realize;
461 dc->desc = "PowerNV SBE Controller";
462 dc->user_creatable = false;
463 }
464
465 static const TypeInfo pnv_sbe_type_info = {
466 .name = TYPE_PNV_SBE,
467 .parent = TYPE_DEVICE,
468 .instance_size = sizeof(PnvSBE),
469 .class_init = pnv_sbe_class_init,
470 .class_size = sizeof(PnvSBEClass),
471 .abstract = true,
472 };
473
474 static void pnv_sbe_register_types(void)
475 {
476 type_register_static(&pnv_sbe_type_info);
477 type_register_static(&pnv_sbe_power9_type_info);
478 type_register_static(&pnv_sbe_power10_type_info);
479 }
480
481 type_init(pnv_sbe_register_types);