pnv_phb3_pbcq.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. * QEMU PowerPC PowerNV (POWER8) PHB3 model
  3. *
  4. * Copyright (c) 2014-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_phb3_regs.h"
  15. #include "hw/pci-host/pnv_phb3.h"
  16. #include "hw/ppc/pnv.h"
  17. #include "hw/ppc/pnv_xscom.h"
  18. #include "hw/pci/pci_bridge.h"
  19. #include "hw/pci/pci_bus.h"
  20. #include <libfdt.h>
  21. #define phb3_pbcq_error(pbcq, fmt, ...) \
  22. qemu_log_mask(LOG_GUEST_ERROR, "phb3_pbcq[%d:%d]: " fmt "\n", \
  23. (pbcq)->phb->chip_id, (pbcq)->phb->phb_id, ## __VA_ARGS__)
  24. static uint64_t pnv_pbcq_nest_xscom_read(void *opaque, hwaddr addr,
  25. unsigned size)
  26. {
  27. PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  28. uint32_t offset = addr >> 3;
  29. return pbcq->nest_regs[offset];
  30. }
  31. static uint64_t pnv_pbcq_pci_xscom_read(void *opaque, hwaddr addr,
  32. unsigned size)
  33. {
  34. PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  35. uint32_t offset = addr >> 3;
  36. return pbcq->pci_regs[offset];
  37. }
  38. static uint64_t pnv_pbcq_spci_xscom_read(void *opaque, hwaddr addr,
  39. unsigned size)
  40. {
  41. PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  42. uint32_t offset = addr >> 3;
  43. if (offset == PBCQ_SPCI_ASB_DATA) {
  44. return pnv_phb3_reg_read(pbcq->phb,
  45. pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR], 8);
  46. }
  47. return pbcq->spci_regs[offset];
  48. }
  49. static void pnv_pbcq_update_map(PnvPBCQState *pbcq)
  50. {
  51. uint64_t bar_en = pbcq->nest_regs[PBCQ_NEST_BAR_EN];
  52. uint64_t bar, mask, size;
  53. /*
  54. * NOTE: This will really not work well if those are remapped
  55. * after the PHB has created its sub regions. We could do better
  56. * if we had a way to resize regions but we don't really care
  57. * that much in practice as the stuff below really only happens
  58. * once early during boot
  59. */
  60. /* Handle unmaps */
  61. if (memory_region_is_mapped(&pbcq->mmbar0) &&
  62. !(bar_en & PBCQ_NEST_BAR_EN_MMIO0)) {
  63. memory_region_del_subregion(get_system_memory(), &pbcq->mmbar0);
  64. }
  65. if (memory_region_is_mapped(&pbcq->mmbar1) &&
  66. !(bar_en & PBCQ_NEST_BAR_EN_MMIO1)) {
  67. memory_region_del_subregion(get_system_memory(), &pbcq->mmbar1);
  68. }
  69. if (memory_region_is_mapped(&pbcq->phbbar) &&
  70. !(bar_en & PBCQ_NEST_BAR_EN_PHB)) {
  71. memory_region_del_subregion(get_system_memory(), &pbcq->phbbar);
  72. }
  73. /* Update PHB */
  74. pnv_phb3_update_regions(pbcq->phb);
  75. /* Handle maps */
  76. if (!memory_region_is_mapped(&pbcq->mmbar0) &&
  77. (bar_en & PBCQ_NEST_BAR_EN_MMIO0)) {
  78. bar = pbcq->nest_regs[PBCQ_NEST_MMIO_BAR0] >> 14;
  79. mask = pbcq->nest_regs[PBCQ_NEST_MMIO_MASK0];
  80. size = ((~mask) >> 14) + 1;
  81. memory_region_init(&pbcq->mmbar0, OBJECT(pbcq), "pbcq-mmio0", size);
  82. memory_region_add_subregion(get_system_memory(), bar, &pbcq->mmbar0);
  83. pbcq->mmio0_base = bar;
  84. pbcq->mmio0_size = size;
  85. }
  86. if (!memory_region_is_mapped(&pbcq->mmbar1) &&
  87. (bar_en & PBCQ_NEST_BAR_EN_MMIO1)) {
  88. bar = pbcq->nest_regs[PBCQ_NEST_MMIO_BAR1] >> 14;
  89. mask = pbcq->nest_regs[PBCQ_NEST_MMIO_MASK1];
  90. size = ((~mask) >> 14) + 1;
  91. memory_region_init(&pbcq->mmbar1, OBJECT(pbcq), "pbcq-mmio1", size);
  92. memory_region_add_subregion(get_system_memory(), bar, &pbcq->mmbar1);
  93. pbcq->mmio1_base = bar;
  94. pbcq->mmio1_size = size;
  95. }
  96. if (!memory_region_is_mapped(&pbcq->phbbar)
  97. && (bar_en & PBCQ_NEST_BAR_EN_PHB)) {
  98. bar = pbcq->nest_regs[PBCQ_NEST_PHB_BAR] >> 14;
  99. size = 0x1000;
  100. memory_region_init(&pbcq->phbbar, OBJECT(pbcq), "pbcq-phb", size);
  101. memory_region_add_subregion(get_system_memory(), bar, &pbcq->phbbar);
  102. }
  103. /* Update PHB */
  104. pnv_phb3_update_regions(pbcq->phb);
  105. }
  106. static void pnv_pbcq_nest_xscom_write(void *opaque, hwaddr addr,
  107. uint64_t val, unsigned size)
  108. {
  109. PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  110. uint32_t reg = addr >> 3;
  111. switch (reg) {
  112. case PBCQ_NEST_MMIO_BAR0:
  113. case PBCQ_NEST_MMIO_BAR1:
  114. case PBCQ_NEST_MMIO_MASK0:
  115. case PBCQ_NEST_MMIO_MASK1:
  116. if (pbcq->nest_regs[PBCQ_NEST_BAR_EN] &
  117. (PBCQ_NEST_BAR_EN_MMIO0 |
  118. PBCQ_NEST_BAR_EN_MMIO1)) {
  119. phb3_pbcq_error(pbcq, "Changing enabled BAR unsupported");
  120. }
  121. pbcq->nest_regs[reg] = val & 0xffffffffc0000000ull;
  122. break;
  123. case PBCQ_NEST_PHB_BAR:
  124. if (pbcq->nest_regs[PBCQ_NEST_BAR_EN] & PBCQ_NEST_BAR_EN_PHB) {
  125. phb3_pbcq_error(pbcq, "Changing enabled BAR unsupported");
  126. }
  127. pbcq->nest_regs[reg] = val & 0xfffffffffc000000ull;
  128. break;
  129. case PBCQ_NEST_BAR_EN:
  130. pbcq->nest_regs[reg] = val & 0xf800000000000000ull;
  131. pnv_pbcq_update_map(pbcq);
  132. pnv_phb3_remap_irqs(pbcq->phb);
  133. break;
  134. case PBCQ_NEST_IRSN_COMPARE:
  135. case PBCQ_NEST_IRSN_MASK:
  136. pbcq->nest_regs[reg] = val & PBCQ_NEST_IRSN_COMP;
  137. pnv_phb3_remap_irqs(pbcq->phb);
  138. break;
  139. case PBCQ_NEST_LSI_SRC_ID:
  140. pbcq->nest_regs[reg] = val & PBCQ_NEST_LSI_SRC;
  141. pnv_phb3_remap_irqs(pbcq->phb);
  142. break;
  143. default:
  144. phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
  145. addr, val);
  146. }
  147. }
  148. static void pnv_pbcq_pci_xscom_write(void *opaque, hwaddr addr,
  149. uint64_t val, unsigned size)
  150. {
  151. PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  152. uint32_t reg = addr >> 3;
  153. switch (reg) {
  154. case PBCQ_PCI_BAR2:
  155. pbcq->pci_regs[reg] = val & 0xfffffffffc000000ull;
  156. pnv_pbcq_update_map(pbcq);
  157. break;
  158. default:
  159. phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
  160. addr, val);
  161. }
  162. }
  163. static void pnv_pbcq_spci_xscom_write(void *opaque, hwaddr addr,
  164. uint64_t val, unsigned size)
  165. {
  166. PnvPBCQState *pbcq = PNV_PBCQ(opaque);
  167. uint32_t reg = addr >> 3;
  168. switch (reg) {
  169. case PBCQ_SPCI_ASB_ADDR:
  170. pbcq->spci_regs[reg] = val & 0xfff;
  171. break;
  172. case PBCQ_SPCI_ASB_STATUS:
  173. pbcq->spci_regs[reg] &= ~val;
  174. break;
  175. case PBCQ_SPCI_ASB_DATA:
  176. pnv_phb3_reg_write(pbcq->phb, pbcq->spci_regs[PBCQ_SPCI_ASB_ADDR],
  177. val, 8);
  178. break;
  179. case PBCQ_SPCI_AIB_CAPP_EN:
  180. case PBCQ_SPCI_CAPP_SEC_TMR:
  181. break;
  182. default:
  183. phb3_pbcq_error(pbcq, "%s @0x%"HWADDR_PRIx"=%"PRIx64, __func__,
  184. addr, val);
  185. }
  186. }
  187. static const MemoryRegionOps pnv_pbcq_nest_xscom_ops = {
  188. .read = pnv_pbcq_nest_xscom_read,
  189. .write = pnv_pbcq_nest_xscom_write,
  190. .valid.min_access_size = 8,
  191. .valid.max_access_size = 8,
  192. .impl.min_access_size = 8,
  193. .impl.max_access_size = 8,
  194. .endianness = DEVICE_BIG_ENDIAN,
  195. };
  196. static const MemoryRegionOps pnv_pbcq_pci_xscom_ops = {
  197. .read = pnv_pbcq_pci_xscom_read,
  198. .write = pnv_pbcq_pci_xscom_write,
  199. .valid.min_access_size = 8,
  200. .valid.max_access_size = 8,
  201. .impl.min_access_size = 8,
  202. .impl.max_access_size = 8,
  203. .endianness = DEVICE_BIG_ENDIAN,
  204. };
  205. static const MemoryRegionOps pnv_pbcq_spci_xscom_ops = {
  206. .read = pnv_pbcq_spci_xscom_read,
  207. .write = pnv_pbcq_spci_xscom_write,
  208. .valid.min_access_size = 8,
  209. .valid.max_access_size = 8,
  210. .impl.min_access_size = 8,
  211. .impl.max_access_size = 8,
  212. .endianness = DEVICE_BIG_ENDIAN,
  213. };
  214. static void pnv_pbcq_default_bars(PnvPBCQState *pbcq)
  215. {
  216. uint64_t mm0, mm1, reg;
  217. PnvPHB3 *phb = pbcq->phb;
  218. mm0 = 0x3d00000000000ull + 0x4000000000ull * phb->chip_id +
  219. 0x1000000000ull * phb->phb_id;
  220. mm1 = 0x3ff8000000000ull + 0x0200000000ull * phb->chip_id +
  221. 0x0080000000ull * phb->phb_id;
  222. reg = 0x3fffe40000000ull + 0x0000400000ull * phb->chip_id +
  223. 0x0000100000ull * phb->phb_id;
  224. pbcq->nest_regs[PBCQ_NEST_MMIO_BAR0] = mm0 << 14;
  225. pbcq->nest_regs[PBCQ_NEST_MMIO_BAR1] = mm1 << 14;
  226. pbcq->nest_regs[PBCQ_NEST_PHB_BAR] = reg << 14;
  227. pbcq->nest_regs[PBCQ_NEST_MMIO_MASK0] = 0x3fff000000000ull << 14;
  228. pbcq->nest_regs[PBCQ_NEST_MMIO_MASK1] = 0x3ffff80000000ull << 14;
  229. pbcq->pci_regs[PBCQ_PCI_BAR2] = reg << 14;
  230. }
  231. static void pnv_pbcq_realize(DeviceState *dev, Error **errp)
  232. {
  233. PnvPBCQState *pbcq = PNV_PBCQ(dev);
  234. PnvPHB3 *phb;
  235. char name[32];
  236. assert(pbcq->phb);
  237. phb = pbcq->phb;
  238. /* TODO: Fix OPAL to do that: establish default BAR values */
  239. pnv_pbcq_default_bars(pbcq);
  240. /* Initialize the XSCOM region for the PBCQ registers */
  241. snprintf(name, sizeof(name), "xscom-pbcq-nest-%d.%d",
  242. phb->chip_id, phb->phb_id);
  243. pnv_xscom_region_init(&pbcq->xscom_nest_regs, OBJECT(dev),
  244. &pnv_pbcq_nest_xscom_ops, pbcq, name,
  245. PNV_XSCOM_PBCQ_NEST_SIZE);
  246. snprintf(name, sizeof(name), "xscom-pbcq-pci-%d.%d",
  247. phb->chip_id, phb->phb_id);
  248. pnv_xscom_region_init(&pbcq->xscom_pci_regs, OBJECT(dev),
  249. &pnv_pbcq_pci_xscom_ops, pbcq, name,
  250. PNV_XSCOM_PBCQ_PCI_SIZE);
  251. snprintf(name, sizeof(name), "xscom-pbcq-spci-%d.%d",
  252. phb->chip_id, phb->phb_id);
  253. pnv_xscom_region_init(&pbcq->xscom_spci_regs, OBJECT(dev),
  254. &pnv_pbcq_spci_xscom_ops, pbcq, name,
  255. PNV_XSCOM_PBCQ_SPCI_SIZE);
  256. /* Populate the XSCOM address space. */
  257. pnv_xscom_add_subregion(phb->chip,
  258. PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id,
  259. &pbcq->xscom_nest_regs);
  260. pnv_xscom_add_subregion(phb->chip,
  261. PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id,
  262. &pbcq->xscom_pci_regs);
  263. pnv_xscom_add_subregion(phb->chip,
  264. PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id,
  265. &pbcq->xscom_spci_regs);
  266. }
  267. static int pnv_pbcq_dt_xscom(PnvXScomInterface *dev, void *fdt,
  268. int xscom_offset)
  269. {
  270. const char compat[] = "ibm,power8-pbcq";
  271. PnvPHB3 *phb = PNV_PBCQ(dev)->phb;
  272. char *name;
  273. int offset;
  274. uint32_t lpc_pcba = PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id;
  275. uint32_t reg[] = {
  276. cpu_to_be32(lpc_pcba),
  277. cpu_to_be32(PNV_XSCOM_PBCQ_NEST_SIZE),
  278. cpu_to_be32(PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id),
  279. cpu_to_be32(PNV_XSCOM_PBCQ_PCI_SIZE),
  280. cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id),
  281. cpu_to_be32(PNV_XSCOM_PBCQ_SPCI_SIZE)
  282. };
  283. name = g_strdup_printf("pbcq@%x", lpc_pcba);
  284. offset = fdt_add_subnode(fdt, xscom_offset, name);
  285. _FDT(offset);
  286. g_free(name);
  287. _FDT((fdt_setprop(fdt, offset, "reg", reg, sizeof(reg))));
  288. _FDT((fdt_setprop_cell(fdt, offset, "ibm,phb-index", phb->phb_id)));
  289. _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", phb->chip_id)));
  290. _FDT((fdt_setprop(fdt, offset, "compatible", compat,
  291. sizeof(compat))));
  292. return 0;
  293. }
  294. static void phb3_pbcq_instance_init(Object *obj)
  295. {
  296. PnvPBCQState *pbcq = PNV_PBCQ(obj);
  297. object_property_add_link(obj, "phb", TYPE_PNV_PHB3,
  298. (Object **)&pbcq->phb,
  299. object_property_allow_set_link,
  300. OBJ_PROP_LINK_STRONG);
  301. }
  302. static void pnv_pbcq_class_init(ObjectClass *klass, void *data)
  303. {
  304. DeviceClass *dc = DEVICE_CLASS(klass);
  305. PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
  306. xdc->dt_xscom = pnv_pbcq_dt_xscom;
  307. dc->realize = pnv_pbcq_realize;
  308. dc->user_creatable = false;
  309. }
  310. static const TypeInfo pnv_pbcq_type_info = {
  311. .name = TYPE_PNV_PBCQ,
  312. .parent = TYPE_DEVICE,
  313. .instance_size = sizeof(PnvPBCQState),
  314. .instance_init = phb3_pbcq_instance_init,
  315. .class_init = pnv_pbcq_class_init,
  316. .interfaces = (InterfaceInfo[]) {
  317. { TYPE_PNV_XSCOM_INTERFACE },
  318. { }
  319. }
  320. };
  321. static void pnv_pbcq_register_types(void)
  322. {
  323. type_register_static(&pnv_pbcq_type_info);
  324. }
  325. type_init(pnv_pbcq_register_types)