pnv_phb4_pec.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * QEMU PowerPC PowerNV (POWER9) PHB4 model
  3. *
  4. * Copyright (c) 2018-2020, IBM Corporation.
  5. *
  6. * This code is licensed under the GPL version 2 or later. See the
  7. * COPYING file in the top-level directory.
  8. */
  9. #include "qemu/osdep.h"
  10. #include "qapi/error.h"
  11. #include "qemu/log.h"
  12. #include "target/ppc/cpu.h"
  13. #include "hw/ppc/fdt.h"
  14. #include "hw/pci-host/pnv_phb4_regs.h"
  15. #include "hw/pci-host/pnv_phb4.h"
  16. #include "hw/ppc/pnv_xscom.h"
  17. #include "hw/pci/pci_bridge.h"
  18. #include "hw/pci/pci_bus.h"
  19. #include "hw/ppc/pnv.h"
  20. #include "hw/ppc/pnv_chip.h"
  21. #include "hw/qdev-properties.h"
  22. #include "sysemu/sysemu.h"
  23. #include <libfdt.h>
  24. #define phb_pec_error(pec, fmt, ...) \
  25. qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n", \
  26. (pec)->chip_id, (pec)->index, ## __VA_ARGS__)
  27. static uint64_t pnv_pec_nest_xscom_read(void *opaque, hwaddr addr,
  28. unsigned size)
  29. {
  30. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  31. uint32_t reg = addr >> 3;
  32. /* TODO: add list of allowed registers and error out if not */
  33. return pec->nest_regs[reg];
  34. }
  35. static void pnv_pec_nest_xscom_write(void *opaque, hwaddr addr,
  36. uint64_t val, unsigned size)
  37. {
  38. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  39. uint32_t reg = addr >> 3;
  40. switch (reg) {
  41. case PEC_NEST_PBCQ_HW_CONFIG:
  42. case PEC_NEST_DROP_PRIO_CTRL:
  43. case PEC_NEST_PBCQ_ERR_INJECT:
  44. case PEC_NEST_PCI_NEST_CLK_TRACE_CTL:
  45. case PEC_NEST_PBCQ_PMON_CTRL:
  46. case PEC_NEST_PBCQ_PBUS_ADDR_EXT:
  47. case PEC_NEST_PBCQ_PRED_VEC_TIMEOUT:
  48. case PEC_NEST_CAPP_CTRL:
  49. case PEC_NEST_PBCQ_READ_STK_OVR:
  50. case PEC_NEST_PBCQ_WRITE_STK_OVR:
  51. case PEC_NEST_PBCQ_STORE_STK_OVR:
  52. case PEC_NEST_PBCQ_RETRY_BKOFF_CTRL:
  53. pec->nest_regs[reg] = val;
  54. break;
  55. default:
  56. phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
  57. addr, val);
  58. }
  59. }
  60. static const MemoryRegionOps pnv_pec_nest_xscom_ops = {
  61. .read = pnv_pec_nest_xscom_read,
  62. .write = pnv_pec_nest_xscom_write,
  63. .valid.min_access_size = 8,
  64. .valid.max_access_size = 8,
  65. .impl.min_access_size = 8,
  66. .impl.max_access_size = 8,
  67. .endianness = DEVICE_BIG_ENDIAN,
  68. };
  69. static uint64_t pnv_pec_pci_xscom_read(void *opaque, hwaddr addr,
  70. unsigned size)
  71. {
  72. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  73. uint32_t reg = addr >> 3;
  74. /* TODO: add list of allowed registers and error out if not */
  75. return pec->pci_regs[reg];
  76. }
  77. static void pnv_pec_pci_xscom_write(void *opaque, hwaddr addr,
  78. uint64_t val, unsigned size)
  79. {
  80. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  81. uint32_t reg = addr >> 3;
  82. switch (reg) {
  83. case PEC_PCI_PBAIB_HW_CONFIG:
  84. case PEC_PCI_PBAIB_READ_STK_OVR:
  85. pec->pci_regs[reg] = val;
  86. break;
  87. default:
  88. phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
  89. addr, val);
  90. }
  91. }
  92. static const MemoryRegionOps pnv_pec_pci_xscom_ops = {
  93. .read = pnv_pec_pci_xscom_read,
  94. .write = pnv_pec_pci_xscom_write,
  95. .valid.min_access_size = 8,
  96. .valid.max_access_size = 8,
  97. .impl.min_access_size = 8,
  98. .impl.max_access_size = 8,
  99. .endianness = DEVICE_BIG_ENDIAN,
  100. };
  101. PnvPhb4PecState *pnv_pec_add_phb(PnvChip *chip, PnvPHB *phb, Error **errp)
  102. {
  103. PnvPhb4PecState *pecs = NULL;
  104. int chip_id = phb->chip_id;
  105. int index = phb->phb_id;
  106. int i, j;
  107. if (phb->version == 4) {
  108. Pnv9Chip *chip9 = PNV9_CHIP(chip);
  109. pecs = chip9->pecs;
  110. } else if (phb->version == 5) {
  111. Pnv10Chip *chip10 = PNV10_CHIP(chip);
  112. pecs = chip10->pecs;
  113. } else {
  114. g_assert_not_reached();
  115. }
  116. for (i = 0; i < chip->num_pecs; i++) {
  117. /*
  118. * For each PEC, check the amount of phbs it supports
  119. * and see if the given phb4 index matches an index.
  120. */
  121. PnvPhb4PecState *pec = &pecs[i];
  122. for (j = 0; j < pec->num_phbs; j++) {
  123. if (index == pnv_phb4_pec_get_phb_id(pec, j)) {
  124. pec->phbs[j] = phb;
  125. phb->pec = pec;
  126. return pec;
  127. }
  128. }
  129. }
  130. error_setg(errp,
  131. "pnv-phb4 chip-id %d index %d didn't match any existing PEC",
  132. chip_id, index);
  133. return NULL;
  134. }
  135. static PnvPHB *pnv_pec_default_phb_realize(PnvPhb4PecState *pec,
  136. int stack_no,
  137. Error **errp)
  138. {
  139. PnvPHB *phb = PNV_PHB(qdev_new(TYPE_PNV_PHB));
  140. int phb_id = pnv_phb4_pec_get_phb_id(pec, stack_no);
  141. object_property_add_child(OBJECT(pec), "phb[*]", OBJECT(phb));
  142. object_property_set_link(OBJECT(phb), "pec", OBJECT(pec),
  143. &error_abort);
  144. object_property_set_int(OBJECT(phb), "chip-id", pec->chip_id,
  145. &error_fatal);
  146. object_property_set_int(OBJECT(phb), "index", phb_id,
  147. &error_fatal);
  148. if (!sysbus_realize(SYS_BUS_DEVICE(phb), errp)) {
  149. return NULL;
  150. }
  151. return phb;
  152. }
  153. static void pnv_pec_realize(DeviceState *dev, Error **errp)
  154. {
  155. PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
  156. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
  157. char name[64];
  158. int i;
  159. if (pec->index >= PNV_CHIP_GET_CLASS(pec->chip)->num_pecs) {
  160. error_setg(errp, "invalid PEC index: %d", pec->index);
  161. return;
  162. }
  163. pec->num_phbs = pecc->num_phbs[pec->index];
  164. /* Create PHBs if running with defaults */
  165. if (defaults_enabled()) {
  166. g_assert(pec->num_phbs <= MAX_PHBS_PER_PEC);
  167. for (i = 0; i < pec->num_phbs; i++) {
  168. pec->phbs[i] = pnv_pec_default_phb_realize(pec, i, errp);
  169. }
  170. }
  171. /* Initialize the XSCOM regions for the PEC registers */
  172. snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest", pec->chip_id,
  173. pec->index);
  174. pnv_xscom_region_init(&pec->nest_regs_mr, OBJECT(dev),
  175. &pnv_pec_nest_xscom_ops, pec, name,
  176. PHB4_PEC_NEST_REGS_COUNT);
  177. snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci", pec->chip_id,
  178. pec->index);
  179. pnv_xscom_region_init(&pec->pci_regs_mr, OBJECT(dev),
  180. &pnv_pec_pci_xscom_ops, pec, name,
  181. PHB4_PEC_PCI_REGS_COUNT);
  182. }
  183. static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
  184. int xscom_offset)
  185. {
  186. PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
  187. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(dev);
  188. uint32_t nbase = pecc->xscom_nest_base(pec);
  189. uint32_t pbase = pecc->xscom_pci_base(pec);
  190. int offset, i;
  191. char *name;
  192. uint32_t reg[] = {
  193. cpu_to_be32(nbase),
  194. cpu_to_be32(pecc->xscom_nest_size),
  195. cpu_to_be32(pbase),
  196. cpu_to_be32(pecc->xscom_pci_size),
  197. };
  198. name = g_strdup_printf("pbcq@%x", nbase);
  199. offset = fdt_add_subnode(fdt, xscom_offset, name);
  200. _FDT(offset);
  201. g_free(name);
  202. _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
  203. _FDT((fdt_setprop_cell(fdt, offset, "ibm,pec-index", pec->index)));
  204. _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 1)));
  205. _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0)));
  206. _FDT((fdt_setprop(fdt, offset, "compatible", pecc->compat,
  207. pecc->compat_size)));
  208. for (i = 0; i < pec->num_phbs; i++) {
  209. int stk_offset;
  210. if (!pec->phbs[i]) {
  211. continue;
  212. }
  213. name = g_strdup_printf("stack@%x", i);
  214. stk_offset = fdt_add_subnode(fdt, offset, name);
  215. _FDT(stk_offset);
  216. g_free(name);
  217. _FDT((fdt_setprop(fdt, stk_offset, "compatible", pecc->stk_compat,
  218. pecc->stk_compat_size)));
  219. _FDT((fdt_setprop_cell(fdt, stk_offset, "reg", i)));
  220. _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index",
  221. pec->phbs[i]->phb_id)));
  222. }
  223. return 0;
  224. }
  225. static Property pnv_pec_properties[] = {
  226. DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0),
  227. DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0),
  228. DEFINE_PROP_LINK("chip", PnvPhb4PecState, chip, TYPE_PNV_CHIP,
  229. PnvChip *),
  230. DEFINE_PROP_END_OF_LIST(),
  231. };
  232. static uint32_t pnv_pec_xscom_pci_base(PnvPhb4PecState *pec)
  233. {
  234. return PNV9_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
  235. }
  236. static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec)
  237. {
  238. return PNV9_XSCOM_PEC_NEST_BASE + 0x400 * pec->index;
  239. }
  240. /*
  241. * PEC0 -> 1 phb
  242. * PEC1 -> 2 phb
  243. * PEC2 -> 3 phbs
  244. */
  245. static const uint32_t pnv_pec_num_phbs[] = { 1, 2, 3 };
  246. static void pnv_pec_class_init(ObjectClass *klass, void *data)
  247. {
  248. DeviceClass *dc = DEVICE_CLASS(klass);
  249. PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
  250. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
  251. static const char compat[] = "ibm,power9-pbcq";
  252. static const char stk_compat[] = "ibm,power9-phb-stack";
  253. xdc->dt_xscom = pnv_pec_dt_xscom;
  254. dc->realize = pnv_pec_realize;
  255. device_class_set_props(dc, pnv_pec_properties);
  256. dc->user_creatable = false;
  257. pecc->xscom_nest_base = pnv_pec_xscom_nest_base;
  258. pecc->xscom_pci_base = pnv_pec_xscom_pci_base;
  259. pecc->xscom_nest_size = PNV9_XSCOM_PEC_NEST_SIZE;
  260. pecc->xscom_pci_size = PNV9_XSCOM_PEC_PCI_SIZE;
  261. pecc->compat = compat;
  262. pecc->compat_size = sizeof(compat);
  263. pecc->stk_compat = stk_compat;
  264. pecc->stk_compat_size = sizeof(stk_compat);
  265. pecc->version = PNV_PHB4_VERSION;
  266. pecc->phb_type = TYPE_PNV_PHB4;
  267. pecc->num_phbs = pnv_pec_num_phbs;
  268. }
  269. static const TypeInfo pnv_pec_type_info = {
  270. .name = TYPE_PNV_PHB4_PEC,
  271. .parent = TYPE_DEVICE,
  272. .instance_size = sizeof(PnvPhb4PecState),
  273. .class_init = pnv_pec_class_init,
  274. .class_size = sizeof(PnvPhb4PecClass),
  275. .interfaces = (InterfaceInfo[]) {
  276. { TYPE_PNV_XSCOM_INTERFACE },
  277. { }
  278. }
  279. };
  280. /*
  281. * POWER10 definitions
  282. */
  283. static uint32_t pnv_phb5_pec_xscom_pci_base(PnvPhb4PecState *pec)
  284. {
  285. return PNV10_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
  286. }
  287. static uint32_t pnv_phb5_pec_xscom_nest_base(PnvPhb4PecState *pec)
  288. {
  289. /* index goes down ... */
  290. return PNV10_XSCOM_PEC_NEST_BASE - 0x1000000 * pec->index;
  291. }
  292. /*
  293. * PEC0 -> 3 stacks
  294. * PEC1 -> 3 stacks
  295. */
  296. static const uint32_t pnv_phb5_pec_num_stacks[] = { 3, 3 };
  297. static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data)
  298. {
  299. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
  300. static const char compat[] = "ibm,power10-pbcq";
  301. static const char stk_compat[] = "ibm,power10-phb-stack";
  302. pecc->xscom_nest_base = pnv_phb5_pec_xscom_nest_base;
  303. pecc->xscom_pci_base = pnv_phb5_pec_xscom_pci_base;
  304. pecc->xscom_nest_size = PNV10_XSCOM_PEC_NEST_SIZE;
  305. pecc->xscom_pci_size = PNV10_XSCOM_PEC_PCI_SIZE;
  306. pecc->compat = compat;
  307. pecc->compat_size = sizeof(compat);
  308. pecc->stk_compat = stk_compat;
  309. pecc->stk_compat_size = sizeof(stk_compat);
  310. pecc->version = PNV_PHB5_VERSION;
  311. pecc->phb_type = TYPE_PNV_PHB5;
  312. pecc->num_phbs = pnv_phb5_pec_num_stacks;
  313. }
  314. static const TypeInfo pnv_phb5_pec_type_info = {
  315. .name = TYPE_PNV_PHB5_PEC,
  316. .parent = TYPE_PNV_PHB4_PEC,
  317. .instance_size = sizeof(PnvPhb4PecState),
  318. .class_init = pnv_phb5_pec_class_init,
  319. .class_size = sizeof(PnvPhb4PecClass),
  320. .interfaces = (InterfaceInfo[]) {
  321. { TYPE_PNV_XSCOM_INTERFACE },
  322. { }
  323. }
  324. };
  325. static void pnv_pec_register_types(void)
  326. {
  327. type_register_static(&pnv_pec_type_info);
  328. type_register_static(&pnv_phb5_pec_type_info);
  329. }
  330. type_init(pnv_pec_register_types);