syborg_virtio.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * Virtio Syborg bindings
  3. *
  4. * Copyright (c) 2009 CodeSourcery
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "syborg.h"
  25. #include "sysbus.h"
  26. #include "virtio.h"
  27. #include "virtio-net.h"
  28. //#define DEBUG_SYBORG_VIRTIO
  29. #ifdef DEBUG_SYBORG_VIRTIO
  30. #define DPRINTF(fmt, ...) \
  31. do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
  32. #define BADF(fmt, ...) \
  33. do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
  34. exit(1);} while (0)
  35. #else
  36. #define DPRINTF(fmt, ...) do {} while(0)
  37. #define BADF(fmt, ...) \
  38. do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
  39. #endif
  40. enum {
  41. SYBORG_VIRTIO_ID = 0,
  42. SYBORG_VIRTIO_DEVTYPE = 1,
  43. SYBORG_VIRTIO_HOST_FEATURES = 2,
  44. SYBORG_VIRTIO_GUEST_FEATURES = 3,
  45. SYBORG_VIRTIO_QUEUE_BASE = 4,
  46. SYBORG_VIRTIO_QUEUE_NUM = 5,
  47. SYBORG_VIRTIO_QUEUE_SEL = 6,
  48. SYBORG_VIRTIO_QUEUE_NOTIFY = 7,
  49. SYBORG_VIRTIO_STATUS = 8,
  50. SYBORG_VIRTIO_INT_ENABLE = 9,
  51. SYBORG_VIRTIO_INT_STATUS = 10
  52. };
  53. #define SYBORG_VIRTIO_CONFIG 0x100
  54. /* Device independent interface. */
  55. typedef struct {
  56. SysBusDevice busdev;
  57. VirtIODevice *vdev;
  58. qemu_irq irq;
  59. uint32_t int_enable;
  60. uint32_t id;
  61. NICConf nic;
  62. uint32_t host_features;
  63. virtio_net_conf net;
  64. } SyborgVirtIOProxy;
  65. static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
  66. {
  67. SyborgVirtIOProxy *s = opaque;
  68. VirtIODevice *vdev = s->vdev;
  69. uint32_t ret;
  70. DPRINTF("readl 0x%x\n", (int)offset);
  71. if (offset >= SYBORG_VIRTIO_CONFIG) {
  72. return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
  73. }
  74. switch(offset >> 2) {
  75. case SYBORG_VIRTIO_ID:
  76. ret = SYBORG_ID_VIRTIO;
  77. break;
  78. case SYBORG_VIRTIO_DEVTYPE:
  79. ret = s->id;
  80. break;
  81. case SYBORG_VIRTIO_HOST_FEATURES:
  82. ret = s->host_features;
  83. break;
  84. case SYBORG_VIRTIO_GUEST_FEATURES:
  85. ret = vdev->guest_features;
  86. break;
  87. case SYBORG_VIRTIO_QUEUE_BASE:
  88. ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
  89. break;
  90. case SYBORG_VIRTIO_QUEUE_NUM:
  91. ret = virtio_queue_get_num(vdev, vdev->queue_sel);
  92. break;
  93. case SYBORG_VIRTIO_QUEUE_SEL:
  94. ret = vdev->queue_sel;
  95. break;
  96. case SYBORG_VIRTIO_STATUS:
  97. ret = vdev->status;
  98. break;
  99. case SYBORG_VIRTIO_INT_ENABLE:
  100. ret = s->int_enable;
  101. break;
  102. case SYBORG_VIRTIO_INT_STATUS:
  103. ret = vdev->isr;
  104. break;
  105. default:
  106. BADF("Bad read offset 0x%x\n", (int)offset);
  107. return 0;
  108. }
  109. return ret;
  110. }
  111. static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
  112. uint32_t value)
  113. {
  114. SyborgVirtIOProxy *s = opaque;
  115. VirtIODevice *vdev = s->vdev;
  116. DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
  117. if (offset >= SYBORG_VIRTIO_CONFIG) {
  118. return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
  119. value);
  120. }
  121. switch (offset >> 2) {
  122. case SYBORG_VIRTIO_GUEST_FEATURES:
  123. virtio_set_features(vdev, value);
  124. break;
  125. case SYBORG_VIRTIO_QUEUE_BASE:
  126. if (value == 0)
  127. virtio_reset(vdev);
  128. else
  129. virtio_queue_set_addr(vdev, vdev->queue_sel, value);
  130. break;
  131. case SYBORG_VIRTIO_QUEUE_SEL:
  132. if (value < VIRTIO_PCI_QUEUE_MAX)
  133. vdev->queue_sel = value;
  134. break;
  135. case SYBORG_VIRTIO_QUEUE_NOTIFY:
  136. if (value < VIRTIO_PCI_QUEUE_MAX) {
  137. virtio_queue_notify(vdev, value);
  138. }
  139. break;
  140. case SYBORG_VIRTIO_STATUS:
  141. virtio_set_status(vdev, value & 0xFF);
  142. if (vdev->status == 0)
  143. virtio_reset(vdev);
  144. break;
  145. case SYBORG_VIRTIO_INT_ENABLE:
  146. s->int_enable = value;
  147. virtio_update_irq(vdev);
  148. break;
  149. case SYBORG_VIRTIO_INT_STATUS:
  150. vdev->isr &= ~value;
  151. virtio_update_irq(vdev);
  152. break;
  153. default:
  154. BADF("Bad write offset 0x%x\n", (int)offset);
  155. break;
  156. }
  157. }
  158. static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
  159. {
  160. SyborgVirtIOProxy *s = opaque;
  161. VirtIODevice *vdev = s->vdev;
  162. DPRINTF("readw 0x%x\n", (int)offset);
  163. if (offset >= SYBORG_VIRTIO_CONFIG) {
  164. return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
  165. }
  166. BADF("Bad halfword read offset 0x%x\n", (int)offset);
  167. return -1;
  168. }
  169. static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
  170. uint32_t value)
  171. {
  172. SyborgVirtIOProxy *s = opaque;
  173. VirtIODevice *vdev = s->vdev;
  174. DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
  175. if (offset >= SYBORG_VIRTIO_CONFIG) {
  176. return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
  177. value);
  178. }
  179. BADF("Bad halfword write offset 0x%x\n", (int)offset);
  180. }
  181. static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
  182. {
  183. SyborgVirtIOProxy *s = opaque;
  184. VirtIODevice *vdev = s->vdev;
  185. DPRINTF("readb 0x%x\n", (int)offset);
  186. if (offset >= SYBORG_VIRTIO_CONFIG) {
  187. return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
  188. }
  189. BADF("Bad byte read offset 0x%x\n", (int)offset);
  190. return -1;
  191. }
  192. static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
  193. uint32_t value)
  194. {
  195. SyborgVirtIOProxy *s = opaque;
  196. VirtIODevice *vdev = s->vdev;
  197. DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
  198. if (offset >= SYBORG_VIRTIO_CONFIG) {
  199. return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
  200. value);
  201. }
  202. BADF("Bad byte write offset 0x%x\n", (int)offset);
  203. }
  204. static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
  205. syborg_virtio_readb,
  206. syborg_virtio_readw,
  207. syborg_virtio_readl
  208. };
  209. static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
  210. syborg_virtio_writeb,
  211. syborg_virtio_writew,
  212. syborg_virtio_writel
  213. };
  214. static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
  215. {
  216. SyborgVirtIOProxy *proxy = opaque;
  217. int level;
  218. level = proxy->int_enable & proxy->vdev->isr;
  219. DPRINTF("IRQ %d\n", level);
  220. qemu_set_irq(proxy->irq, level != 0);
  221. }
  222. static unsigned syborg_virtio_get_features(void *opaque)
  223. {
  224. SyborgVirtIOProxy *proxy = opaque;
  225. return proxy->host_features;
  226. }
  227. static VirtIOBindings syborg_virtio_bindings = {
  228. .notify = syborg_virtio_update_irq,
  229. .get_features = syborg_virtio_get_features,
  230. };
  231. static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
  232. {
  233. int iomemtype;
  234. proxy->vdev = vdev;
  235. /* Don't support multiple vectors */
  236. proxy->vdev->nvectors = 0;
  237. sysbus_init_irq(&proxy->busdev, &proxy->irq);
  238. iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
  239. syborg_virtio_writefn, proxy,
  240. DEVICE_NATIVE_ENDIAN);
  241. sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
  242. proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
  243. qemu_register_reset(virtio_reset, vdev);
  244. virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
  245. proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
  246. proxy->host_features = vdev->get_features(vdev, proxy->host_features);
  247. return 0;
  248. }
  249. /* Device specific bindings. */
  250. static int syborg_virtio_net_init(SysBusDevice *dev)
  251. {
  252. VirtIODevice *vdev;
  253. SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
  254. vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
  255. return syborg_virtio_init(proxy, vdev);
  256. }
  257. static SysBusDeviceInfo syborg_virtio_net_info = {
  258. .init = syborg_virtio_net_init,
  259. .qdev.name = "syborg,virtio-net",
  260. .qdev.size = sizeof(SyborgVirtIOProxy),
  261. .qdev.props = (Property[]) {
  262. DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
  263. DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
  264. DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
  265. net.txtimer, TX_TIMER_INTERVAL),
  266. DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
  267. net.txburst, TX_BURST),
  268. DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
  269. DEFINE_PROP_END_OF_LIST(),
  270. }
  271. };
  272. static void syborg_virtio_register_devices(void)
  273. {
  274. sysbus_register_withprop(&syborg_virtio_net_info);
  275. }
  276. device_init(syborg_virtio_register_devices)