syborg_virtio.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. if (vdev->set_features)
  124. vdev->set_features(vdev, value);
  125. vdev->guest_features = value;
  126. break;
  127. case SYBORG_VIRTIO_QUEUE_BASE:
  128. if (value == 0)
  129. virtio_reset(vdev);
  130. else
  131. virtio_queue_set_addr(vdev, vdev->queue_sel, value);
  132. break;
  133. case SYBORG_VIRTIO_QUEUE_SEL:
  134. if (value < VIRTIO_PCI_QUEUE_MAX)
  135. vdev->queue_sel = value;
  136. break;
  137. case SYBORG_VIRTIO_QUEUE_NOTIFY:
  138. if (value < VIRTIO_PCI_QUEUE_MAX) {
  139. virtio_queue_notify(vdev, value);
  140. }
  141. break;
  142. case SYBORG_VIRTIO_STATUS:
  143. virtio_set_status(vdev, value & 0xFF);
  144. if (vdev->status == 0)
  145. virtio_reset(vdev);
  146. break;
  147. case SYBORG_VIRTIO_INT_ENABLE:
  148. s->int_enable = value;
  149. virtio_update_irq(vdev);
  150. break;
  151. case SYBORG_VIRTIO_INT_STATUS:
  152. vdev->isr &= ~value;
  153. virtio_update_irq(vdev);
  154. break;
  155. default:
  156. BADF("Bad write offset 0x%x\n", (int)offset);
  157. break;
  158. }
  159. }
  160. static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
  161. {
  162. SyborgVirtIOProxy *s = opaque;
  163. VirtIODevice *vdev = s->vdev;
  164. DPRINTF("readw 0x%x\n", (int)offset);
  165. if (offset >= SYBORG_VIRTIO_CONFIG) {
  166. return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
  167. }
  168. BADF("Bad halfword read offset 0x%x\n", (int)offset);
  169. return -1;
  170. }
  171. static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
  172. uint32_t value)
  173. {
  174. SyborgVirtIOProxy *s = opaque;
  175. VirtIODevice *vdev = s->vdev;
  176. DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
  177. if (offset >= SYBORG_VIRTIO_CONFIG) {
  178. return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
  179. value);
  180. }
  181. BADF("Bad halfword write offset 0x%x\n", (int)offset);
  182. }
  183. static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
  184. {
  185. SyborgVirtIOProxy *s = opaque;
  186. VirtIODevice *vdev = s->vdev;
  187. DPRINTF("readb 0x%x\n", (int)offset);
  188. if (offset >= SYBORG_VIRTIO_CONFIG) {
  189. return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
  190. }
  191. BADF("Bad byte read offset 0x%x\n", (int)offset);
  192. return -1;
  193. }
  194. static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
  195. uint32_t value)
  196. {
  197. SyborgVirtIOProxy *s = opaque;
  198. VirtIODevice *vdev = s->vdev;
  199. DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
  200. if (offset >= SYBORG_VIRTIO_CONFIG) {
  201. return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
  202. value);
  203. }
  204. BADF("Bad byte write offset 0x%x\n", (int)offset);
  205. }
  206. static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
  207. syborg_virtio_readb,
  208. syborg_virtio_readw,
  209. syborg_virtio_readl
  210. };
  211. static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
  212. syborg_virtio_writeb,
  213. syborg_virtio_writew,
  214. syborg_virtio_writel
  215. };
  216. static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
  217. {
  218. SyborgVirtIOProxy *proxy = opaque;
  219. int level;
  220. level = proxy->int_enable & proxy->vdev->isr;
  221. DPRINTF("IRQ %d\n", level);
  222. qemu_set_irq(proxy->irq, level != 0);
  223. }
  224. static unsigned syborg_virtio_get_features(void *opaque)
  225. {
  226. SyborgVirtIOProxy *proxy = opaque;
  227. return proxy->host_features;
  228. }
  229. static VirtIOBindings syborg_virtio_bindings = {
  230. .notify = syborg_virtio_update_irq,
  231. .get_features = syborg_virtio_get_features,
  232. };
  233. static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
  234. {
  235. int iomemtype;
  236. proxy->vdev = vdev;
  237. /* Don't support multiple vectors */
  238. proxy->vdev->nvectors = 0;
  239. sysbus_init_irq(&proxy->busdev, &proxy->irq);
  240. iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
  241. syborg_virtio_writefn, proxy,
  242. DEVICE_NATIVE_ENDIAN);
  243. sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
  244. proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
  245. qemu_register_reset(virtio_reset, vdev);
  246. virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
  247. proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
  248. proxy->host_features = vdev->get_features(vdev, proxy->host_features);
  249. return 0;
  250. }
  251. /* Device specific bindings. */
  252. static int syborg_virtio_net_init(SysBusDevice *dev)
  253. {
  254. VirtIODevice *vdev;
  255. SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
  256. vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
  257. return syborg_virtio_init(proxy, vdev);
  258. }
  259. static SysBusDeviceInfo syborg_virtio_net_info = {
  260. .init = syborg_virtio_net_init,
  261. .qdev.name = "syborg,virtio-net",
  262. .qdev.size = sizeof(SyborgVirtIOProxy),
  263. .qdev.props = (Property[]) {
  264. DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
  265. DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
  266. DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
  267. net.txtimer, TX_TIMER_INTERVAL),
  268. DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
  269. net.txburst, TX_BURST),
  270. DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
  271. DEFINE_PROP_END_OF_LIST(),
  272. }
  273. };
  274. static void syborg_virtio_register_devices(void)
  275. {
  276. sysbus_register_withprop(&syborg_virtio_net_info);
  277. }
  278. device_init(syborg_virtio_register_devices)