spapr_vio.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. /*
  2. * QEMU sPAPR VIO code
  3. *
  4. * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
  5. * Based on the s390 virtio bus code:
  6. * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "hw.h"
  22. #include "sysemu.h"
  23. #include "boards.h"
  24. #include "monitor.h"
  25. #include "loader.h"
  26. #include "elf.h"
  27. #include "hw/sysbus.h"
  28. #include "kvm.h"
  29. #include "device_tree.h"
  30. #include "kvm_ppc.h"
  31. #include "hw/spapr.h"
  32. #include "hw/spapr_vio.h"
  33. #include "hw/xics.h"
  34. #ifdef CONFIG_FDT
  35. #include <libfdt.h>
  36. #endif /* CONFIG_FDT */
  37. /* #define DEBUG_SPAPR */
  38. /* #define DEBUG_TCE */
  39. #ifdef DEBUG_SPAPR
  40. #define dprintf(fmt, ...) \
  41. do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
  42. #else
  43. #define dprintf(fmt, ...) \
  44. do { } while (0)
  45. #endif
  46. static struct BusInfo spapr_vio_bus_info = {
  47. .name = "spapr-vio",
  48. .size = sizeof(VIOsPAPRBus),
  49. .props = (Property[]) {
  50. DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
  51. DEFINE_PROP_END_OF_LIST(),
  52. },
  53. };
  54. VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
  55. {
  56. DeviceState *qdev;
  57. VIOsPAPRDevice *dev = NULL;
  58. QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
  59. dev = (VIOsPAPRDevice *)qdev;
  60. if (dev->reg == reg) {
  61. return dev;
  62. }
  63. }
  64. return NULL;
  65. }
  66. static char *vio_format_dev_name(VIOsPAPRDevice *dev)
  67. {
  68. VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
  69. char *name;
  70. /* Device tree style name device@reg */
  71. if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) {
  72. return NULL;
  73. }
  74. return name;
  75. }
  76. #ifdef CONFIG_FDT
  77. static int vio_make_devnode(VIOsPAPRDevice *dev,
  78. void *fdt)
  79. {
  80. VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
  81. int vdevice_off, node_off, ret;
  82. char *dt_name;
  83. vdevice_off = fdt_path_offset(fdt, "/vdevice");
  84. if (vdevice_off < 0) {
  85. return vdevice_off;
  86. }
  87. dt_name = vio_format_dev_name(dev);
  88. if (!dt_name) {
  89. return -ENOMEM;
  90. }
  91. node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
  92. free(dt_name);
  93. if (node_off < 0) {
  94. return node_off;
  95. }
  96. ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
  97. if (ret < 0) {
  98. return ret;
  99. }
  100. if (info->dt_type) {
  101. ret = fdt_setprop_string(fdt, node_off, "device_type",
  102. info->dt_type);
  103. if (ret < 0) {
  104. return ret;
  105. }
  106. }
  107. if (info->dt_compatible) {
  108. ret = fdt_setprop_string(fdt, node_off, "compatible",
  109. info->dt_compatible);
  110. if (ret < 0) {
  111. return ret;
  112. }
  113. }
  114. if (dev->qirq) {
  115. uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
  116. ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
  117. sizeof(ints_prop));
  118. if (ret < 0) {
  119. return ret;
  120. }
  121. }
  122. if (dev->rtce_window_size) {
  123. uint32_t dma_prop[] = {cpu_to_be32(dev->reg),
  124. 0, 0,
  125. 0, cpu_to_be32(dev->rtce_window_size)};
  126. ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
  127. if (ret < 0) {
  128. return ret;
  129. }
  130. ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
  131. if (ret < 0) {
  132. return ret;
  133. }
  134. ret = fdt_setprop(fdt, node_off, "ibm,my-dma-window", dma_prop,
  135. sizeof(dma_prop));
  136. if (ret < 0) {
  137. return ret;
  138. }
  139. }
  140. if (info->devnode) {
  141. ret = (info->devnode)(dev, fdt, node_off);
  142. if (ret < 0) {
  143. return ret;
  144. }
  145. }
  146. return node_off;
  147. }
  148. #endif /* CONFIG_FDT */
  149. /*
  150. * RTCE handling
  151. */
  152. static void rtce_init(VIOsPAPRDevice *dev)
  153. {
  154. size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
  155. * sizeof(VIOsPAPR_RTCE);
  156. if (size) {
  157. dev->rtce_table = kvmppc_create_spapr_tce(dev->reg,
  158. dev->rtce_window_size,
  159. &dev->kvmtce_fd);
  160. if (!dev->rtce_table) {
  161. dev->rtce_table = g_malloc0(size);
  162. }
  163. }
  164. }
  165. static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr,
  166. target_ulong opcode, target_ulong *args)
  167. {
  168. target_ulong liobn = args[0];
  169. target_ulong ioba = args[1];
  170. target_ulong tce = args[2];
  171. VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn);
  172. VIOsPAPR_RTCE *rtce;
  173. if (!dev) {
  174. hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
  175. TARGET_FMT_lx "\n", liobn);
  176. return H_PARAMETER;
  177. }
  178. ioba &= ~(SPAPR_VIO_TCE_PAGE_SIZE - 1);
  179. #ifdef DEBUG_TCE
  180. fprintf(stderr, "spapr_vio_put_tce on %s ioba 0x" TARGET_FMT_lx
  181. " TCE 0x" TARGET_FMT_lx "\n", dev->qdev.id, ioba, tce);
  182. #endif
  183. if (ioba >= dev->rtce_window_size) {
  184. hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
  185. TARGET_FMT_lx "\n", ioba);
  186. return H_PARAMETER;
  187. }
  188. rtce = dev->rtce_table + (ioba >> SPAPR_VIO_TCE_PAGE_SHIFT);
  189. rtce->tce = tce;
  190. return H_SUCCESS;
  191. }
  192. int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
  193. target_ulong len, enum VIOsPAPR_TCEAccess access)
  194. {
  195. int start, end, i;
  196. start = ioba >> SPAPR_VIO_TCE_PAGE_SHIFT;
  197. end = (ioba + len - 1) >> SPAPR_VIO_TCE_PAGE_SHIFT;
  198. for (i = start; i <= end; i++) {
  199. if ((dev->rtce_table[i].tce & access) != access) {
  200. #ifdef DEBUG_TCE
  201. fprintf(stderr, "FAIL on %d\n", i);
  202. #endif
  203. return -1;
  204. }
  205. }
  206. return 0;
  207. }
  208. int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf,
  209. uint32_t size)
  210. {
  211. #ifdef DEBUG_TCE
  212. fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
  213. (unsigned long long)taddr, size);
  214. #endif
  215. /* Check for bypass */
  216. if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
  217. cpu_physical_memory_write(taddr, buf, size);
  218. return 0;
  219. }
  220. while (size) {
  221. uint64_t tce;
  222. uint32_t lsize;
  223. uint64_t txaddr;
  224. /* Check if we are in bound */
  225. if (taddr >= dev->rtce_window_size) {
  226. #ifdef DEBUG_TCE
  227. fprintf(stderr, "spapr_tce_dma_write out of bounds\n");
  228. #endif
  229. return H_DEST_PARM;
  230. }
  231. tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
  232. /* How much til end of page ? */
  233. lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
  234. /* Check TCE */
  235. if (!(tce & 2)) {
  236. return H_DEST_PARM;
  237. }
  238. /* Translate */
  239. txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
  240. (taddr & SPAPR_VIO_TCE_PAGE_MASK);
  241. #ifdef DEBUG_TCE
  242. fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
  243. (unsigned long long)txaddr, lsize);
  244. #endif
  245. /* Do it */
  246. cpu_physical_memory_write(txaddr, buf, lsize);
  247. buf += lsize;
  248. taddr += lsize;
  249. size -= lsize;
  250. }
  251. return 0;
  252. }
  253. int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size)
  254. {
  255. /* FIXME: allocating a temp buffer is nasty, but just stepping
  256. * through writing zeroes is awkward. This will do for now. */
  257. uint8_t zeroes[size];
  258. #ifdef DEBUG_TCE
  259. fprintf(stderr, "spapr_tce_dma_zero taddr=0x%llx size=0x%x\n",
  260. (unsigned long long)taddr, size);
  261. #endif
  262. memset(zeroes, 0, size);
  263. return spapr_tce_dma_write(dev, taddr, zeroes, size);
  264. }
  265. void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val)
  266. {
  267. spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
  268. }
  269. void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val)
  270. {
  271. val = tswap16(val);
  272. spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
  273. }
  274. void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val)
  275. {
  276. val = tswap32(val);
  277. spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
  278. }
  279. void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val)
  280. {
  281. val = tswap64(val);
  282. spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
  283. }
  284. int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf,
  285. uint32_t size)
  286. {
  287. #ifdef DEBUG_TCE
  288. fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
  289. (unsigned long long)taddr, size);
  290. #endif
  291. /* Check for bypass */
  292. if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
  293. cpu_physical_memory_read(taddr, buf, size);
  294. return 0;
  295. }
  296. while (size) {
  297. uint64_t tce;
  298. uint32_t lsize;
  299. uint64_t txaddr;
  300. /* Check if we are in bound */
  301. if (taddr >= dev->rtce_window_size) {
  302. #ifdef DEBUG_TCE
  303. fprintf(stderr, "spapr_tce_dma_read out of bounds\n");
  304. #endif
  305. return H_DEST_PARM;
  306. }
  307. tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
  308. /* How much til end of page ? */
  309. lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
  310. /* Check TCE */
  311. if (!(tce & 1)) {
  312. return H_DEST_PARM;
  313. }
  314. /* Translate */
  315. txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) |
  316. (taddr & SPAPR_VIO_TCE_PAGE_MASK);
  317. #ifdef DEBUG_TCE
  318. fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
  319. (unsigned long long)txaddr, lsize);
  320. #endif
  321. /* Do it */
  322. cpu_physical_memory_read(txaddr, buf, lsize);
  323. buf += lsize;
  324. taddr += lsize;
  325. size -= lsize;
  326. }
  327. return H_SUCCESS;
  328. }
  329. uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr)
  330. {
  331. uint64_t val;
  332. spapr_tce_dma_read(dev, taddr, &val, sizeof(val));
  333. return tswap64(val);
  334. }
  335. /*
  336. * CRQ handling
  337. */
  338. static target_ulong h_reg_crq(CPUState *env, sPAPREnvironment *spapr,
  339. target_ulong opcode, target_ulong *args)
  340. {
  341. target_ulong reg = args[0];
  342. target_ulong queue_addr = args[1];
  343. target_ulong queue_len = args[2];
  344. VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
  345. if (!dev) {
  346. hcall_dprintf("h_reg_crq on non-existent unit 0x"
  347. TARGET_FMT_lx "\n", reg);
  348. return H_PARAMETER;
  349. }
  350. /* We can't grok a queue size bigger than 256M for now */
  351. if (queue_len < 0x1000 || queue_len > 0x10000000) {
  352. hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n",
  353. (unsigned long long)queue_len);
  354. return H_PARAMETER;
  355. }
  356. /* Check queue alignment */
  357. if (queue_addr & 0xfff) {
  358. hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n",
  359. (unsigned long long)queue_addr);
  360. return H_PARAMETER;
  361. }
  362. /* Check if device supports CRQs */
  363. if (!dev->crq.SendFunc) {
  364. return H_NOT_FOUND;
  365. }
  366. /* Already a queue ? */
  367. if (dev->crq.qsize) {
  368. return H_RESOURCE;
  369. }
  370. dev->crq.qladdr = queue_addr;
  371. dev->crq.qsize = queue_len;
  372. dev->crq.qnext = 0;
  373. dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
  374. TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
  375. reg, queue_addr, queue_len);
  376. return H_SUCCESS;
  377. }
  378. static target_ulong h_free_crq(CPUState *env, sPAPREnvironment *spapr,
  379. target_ulong opcode, target_ulong *args)
  380. {
  381. target_ulong reg = args[0];
  382. VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
  383. if (!dev) {
  384. hcall_dprintf("h_free_crq on non-existent unit 0x"
  385. TARGET_FMT_lx "\n", reg);
  386. return H_PARAMETER;
  387. }
  388. dev->crq.qladdr = 0;
  389. dev->crq.qsize = 0;
  390. dev->crq.qnext = 0;
  391. dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
  392. return H_SUCCESS;
  393. }
  394. static target_ulong h_send_crq(CPUState *env, sPAPREnvironment *spapr,
  395. target_ulong opcode, target_ulong *args)
  396. {
  397. target_ulong reg = args[0];
  398. target_ulong msg_hi = args[1];
  399. target_ulong msg_lo = args[2];
  400. VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
  401. uint64_t crq_mangle[2];
  402. if (!dev) {
  403. hcall_dprintf("h_send_crq on non-existent unit 0x"
  404. TARGET_FMT_lx "\n", reg);
  405. return H_PARAMETER;
  406. }
  407. crq_mangle[0] = cpu_to_be64(msg_hi);
  408. crq_mangle[1] = cpu_to_be64(msg_lo);
  409. if (dev->crq.SendFunc) {
  410. return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
  411. }
  412. return H_HARDWARE;
  413. }
  414. static target_ulong h_enable_crq(CPUState *env, sPAPREnvironment *spapr,
  415. target_ulong opcode, target_ulong *args)
  416. {
  417. target_ulong reg = args[0];
  418. VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
  419. if (!dev) {
  420. hcall_dprintf("h_enable_crq on non-existent unit 0x"
  421. TARGET_FMT_lx "\n", reg);
  422. return H_PARAMETER;
  423. }
  424. return 0;
  425. }
  426. /* Returns negative error, 0 success, or positive: queue full */
  427. int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
  428. {
  429. int rc;
  430. uint8_t byte;
  431. if (!dev->crq.qsize) {
  432. fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
  433. return -1;
  434. }
  435. /* Maybe do a fast path for KVM just writing to the pages */
  436. rc = spapr_tce_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
  437. if (rc) {
  438. return rc;
  439. }
  440. if (byte != 0) {
  441. return 1;
  442. }
  443. rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8,
  444. &crq[8], 8);
  445. if (rc) {
  446. return rc;
  447. }
  448. kvmppc_eieio();
  449. rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
  450. if (rc) {
  451. return rc;
  452. }
  453. dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
  454. if (dev->signal_state & 1) {
  455. qemu_irq_pulse(dev->qirq);
  456. }
  457. return 0;
  458. }
  459. /* "quiesce" handling */
  460. static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
  461. {
  462. dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
  463. if (dev->rtce_table) {
  464. size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
  465. * sizeof(VIOsPAPR_RTCE);
  466. memset(dev->rtce_table, 0, size);
  467. }
  468. dev->crq.qladdr = 0;
  469. dev->crq.qsize = 0;
  470. dev->crq.qnext = 0;
  471. }
  472. static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
  473. uint32_t nargs, target_ulong args,
  474. uint32_t nret, target_ulong rets)
  475. {
  476. VIOsPAPRBus *bus = spapr->vio_bus;
  477. VIOsPAPRDevice *dev;
  478. uint32_t unit, enable;
  479. if (nargs != 2) {
  480. rtas_st(rets, 0, -3);
  481. return;
  482. }
  483. unit = rtas_ld(args, 0);
  484. enable = rtas_ld(args, 1);
  485. dev = spapr_vio_find_by_reg(bus, unit);
  486. if (!dev) {
  487. rtas_st(rets, 0, -3);
  488. return;
  489. }
  490. if (enable) {
  491. dev->flags |= VIO_PAPR_FLAG_DMA_BYPASS;
  492. } else {
  493. dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
  494. }
  495. rtas_st(rets, 0, 0);
  496. }
  497. static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
  498. uint32_t nargs, target_ulong args,
  499. uint32_t nret, target_ulong rets)
  500. {
  501. VIOsPAPRBus *bus = spapr->vio_bus;
  502. DeviceState *qdev;
  503. VIOsPAPRDevice *dev = NULL;
  504. if (nargs != 0) {
  505. rtas_st(rets, 0, -3);
  506. return;
  507. }
  508. QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
  509. dev = (VIOsPAPRDevice *)qdev;
  510. spapr_vio_quiesce_one(dev);
  511. }
  512. rtas_st(rets, 0, 0);
  513. }
  514. static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
  515. {
  516. VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
  517. VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
  518. char *id;
  519. /* Don't overwrite ids assigned on the command line */
  520. if (!dev->qdev.id) {
  521. id = vio_format_dev_name(dev);
  522. if (!id) {
  523. return -1;
  524. }
  525. dev->qdev.id = id;
  526. }
  527. dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num);
  528. if (!dev->qirq) {
  529. return -1;
  530. }
  531. rtce_init(dev);
  532. return info->init(dev);
  533. }
  534. void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
  535. {
  536. info->qdev.init = spapr_vio_busdev_init;
  537. info->qdev.bus_info = &spapr_vio_bus_info;
  538. assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
  539. qdev_register(&info->qdev);
  540. }
  541. static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
  542. target_ulong opcode,
  543. target_ulong *args)
  544. {
  545. target_ulong reg = args[0];
  546. target_ulong mode = args[1];
  547. VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
  548. VIOsPAPRDeviceInfo *info;
  549. if (!dev) {
  550. return H_PARAMETER;
  551. }
  552. info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
  553. if (mode & ~info->signal_mask) {
  554. return H_PARAMETER;
  555. }
  556. dev->signal_state = mode;
  557. return H_SUCCESS;
  558. }
  559. VIOsPAPRBus *spapr_vio_bus_init(void)
  560. {
  561. VIOsPAPRBus *bus;
  562. BusState *qbus;
  563. DeviceState *dev;
  564. DeviceInfo *qinfo;
  565. /* Create bridge device */
  566. dev = qdev_create(NULL, "spapr-vio-bridge");
  567. qdev_init_nofail(dev);
  568. /* Create bus on bridge device */
  569. qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
  570. bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
  571. /* hcall-vio */
  572. spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
  573. /* hcall-tce */
  574. spapr_register_hypercall(H_PUT_TCE, h_put_tce);
  575. /* hcall-crq */
  576. spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
  577. spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
  578. spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
  579. spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
  580. /* RTAS calls */
  581. spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
  582. spapr_rtas_register("quiesce", rtas_quiesce);
  583. for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
  584. VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
  585. if (qinfo->bus_info != &spapr_vio_bus_info) {
  586. continue;
  587. }
  588. if (info->hcalls) {
  589. info->hcalls(bus);
  590. }
  591. }
  592. return bus;
  593. }
  594. /* Represents sPAPR hcall VIO devices */
  595. static int spapr_vio_bridge_init(SysBusDevice *dev)
  596. {
  597. /* nothing */
  598. return 0;
  599. }
  600. static SysBusDeviceInfo spapr_vio_bridge_info = {
  601. .init = spapr_vio_bridge_init,
  602. .qdev.name = "spapr-vio-bridge",
  603. .qdev.size = sizeof(SysBusDevice),
  604. .qdev.no_user = 1,
  605. };
  606. static void spapr_vio_register_devices(void)
  607. {
  608. sysbus_register_withprop(&spapr_vio_bridge_info);
  609. }
  610. device_init(spapr_vio_register_devices)
  611. #ifdef CONFIG_FDT
  612. static int compare_reg(const void *p1, const void *p2)
  613. {
  614. VIOsPAPRDevice const *dev1, *dev2;
  615. dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
  616. dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
  617. if (dev1->reg < dev2->reg) {
  618. return -1;
  619. }
  620. if (dev1->reg == dev2->reg) {
  621. return 0;
  622. }
  623. /* dev1->reg > dev2->reg */
  624. return 1;
  625. }
  626. int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
  627. {
  628. DeviceState *qdev, **qdevs;
  629. int i, num, ret = 0;
  630. /* Count qdevs on the bus list */
  631. num = 0;
  632. QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
  633. num++;
  634. }
  635. /* Copy out into an array of pointers */
  636. qdevs = g_malloc(sizeof(qdev) * num);
  637. num = 0;
  638. QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
  639. qdevs[num++] = qdev;
  640. }
  641. /* Sort the array */
  642. qsort(qdevs, num, sizeof(qdev), compare_reg);
  643. /* Hack alert. Give the devices to libfdt in reverse order, we happen
  644. * to know that will mean they are in forward order in the tree. */
  645. for (i = num - 1; i >= 0; i--) {
  646. VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
  647. ret = vio_make_devnode(dev, fdt);
  648. if (ret < 0) {
  649. goto out;
  650. }
  651. }
  652. ret = 0;
  653. out:
  654. free(qdevs);
  655. return ret;
  656. }
  657. int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
  658. {
  659. VIOsPAPRDevice *dev;
  660. char *name, *path;
  661. int ret, offset;
  662. dev = spapr_vty_get_default(bus);
  663. if (!dev)
  664. return 0;
  665. offset = fdt_path_offset(fdt, "/chosen");
  666. if (offset < 0) {
  667. return offset;
  668. }
  669. name = vio_format_dev_name(dev);
  670. if (!name) {
  671. return -ENOMEM;
  672. }
  673. if (asprintf(&path, "/vdevice/%s", name) < 0) {
  674. path = NULL;
  675. ret = -ENOMEM;
  676. goto out;
  677. }
  678. ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
  679. out:
  680. free(name);
  681. free(path);
  682. return ret;
  683. }
  684. #endif /* CONFIG_FDT */