pci.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * Support for generating PCI related ACPI tables and passing them to Guests
  3. *
  4. * Copyright (C) 2006 Fabrice Bellard
  5. * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
  6. * Copyright (C) 2013-2019 Red Hat Inc
  7. * Copyright (C) 2019 Intel Corporation
  8. *
  9. * Author: Wei Yang <richardw.yang@linux.intel.com>
  10. * Author: Michael S. Tsirkin <mst@redhat.com>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. * You should have received a copy of the GNU General Public License along
  21. * with this program; if not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #include "qemu/osdep.h"
  24. #include "qemu/error-report.h"
  25. #include "qom/object_interfaces.h"
  26. #include "qapi/error.h"
  27. #include "hw/boards.h"
  28. #include "hw/acpi/aml-build.h"
  29. #include "hw/acpi/pci.h"
  30. #include "hw/pci/pci_bridge.h"
  31. #include "hw/pci/pci_device.h"
  32. #include "hw/pci/pcie_host.h"
  33. /*
  34. * PCI Firmware Specification, Revision 3.0
  35. * 4.1.2 MCFG Table Description.
  36. */
  37. void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
  38. const char *oem_id, const char *oem_table_id)
  39. {
  40. AcpiTable table = { .sig = "MCFG", .rev = 1,
  41. .oem_id = oem_id, .oem_table_id = oem_table_id };
  42. acpi_table_begin(&table, table_data);
  43. /* Reserved */
  44. build_append_int_noprefix(table_data, 0, 8);
  45. /*
  46. * Memory Mapped Enhanced Configuration Space Base Address Allocation
  47. * Structure
  48. */
  49. /* Base address, processor-relative */
  50. build_append_int_noprefix(table_data, info->base, 8);
  51. /* PCI segment group number */
  52. build_append_int_noprefix(table_data, 0, 2);
  53. /* Starting PCI Bus number */
  54. build_append_int_noprefix(table_data, 0, 1);
  55. /* Final PCI Bus number */
  56. build_append_int_noprefix(table_data, PCIE_MMCFG_BUS(info->size - 1), 1);
  57. /* Reserved */
  58. build_append_int_noprefix(table_data, 0, 4);
  59. acpi_table_end(linker, &table);
  60. }
  61. typedef struct AcpiGenericInitiator {
  62. /* private */
  63. Object parent;
  64. /* public */
  65. char *pci_dev;
  66. uint32_t node;
  67. } AcpiGenericInitiator;
  68. typedef struct AcpiGenericInitiatorClass {
  69. ObjectClass parent_class;
  70. } AcpiGenericInitiatorClass;
  71. #define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator"
  72. OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
  73. ACPI_GENERIC_INITIATOR, OBJECT,
  74. { TYPE_USER_CREATABLE },
  75. { NULL })
  76. OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
  77. static void acpi_generic_initiator_init(Object *obj)
  78. {
  79. AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
  80. gi->node = MAX_NODES;
  81. gi->pci_dev = NULL;
  82. }
  83. static void acpi_generic_initiator_finalize(Object *obj)
  84. {
  85. AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
  86. g_free(gi->pci_dev);
  87. }
  88. static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
  89. Error **errp)
  90. {
  91. AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
  92. gi->pci_dev = g_strdup(val);
  93. }
  94. static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
  95. const char *name, void *opaque,
  96. Error **errp)
  97. {
  98. AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
  99. MachineState *ms = MACHINE(qdev_get_machine());
  100. uint32_t value;
  101. if (!visit_type_uint32(v, name, &value, errp)) {
  102. return;
  103. }
  104. if (value >= MAX_NODES) {
  105. error_printf("%s: Invalid NUMA node specified\n",
  106. TYPE_ACPI_GENERIC_INITIATOR);
  107. exit(1);
  108. }
  109. gi->node = value;
  110. ms->numa_state->nodes[gi->node].has_gi = true;
  111. }
  112. static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
  113. {
  114. object_class_property_add_str(oc, "pci-dev", NULL,
  115. acpi_generic_initiator_set_pci_device);
  116. object_class_property_set_description(oc, "pci-dev",
  117. "PCI device to associate with the node");
  118. object_class_property_add(oc, "node", "int", NULL,
  119. acpi_generic_initiator_set_node, NULL, NULL);
  120. object_class_property_set_description(oc, "node",
  121. "NUMA node associated with the PCI device");
  122. }
  123. static int build_acpi_generic_initiator(Object *obj, void *opaque)
  124. {
  125. MachineState *ms = MACHINE(qdev_get_machine());
  126. AcpiGenericInitiator *gi;
  127. GArray *table_data = opaque;
  128. int32_t devfn;
  129. uint8_t bus;
  130. Object *o;
  131. if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
  132. return 0;
  133. }
  134. gi = ACPI_GENERIC_INITIATOR(obj);
  135. if (gi->node >= ms->numa_state->num_nodes) {
  136. error_printf("%s: Specified node %d is invalid.\n",
  137. TYPE_ACPI_GENERIC_INITIATOR, gi->node);
  138. exit(1);
  139. }
  140. o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
  141. if (!o) {
  142. error_printf("%s: Specified device must be a PCI device.\n",
  143. TYPE_ACPI_GENERIC_INITIATOR);
  144. exit(1);
  145. }
  146. bus = object_property_get_uint(o, "busnr", &error_fatal);
  147. devfn = object_property_get_uint(o, "addr", &error_fatal);
  148. /* devfn is constrained in PCI to be 8 bit but storage is an int32_t */
  149. assert(devfn >= 0 && devfn < PCI_DEVFN_MAX);
  150. build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn);
  151. return 0;
  152. }
  153. typedef struct AcpiGenericPort {
  154. /* private */
  155. Object parent;
  156. /* public */
  157. char *pci_bus;
  158. uint32_t node;
  159. } AcpiGenericPort;
  160. typedef struct AcpiGenericPortClass {
  161. ObjectClass parent_class;
  162. } AcpiGenericPortClass;
  163. #define TYPE_ACPI_GENERIC_PORT "acpi-generic-port"
  164. OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericPort, acpi_generic_port,
  165. ACPI_GENERIC_PORT, OBJECT,
  166. { TYPE_USER_CREATABLE },
  167. { NULL })
  168. OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort, ACPI_GENERIC_PORT)
  169. static void acpi_generic_port_init(Object *obj)
  170. {
  171. AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
  172. gp->node = MAX_NODES;
  173. gp->pci_bus = NULL;
  174. }
  175. static void acpi_generic_port_finalize(Object *obj)
  176. {
  177. AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
  178. g_free(gp->pci_bus);
  179. }
  180. static void acpi_generic_port_set_pci_bus(Object *obj, const char *val,
  181. Error **errp)
  182. {
  183. AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
  184. gp->pci_bus = g_strdup(val);
  185. }
  186. static void acpi_generic_port_set_node(Object *obj, Visitor *v,
  187. const char *name, void *opaque,
  188. Error **errp)
  189. {
  190. AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
  191. uint32_t value;
  192. if (!visit_type_uint32(v, name, &value, errp)) {
  193. return;
  194. }
  195. if (value >= MAX_NODES) {
  196. error_printf("%s: Invalid NUMA node specified\n",
  197. TYPE_ACPI_GENERIC_INITIATOR);
  198. exit(1);
  199. }
  200. gp->node = value;
  201. }
  202. static void acpi_generic_port_class_init(ObjectClass *oc, void *data)
  203. {
  204. object_class_property_add_str(oc, "pci-bus", NULL,
  205. acpi_generic_port_set_pci_bus);
  206. object_class_property_set_description(oc, "pci-bus",
  207. "PCI Bus of the host bridge associated with this GP affinity structure");
  208. object_class_property_add(oc, "node", "int", NULL,
  209. acpi_generic_port_set_node, NULL, NULL);
  210. object_class_property_set_description(oc, "node",
  211. "The NUMA node like ID to index HMAT/SLIT NUMA properties involving GP");
  212. }
  213. static int build_acpi_generic_port(Object *obj, void *opaque)
  214. {
  215. MachineState *ms = MACHINE(qdev_get_machine());
  216. const char *hid = "ACPI0016";
  217. GArray *table_data = opaque;
  218. AcpiGenericPort *gp;
  219. uint32_t uid;
  220. Object *o;
  221. if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_PORT)) {
  222. return 0;
  223. }
  224. gp = ACPI_GENERIC_PORT(obj);
  225. if (gp->node >= ms->numa_state->num_nodes) {
  226. error_printf("%s: node %d is invalid.\n",
  227. TYPE_ACPI_GENERIC_PORT, gp->node);
  228. exit(1);
  229. }
  230. o = object_resolve_path_type(gp->pci_bus, TYPE_PXB_CXL_BUS, NULL);
  231. if (!o) {
  232. error_printf("%s: device must be a CXL host bridge.\n",
  233. TYPE_ACPI_GENERIC_PORT);
  234. exit(1);
  235. }
  236. uid = object_property_get_uint(o, "acpi_uid", &error_fatal);
  237. build_srat_acpi_generic_port(table_data, gp->node, hid, uid);
  238. return 0;
  239. }
  240. void build_srat_generic_affinity_structures(GArray *table_data)
  241. {
  242. object_child_foreach_recursive(object_get_root(),
  243. build_acpi_generic_initiator,
  244. table_data);
  245. object_child_foreach_recursive(object_get_root(), build_acpi_generic_port,
  246. table_data);
  247. }