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