pnv_phb4_pec.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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/qdev-properties.h"
  21. #include "sysemu/sysemu.h"
  22. #include <libfdt.h>
  23. #define phb_pec_error(pec, fmt, ...) \
  24. qemu_log_mask(LOG_GUEST_ERROR, "phb4_pec[%d:%d]: " fmt "\n", \
  25. (pec)->chip_id, (pec)->index, ## __VA_ARGS__)
  26. static uint64_t pnv_pec_nest_xscom_read(void *opaque, hwaddr addr,
  27. unsigned size)
  28. {
  29. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  30. uint32_t reg = addr >> 3;
  31. /* TODO: add list of allowed registers and error out if not */
  32. return pec->nest_regs[reg];
  33. }
  34. static void pnv_pec_nest_xscom_write(void *opaque, hwaddr addr,
  35. uint64_t val, unsigned size)
  36. {
  37. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  38. uint32_t reg = addr >> 3;
  39. switch (reg) {
  40. case PEC_NEST_PBCQ_HW_CONFIG:
  41. case PEC_NEST_DROP_PRIO_CTRL:
  42. case PEC_NEST_PBCQ_ERR_INJECT:
  43. case PEC_NEST_PCI_NEST_CLK_TRACE_CTL:
  44. case PEC_NEST_PBCQ_PMON_CTRL:
  45. case PEC_NEST_PBCQ_PBUS_ADDR_EXT:
  46. case PEC_NEST_PBCQ_PRED_VEC_TIMEOUT:
  47. case PEC_NEST_CAPP_CTRL:
  48. case PEC_NEST_PBCQ_READ_STK_OVR:
  49. case PEC_NEST_PBCQ_WRITE_STK_OVR:
  50. case PEC_NEST_PBCQ_STORE_STK_OVR:
  51. case PEC_NEST_PBCQ_RETRY_BKOFF_CTRL:
  52. pec->nest_regs[reg] = val;
  53. break;
  54. default:
  55. phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
  56. addr, val);
  57. }
  58. }
  59. static const MemoryRegionOps pnv_pec_nest_xscom_ops = {
  60. .read = pnv_pec_nest_xscom_read,
  61. .write = pnv_pec_nest_xscom_write,
  62. .valid.min_access_size = 8,
  63. .valid.max_access_size = 8,
  64. .impl.min_access_size = 8,
  65. .impl.max_access_size = 8,
  66. .endianness = DEVICE_BIG_ENDIAN,
  67. };
  68. static uint64_t pnv_pec_pci_xscom_read(void *opaque, hwaddr addr,
  69. unsigned size)
  70. {
  71. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  72. uint32_t reg = addr >> 3;
  73. /* TODO: add list of allowed registers and error out if not */
  74. return pec->pci_regs[reg];
  75. }
  76. static void pnv_pec_pci_xscom_write(void *opaque, hwaddr addr,
  77. uint64_t val, unsigned size)
  78. {
  79. PnvPhb4PecState *pec = PNV_PHB4_PEC(opaque);
  80. uint32_t reg = addr >> 3;
  81. switch (reg) {
  82. case PEC_PCI_PBAIB_HW_CONFIG:
  83. case PEC_PCI_PBAIB_READ_STK_OVR:
  84. pec->pci_regs[reg] = val;
  85. break;
  86. default:
  87. phb_pec_error(pec, "%s @0x%"HWADDR_PRIx"=%"PRIx64"\n", __func__,
  88. addr, val);
  89. }
  90. }
  91. static const MemoryRegionOps pnv_pec_pci_xscom_ops = {
  92. .read = pnv_pec_pci_xscom_read,
  93. .write = pnv_pec_pci_xscom_write,
  94. .valid.min_access_size = 8,
  95. .valid.max_access_size = 8,
  96. .impl.min_access_size = 8,
  97. .impl.max_access_size = 8,
  98. .endianness = DEVICE_BIG_ENDIAN,
  99. };
  100. static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec,
  101. int stack_no,
  102. Error **errp)
  103. {
  104. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
  105. PnvPHB4 *phb = PNV_PHB4(qdev_new(pecc->phb_type));
  106. int phb_id = pnv_phb4_pec_get_phb_id(pec, stack_no);
  107. object_property_add_child(OBJECT(pec), "phb[*]", OBJECT(phb));
  108. object_property_set_link(OBJECT(phb), "pec", OBJECT(pec),
  109. &error_abort);
  110. object_property_set_int(OBJECT(phb), "chip-id", pec->chip_id,
  111. &error_fatal);
  112. object_property_set_int(OBJECT(phb), "index", phb_id,
  113. &error_fatal);
  114. if (!sysbus_realize(SYS_BUS_DEVICE(phb), errp)) {
  115. return;
  116. }
  117. /* Add a single Root port if running with defaults */
  118. pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), pecc->rp_model);
  119. }
  120. static void pnv_pec_realize(DeviceState *dev, Error **errp)
  121. {
  122. PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
  123. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
  124. char name[64];
  125. int i;
  126. if (pec->index >= PNV_CHIP_GET_CLASS(pec->chip)->num_pecs) {
  127. error_setg(errp, "invalid PEC index: %d", pec->index);
  128. return;
  129. }
  130. pec->num_phbs = pecc->num_phbs[pec->index];
  131. /* Create PHBs if running with defaults */
  132. for (i = 0; i < pec->num_phbs; i++) {
  133. pnv_pec_default_phb_realize(pec, i, errp);
  134. }
  135. /* Initialize the XSCOM regions for the PEC registers */
  136. snprintf(name, sizeof(name), "xscom-pec-%d.%d-nest", pec->chip_id,
  137. pec->index);
  138. pnv_xscom_region_init(&pec->nest_regs_mr, OBJECT(dev),
  139. &pnv_pec_nest_xscom_ops, pec, name,
  140. PHB4_PEC_NEST_REGS_COUNT);
  141. snprintf(name, sizeof(name), "xscom-pec-%d.%d-pci", pec->chip_id,
  142. pec->index);
  143. pnv_xscom_region_init(&pec->pci_regs_mr, OBJECT(dev),
  144. &pnv_pec_pci_xscom_ops, pec, name,
  145. PHB4_PEC_PCI_REGS_COUNT);
  146. }
  147. static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
  148. int xscom_offset)
  149. {
  150. PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
  151. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(dev);
  152. uint32_t nbase = pecc->xscom_nest_base(pec);
  153. uint32_t pbase = pecc->xscom_pci_base(pec);
  154. int offset, i;
  155. char *name;
  156. uint32_t reg[] = {
  157. cpu_to_be32(nbase),
  158. cpu_to_be32(pecc->xscom_nest_size),
  159. cpu_to_be32(pbase),
  160. cpu_to_be32(pecc->xscom_pci_size),
  161. };
  162. name = g_strdup_printf("pbcq@%x", nbase);
  163. offset = fdt_add_subnode(fdt, xscom_offset, name);
  164. _FDT(offset);
  165. g_free(name);
  166. _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
  167. _FDT((fdt_setprop_cell(fdt, offset, "ibm,pec-index", pec->index)));
  168. _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 1)));
  169. _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0)));
  170. _FDT((fdt_setprop(fdt, offset, "compatible", pecc->compat,
  171. pecc->compat_size)));
  172. for (i = 0; i < pec->num_phbs; i++) {
  173. int phb_id = pnv_phb4_pec_get_phb_id(pec, i);
  174. int stk_offset;
  175. name = g_strdup_printf("stack@%x", i);
  176. stk_offset = fdt_add_subnode(fdt, offset, name);
  177. _FDT(stk_offset);
  178. g_free(name);
  179. _FDT((fdt_setprop(fdt, stk_offset, "compatible", pecc->stk_compat,
  180. pecc->stk_compat_size)));
  181. _FDT((fdt_setprop_cell(fdt, stk_offset, "reg", i)));
  182. _FDT((fdt_setprop_cell(fdt, stk_offset, "ibm,phb-index", phb_id)));
  183. }
  184. return 0;
  185. }
  186. static Property pnv_pec_properties[] = {
  187. DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0),
  188. DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0),
  189. DEFINE_PROP_LINK("chip", PnvPhb4PecState, chip, TYPE_PNV_CHIP,
  190. PnvChip *),
  191. DEFINE_PROP_END_OF_LIST(),
  192. };
  193. static uint32_t pnv_pec_xscom_pci_base(PnvPhb4PecState *pec)
  194. {
  195. return PNV9_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
  196. }
  197. static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec)
  198. {
  199. return PNV9_XSCOM_PEC_NEST_BASE + 0x400 * pec->index;
  200. }
  201. /*
  202. * PEC0 -> 1 phb
  203. * PEC1 -> 2 phb
  204. * PEC2 -> 3 phbs
  205. */
  206. static const uint32_t pnv_pec_num_phbs[] = { 1, 2, 3 };
  207. static void pnv_pec_class_init(ObjectClass *klass, void *data)
  208. {
  209. DeviceClass *dc = DEVICE_CLASS(klass);
  210. PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
  211. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
  212. static const char compat[] = "ibm,power9-pbcq";
  213. static const char stk_compat[] = "ibm,power9-phb-stack";
  214. xdc->dt_xscom = pnv_pec_dt_xscom;
  215. dc->realize = pnv_pec_realize;
  216. device_class_set_props(dc, pnv_pec_properties);
  217. dc->user_creatable = false;
  218. pecc->xscom_nest_base = pnv_pec_xscom_nest_base;
  219. pecc->xscom_pci_base = pnv_pec_xscom_pci_base;
  220. pecc->xscom_nest_size = PNV9_XSCOM_PEC_NEST_SIZE;
  221. pecc->xscom_pci_size = PNV9_XSCOM_PEC_PCI_SIZE;
  222. pecc->compat = compat;
  223. pecc->compat_size = sizeof(compat);
  224. pecc->stk_compat = stk_compat;
  225. pecc->stk_compat_size = sizeof(stk_compat);
  226. pecc->version = PNV_PHB4_VERSION;
  227. pecc->phb_type = TYPE_PNV_PHB4;
  228. pecc->num_phbs = pnv_pec_num_phbs;
  229. pecc->rp_model = TYPE_PNV_PHB4_ROOT_PORT;
  230. }
  231. static const TypeInfo pnv_pec_type_info = {
  232. .name = TYPE_PNV_PHB4_PEC,
  233. .parent = TYPE_DEVICE,
  234. .instance_size = sizeof(PnvPhb4PecState),
  235. .class_init = pnv_pec_class_init,
  236. .class_size = sizeof(PnvPhb4PecClass),
  237. .interfaces = (InterfaceInfo[]) {
  238. { TYPE_PNV_XSCOM_INTERFACE },
  239. { }
  240. }
  241. };
  242. /*
  243. * POWER10 definitions
  244. */
  245. static uint32_t pnv_phb5_pec_xscom_pci_base(PnvPhb4PecState *pec)
  246. {
  247. return PNV10_XSCOM_PEC_PCI_BASE + 0x1000000 * pec->index;
  248. }
  249. static uint32_t pnv_phb5_pec_xscom_nest_base(PnvPhb4PecState *pec)
  250. {
  251. /* index goes down ... */
  252. return PNV10_XSCOM_PEC_NEST_BASE - 0x1000000 * pec->index;
  253. }
  254. /*
  255. * PEC0 -> 3 stacks
  256. * PEC1 -> 3 stacks
  257. */
  258. static const uint32_t pnv_phb5_pec_num_stacks[] = { 3, 3 };
  259. static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data)
  260. {
  261. PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass);
  262. static const char compat[] = "ibm,power10-pbcq";
  263. static const char stk_compat[] = "ibm,power10-phb-stack";
  264. pecc->xscom_nest_base = pnv_phb5_pec_xscom_nest_base;
  265. pecc->xscom_pci_base = pnv_phb5_pec_xscom_pci_base;
  266. pecc->xscom_nest_size = PNV10_XSCOM_PEC_NEST_SIZE;
  267. pecc->xscom_pci_size = PNV10_XSCOM_PEC_PCI_SIZE;
  268. pecc->compat = compat;
  269. pecc->compat_size = sizeof(compat);
  270. pecc->stk_compat = stk_compat;
  271. pecc->stk_compat_size = sizeof(stk_compat);
  272. pecc->version = PNV_PHB5_VERSION;
  273. pecc->phb_type = TYPE_PNV_PHB5;
  274. pecc->num_phbs = pnv_phb5_pec_num_stacks;
  275. pecc->rp_model = TYPE_PNV_PHB5_ROOT_PORT;
  276. }
  277. static const TypeInfo pnv_phb5_pec_type_info = {
  278. .name = TYPE_PNV_PHB5_PEC,
  279. .parent = TYPE_PNV_PHB4_PEC,
  280. .instance_size = sizeof(PnvPhb4PecState),
  281. .class_init = pnv_phb5_pec_class_init,
  282. .class_size = sizeof(PnvPhb4PecClass),
  283. .interfaces = (InterfaceInfo[]) {
  284. { TYPE_PNV_XSCOM_INTERFACE },
  285. { }
  286. }
  287. };
  288. static void pnv_pec_register_types(void)
  289. {
  290. type_register_static(&pnv_pec_type_info);
  291. type_register_static(&pnv_phb5_pec_type_info);
  292. }
  293. type_init(pnv_pec_register_types);