sysbus-fdt.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*
  2. * ARM Platform Bus device tree generation helpers
  3. *
  4. * Copyright (c) 2014 Linaro Limited
  5. *
  6. * Authors:
  7. * Alex Graf <agraf@suse.de>
  8. * Eric Auger <eric.auger@linaro.org>
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms and conditions of the GNU General Public License,
  12. * version 2 or later, as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  17. * more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along with
  20. * this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. #include "qemu/osdep.h"
  24. #include "qapi/error.h"
  25. #include <libfdt.h>
  26. #ifdef CONFIG_LINUX
  27. #include <linux/vfio.h>
  28. #endif
  29. #include "hw/arm/sysbus-fdt.h"
  30. #include "qemu/error-report.h"
  31. #include "sysemu/device_tree.h"
  32. #include "sysemu/tpm.h"
  33. #include "hw/platform-bus.h"
  34. #include "hw/vfio/vfio-platform.h"
  35. #include "hw/vfio/vfio-calxeda-xgmac.h"
  36. #include "hw/vfio/vfio-amd-xgbe.h"
  37. #include "hw/display/ramfb.h"
  38. #include "hw/arm/fdt.h"
  39. /*
  40. * internal struct that contains the information to create dynamic
  41. * sysbus device node
  42. */
  43. typedef struct PlatformBusFDTData {
  44. void *fdt; /* device tree handle */
  45. int irq_start; /* index of the first IRQ usable by platform bus devices */
  46. const char *pbus_node_name; /* name of the platform bus node */
  47. PlatformBusDevice *pbus;
  48. } PlatformBusFDTData;
  49. /* struct that allows to match a device and create its FDT node */
  50. typedef struct BindingEntry {
  51. const char *typename;
  52. const char *compat;
  53. int (*add_fn)(SysBusDevice *sbdev, void *opaque);
  54. bool (*match_fn)(SysBusDevice *sbdev, const struct BindingEntry *combo);
  55. } BindingEntry;
  56. /* helpers */
  57. typedef struct HostProperty {
  58. const char *name;
  59. bool optional;
  60. } HostProperty;
  61. #ifdef CONFIG_LINUX
  62. /**
  63. * copy_properties_from_host
  64. *
  65. * copies properties listed in an array from host device tree to
  66. * guest device tree. If a non optional property is not found, the
  67. * function asserts. An optional property is ignored if not found
  68. * in the host device tree.
  69. * @props: array of HostProperty to copy
  70. * @nb_props: number of properties in the array
  71. * @host_dt: host device tree blob
  72. * @guest_dt: guest device tree blob
  73. * @node_path: host dt node path where the property is supposed to be
  74. found
  75. * @nodename: guest node name the properties should be added to
  76. */
  77. static void copy_properties_from_host(HostProperty *props, int nb_props,
  78. void *host_fdt, void *guest_fdt,
  79. char *node_path, char *nodename)
  80. {
  81. int i, prop_len;
  82. const void *r;
  83. Error *err = NULL;
  84. for (i = 0; i < nb_props; i++) {
  85. r = qemu_fdt_getprop(host_fdt, node_path,
  86. props[i].name,
  87. &prop_len,
  88. &err);
  89. if (r) {
  90. qemu_fdt_setprop(guest_fdt, nodename,
  91. props[i].name, r, prop_len);
  92. } else {
  93. if (props[i].optional && prop_len == -FDT_ERR_NOTFOUND) {
  94. /* optional property does not exist */
  95. error_free(err);
  96. } else {
  97. error_report_err(err);
  98. }
  99. if (!props[i].optional) {
  100. /* mandatory property not found: bail out */
  101. exit(1);
  102. }
  103. err = NULL;
  104. }
  105. }
  106. }
  107. /* clock properties whose values are copied/pasted from host */
  108. static HostProperty clock_copied_properties[] = {
  109. {"compatible", false},
  110. {"#clock-cells", false},
  111. {"clock-frequency", true},
  112. {"clock-output-names", true},
  113. };
  114. /**
  115. * fdt_build_clock_node
  116. *
  117. * Build a guest clock node, used as a dependency from a passthrough'ed
  118. * device. Most information are retrieved from the host clock node.
  119. * Also check the host clock is a fixed one.
  120. *
  121. * @host_fdt: host device tree blob from which info are retrieved
  122. * @guest_fdt: guest device tree blob where the clock node is added
  123. * @host_phandle: phandle of the clock in host device tree
  124. * @guest_phandle: phandle to assign to the guest node
  125. */
  126. static void fdt_build_clock_node(void *host_fdt, void *guest_fdt,
  127. uint32_t host_phandle,
  128. uint32_t guest_phandle)
  129. {
  130. char *node_path = NULL;
  131. char *nodename;
  132. const void *r;
  133. int ret, node_offset, prop_len, path_len = 16;
  134. node_offset = fdt_node_offset_by_phandle(host_fdt, host_phandle);
  135. if (node_offset <= 0) {
  136. error_report("not able to locate clock handle %d in host device tree",
  137. host_phandle);
  138. exit(1);
  139. }
  140. node_path = g_malloc(path_len);
  141. while ((ret = fdt_get_path(host_fdt, node_offset, node_path, path_len))
  142. == -FDT_ERR_NOSPACE) {
  143. path_len += 16;
  144. node_path = g_realloc(node_path, path_len);
  145. }
  146. if (ret < 0) {
  147. error_report("not able to retrieve node path for clock handle %d",
  148. host_phandle);
  149. exit(1);
  150. }
  151. r = qemu_fdt_getprop(host_fdt, node_path, "compatible", &prop_len,
  152. &error_fatal);
  153. if (strcmp(r, "fixed-clock")) {
  154. error_report("clock handle %d is not a fixed clock", host_phandle);
  155. exit(1);
  156. }
  157. nodename = strrchr(node_path, '/');
  158. qemu_fdt_add_subnode(guest_fdt, nodename);
  159. copy_properties_from_host(clock_copied_properties,
  160. ARRAY_SIZE(clock_copied_properties),
  161. host_fdt, guest_fdt,
  162. node_path, nodename);
  163. qemu_fdt_setprop_cell(guest_fdt, nodename, "phandle", guest_phandle);
  164. g_free(node_path);
  165. }
  166. /**
  167. * sysfs_to_dt_name: convert the name found in sysfs into the node name
  168. * for instance e0900000.xgmac is converted into xgmac@e0900000
  169. * @sysfs_name: directory name in sysfs
  170. *
  171. * returns the device tree name upon success or NULL in case the sysfs name
  172. * does not match the expected format
  173. */
  174. static char *sysfs_to_dt_name(const char *sysfs_name)
  175. {
  176. gchar **substrings = g_strsplit(sysfs_name, ".", 2);
  177. char *dt_name = NULL;
  178. if (!substrings || !substrings[0] || !substrings[1]) {
  179. goto out;
  180. }
  181. dt_name = g_strdup_printf("%s@%s", substrings[1], substrings[0]);
  182. out:
  183. g_strfreev(substrings);
  184. return dt_name;
  185. }
  186. /* Device Specific Code */
  187. /**
  188. * add_calxeda_midway_xgmac_fdt_node
  189. *
  190. * Generates a simple node with following properties:
  191. * compatible string, regs, interrupts, dma-coherent
  192. */
  193. static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque)
  194. {
  195. PlatformBusFDTData *data = opaque;
  196. PlatformBusDevice *pbus = data->pbus;
  197. void *fdt = data->fdt;
  198. const char *parent_node = data->pbus_node_name;
  199. int compat_str_len, i;
  200. char *nodename;
  201. uint32_t *irq_attr, *reg_attr;
  202. uint64_t mmio_base, irq_number;
  203. VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
  204. VFIODevice *vbasedev = &vdev->vbasedev;
  205. mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
  206. nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
  207. vbasedev->name, mmio_base);
  208. qemu_fdt_add_subnode(fdt, nodename);
  209. compat_str_len = strlen(vdev->compat) + 1;
  210. qemu_fdt_setprop(fdt, nodename, "compatible",
  211. vdev->compat, compat_str_len);
  212. qemu_fdt_setprop(fdt, nodename, "dma-coherent", "", 0);
  213. reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
  214. for (i = 0; i < vbasedev->num_regions; i++) {
  215. mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
  216. reg_attr[2 * i] = cpu_to_be32(mmio_base);
  217. reg_attr[2 * i + 1] = cpu_to_be32(
  218. memory_region_size(vdev->regions[i]->mem));
  219. }
  220. qemu_fdt_setprop(fdt, nodename, "reg", reg_attr,
  221. vbasedev->num_regions * 2 * sizeof(uint32_t));
  222. irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
  223. for (i = 0; i < vbasedev->num_irqs; i++) {
  224. irq_number = platform_bus_get_irqn(pbus, sbdev , i)
  225. + data->irq_start;
  226. irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI);
  227. irq_attr[3 * i + 1] = cpu_to_be32(irq_number);
  228. irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI);
  229. }
  230. qemu_fdt_setprop(fdt, nodename, "interrupts",
  231. irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t));
  232. g_free(irq_attr);
  233. g_free(reg_attr);
  234. g_free(nodename);
  235. return 0;
  236. }
  237. /* AMD xgbe properties whose values are copied/pasted from host */
  238. static HostProperty amd_xgbe_copied_properties[] = {
  239. {"compatible", false},
  240. {"dma-coherent", true},
  241. {"amd,per-channel-interrupt", true},
  242. {"phy-mode", false},
  243. {"mac-address", true},
  244. {"amd,speed-set", false},
  245. {"amd,serdes-blwc", true},
  246. {"amd,serdes-cdr-rate", true},
  247. {"amd,serdes-pq-skew", true},
  248. {"amd,serdes-tx-amp", true},
  249. {"amd,serdes-dfe-tap-config", true},
  250. {"amd,serdes-dfe-tap-enable", true},
  251. {"clock-names", false},
  252. };
  253. /**
  254. * add_amd_xgbe_fdt_node
  255. *
  256. * Generates the combined xgbe/phy node following kernel >=4.2
  257. * binding documentation:
  258. * Documentation/devicetree/bindings/net/amd-xgbe.txt:
  259. * Also 2 clock nodes are created (dma and ptp)
  260. *
  261. * Asserts in case of error
  262. */
  263. static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque)
  264. {
  265. PlatformBusFDTData *data = opaque;
  266. PlatformBusDevice *pbus = data->pbus;
  267. VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
  268. VFIODevice *vbasedev = &vdev->vbasedev;
  269. VFIOINTp *intp;
  270. const char *parent_node = data->pbus_node_name;
  271. char **node_path, *nodename, *dt_name;
  272. void *guest_fdt = data->fdt, *host_fdt;
  273. const void *r;
  274. int i, prop_len;
  275. uint32_t *irq_attr, *reg_attr, *host_clock_phandles;
  276. uint64_t mmio_base, irq_number;
  277. uint32_t guest_clock_phandles[2];
  278. host_fdt = load_device_tree_from_sysfs();
  279. dt_name = sysfs_to_dt_name(vbasedev->name);
  280. if (!dt_name) {
  281. error_report("%s incorrect sysfs device name %s",
  282. __func__, vbasedev->name);
  283. exit(1);
  284. }
  285. node_path = qemu_fdt_node_path(host_fdt, dt_name, vdev->compat,
  286. &error_fatal);
  287. if (!node_path || !node_path[0]) {
  288. error_report("%s unable to retrieve node path for %s/%s",
  289. __func__, dt_name, vdev->compat);
  290. exit(1);
  291. }
  292. if (node_path[1]) {
  293. error_report("%s more than one node matching %s/%s!",
  294. __func__, dt_name, vdev->compat);
  295. exit(1);
  296. }
  297. g_free(dt_name);
  298. if (vbasedev->num_regions != 5) {
  299. error_report("%s Does the host dt node combine XGBE/PHY?", __func__);
  300. exit(1);
  301. }
  302. /* generate nodes for DMA_CLK and PTP_CLK */
  303. r = qemu_fdt_getprop(host_fdt, node_path[0], "clocks",
  304. &prop_len, &error_fatal);
  305. if (prop_len != 8) {
  306. error_report("%s clocks property should contain 2 handles", __func__);
  307. exit(1);
  308. }
  309. host_clock_phandles = (uint32_t *)r;
  310. guest_clock_phandles[0] = qemu_fdt_alloc_phandle(guest_fdt);
  311. guest_clock_phandles[1] = qemu_fdt_alloc_phandle(guest_fdt);
  312. /**
  313. * clock handles fetched from host dt are in be32 layout whereas
  314. * rest of the code uses cpu layout. Also guest clock handles are
  315. * in cpu layout.
  316. */
  317. fdt_build_clock_node(host_fdt, guest_fdt,
  318. be32_to_cpu(host_clock_phandles[0]),
  319. guest_clock_phandles[0]);
  320. fdt_build_clock_node(host_fdt, guest_fdt,
  321. be32_to_cpu(host_clock_phandles[1]),
  322. guest_clock_phandles[1]);
  323. /* combined XGBE/PHY node */
  324. mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
  325. nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
  326. vbasedev->name, mmio_base);
  327. qemu_fdt_add_subnode(guest_fdt, nodename);
  328. copy_properties_from_host(amd_xgbe_copied_properties,
  329. ARRAY_SIZE(amd_xgbe_copied_properties),
  330. host_fdt, guest_fdt,
  331. node_path[0], nodename);
  332. qemu_fdt_setprop_cells(guest_fdt, nodename, "clocks",
  333. guest_clock_phandles[0],
  334. guest_clock_phandles[1]);
  335. reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
  336. for (i = 0; i < vbasedev->num_regions; i++) {
  337. mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
  338. reg_attr[2 * i] = cpu_to_be32(mmio_base);
  339. reg_attr[2 * i + 1] = cpu_to_be32(
  340. memory_region_size(vdev->regions[i]->mem));
  341. }
  342. qemu_fdt_setprop(guest_fdt, nodename, "reg", reg_attr,
  343. vbasedev->num_regions * 2 * sizeof(uint32_t));
  344. irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
  345. for (i = 0; i < vbasedev->num_irqs; i++) {
  346. irq_number = platform_bus_get_irqn(pbus, sbdev , i)
  347. + data->irq_start;
  348. irq_attr[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI);
  349. irq_attr[3 * i + 1] = cpu_to_be32(irq_number);
  350. /*
  351. * General device interrupt and PCS auto-negotiation interrupts are
  352. * level-sensitive while the 4 per-channel interrupts are edge
  353. * sensitive
  354. */
  355. QLIST_FOREACH(intp, &vdev->intp_list, next) {
  356. if (intp->pin == i) {
  357. break;
  358. }
  359. }
  360. if (intp->flags & VFIO_IRQ_INFO_AUTOMASKED) {
  361. irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI);
  362. } else {
  363. irq_attr[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
  364. }
  365. }
  366. qemu_fdt_setprop(guest_fdt, nodename, "interrupts",
  367. irq_attr, vbasedev->num_irqs * 3 * sizeof(uint32_t));
  368. g_free(host_fdt);
  369. g_strfreev(node_path);
  370. g_free(irq_attr);
  371. g_free(reg_attr);
  372. g_free(nodename);
  373. return 0;
  374. }
  375. /* DT compatible matching */
  376. static bool vfio_platform_match(SysBusDevice *sbdev,
  377. const BindingEntry *entry)
  378. {
  379. VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev);
  380. const char *compat;
  381. unsigned int n;
  382. for (n = vdev->num_compat, compat = vdev->compat; n > 0;
  383. n--, compat += strlen(compat) + 1) {
  384. if (!strcmp(entry->compat, compat)) {
  385. return true;
  386. }
  387. }
  388. return false;
  389. }
  390. #define VFIO_PLATFORM_BINDING(compat, add_fn) \
  391. {TYPE_VFIO_PLATFORM, (compat), (add_fn), vfio_platform_match}
  392. #endif /* CONFIG_LINUX */
  393. /*
  394. * add_tpm_tis_fdt_node: Create a DT node for TPM TIS
  395. *
  396. * See kernel documentation:
  397. * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt
  398. * Optional interrupt for command completion is not exposed
  399. */
  400. static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque)
  401. {
  402. PlatformBusFDTData *data = opaque;
  403. PlatformBusDevice *pbus = data->pbus;
  404. void *fdt = data->fdt;
  405. const char *parent_node = data->pbus_node_name;
  406. char *nodename;
  407. uint32_t reg_attr[2];
  408. uint64_t mmio_base;
  409. mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
  410. nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base);
  411. qemu_fdt_add_subnode(fdt, nodename);
  412. qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio");
  413. reg_attr[0] = cpu_to_be32(mmio_base);
  414. reg_attr[1] = cpu_to_be32(0x5000);
  415. qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t));
  416. g_free(nodename);
  417. return 0;
  418. }
  419. static int no_fdt_node(SysBusDevice *sbdev, void *opaque)
  420. {
  421. return 0;
  422. }
  423. /* Device type based matching */
  424. static bool type_match(SysBusDevice *sbdev, const BindingEntry *entry)
  425. {
  426. return !strcmp(object_get_typename(OBJECT(sbdev)), entry->typename);
  427. }
  428. #define TYPE_BINDING(type, add_fn) {(type), NULL, (add_fn), NULL}
  429. /* list of supported dynamic sysbus bindings */
  430. static const BindingEntry bindings[] = {
  431. #ifdef CONFIG_LINUX
  432. TYPE_BINDING(TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node),
  433. TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node),
  434. VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node),
  435. #endif
  436. TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
  437. TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
  438. TYPE_BINDING("", NULL), /* last element */
  439. };
  440. /* Generic Code */
  441. /**
  442. * add_fdt_node - add the device tree node of a dynamic sysbus device
  443. *
  444. * @sbdev: handle to the sysbus device
  445. * @opaque: handle to the PlatformBusFDTData
  446. *
  447. * Checks the sysbus type belongs to the list of device types that
  448. * are dynamically instantiable and if so call the node creation
  449. * function.
  450. */
  451. static void add_fdt_node(SysBusDevice *sbdev, void *opaque)
  452. {
  453. int i, ret;
  454. for (i = 0; i < ARRAY_SIZE(bindings); i++) {
  455. const BindingEntry *iter = &bindings[i];
  456. if (type_match(sbdev, iter)) {
  457. if (!iter->match_fn || iter->match_fn(sbdev, iter)) {
  458. ret = iter->add_fn(sbdev, opaque);
  459. assert(!ret);
  460. return;
  461. }
  462. }
  463. }
  464. error_report("Device %s can not be dynamically instantiated",
  465. qdev_fw_name(DEVICE(sbdev)));
  466. exit(1);
  467. }
  468. void platform_bus_add_all_fdt_nodes(void *fdt, const char *intc, hwaddr addr,
  469. hwaddr bus_size, int irq_start)
  470. {
  471. const char platcomp[] = "qemu,platform\0simple-bus";
  472. PlatformBusDevice *pbus;
  473. DeviceState *dev;
  474. gchar *node;
  475. assert(fdt);
  476. node = g_strdup_printf("/platform@%"PRIx64, addr);
  477. /* Create a /platform node that we can put all devices into */
  478. qemu_fdt_add_subnode(fdt, node);
  479. qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
  480. /* Our platform bus region is less than 32bits, so 1 cell is enough for
  481. * address and size
  482. */
  483. qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
  484. qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
  485. qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, bus_size);
  486. qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc);
  487. dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
  488. pbus = PLATFORM_BUS_DEVICE(dev);
  489. PlatformBusFDTData data = {
  490. .fdt = fdt,
  491. .irq_start = irq_start,
  492. .pbus_node_name = node,
  493. .pbus = pbus,
  494. };
  495. /* Loop through all dynamic sysbus devices and create their node */
  496. foreach_dynamic_sysbus_device(add_fdt_node, &data);
  497. g_free(node);
  498. }