xref: /openbmc/qemu/hw/ppc/pnv_sbe.c (revision d2dfe0b5)
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 
83 struct sbe_msg {
84     uint64_t reg[4];
85 };
86 
87 static 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 
104 static 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 
118 static 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 
128 static 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 
196 static 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 
205 static 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 
244 static 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 
255 static 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 
284 static 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 
324 static 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 
334 static 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 
346 static 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 
353 static 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 
365 static 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 
371 static 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 
384     qdev_init_gpio_out(DEVICE(dev), &sbe->psi_irq, 1);
385 
386     sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe);
387 }
388 
389 static 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 
398 static 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 
407 static 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 
414 type_init(pnv_sbe_register_types);
415