sysbus-fdt.c 17 KB

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