virtio-net.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * libqos driver framework
  3. *
  4. * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License version 2.1 as published by the Free Software Foundation.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, see <http://www.gnu.org/licenses/>
  17. */
  18. #include "qemu/osdep.h"
  19. #include "../libqtest.h"
  20. #include "qemu/module.h"
  21. #include "qgraph.h"
  22. #include "virtio-net.h"
  23. #include "hw/virtio/virtio-net.h"
  24. static QGuestAllocator *alloc;
  25. static void virtio_net_cleanup(QVirtioNet *interface)
  26. {
  27. int i;
  28. for (i = 0; i < interface->n_queues; i++) {
  29. qvirtqueue_cleanup(interface->vdev->bus, interface->queues[i], alloc);
  30. }
  31. g_free(interface->queues);
  32. }
  33. static void virtio_net_setup(QVirtioNet *interface)
  34. {
  35. QVirtioDevice *vdev = interface->vdev;
  36. uint64_t features;
  37. int i;
  38. features = qvirtio_get_features(vdev);
  39. features &= ~(QVIRTIO_F_BAD_FEATURE |
  40. (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
  41. (1ull << VIRTIO_RING_F_EVENT_IDX));
  42. qvirtio_set_features(vdev, features);
  43. if (features & (1ull << VIRTIO_NET_F_MQ)) {
  44. interface->n_queues = qvirtio_config_readw(vdev, 8) * 2;
  45. } else {
  46. interface->n_queues = 2;
  47. }
  48. interface->n_queues++; /* Account for the ctrl queue */
  49. interface->queues = g_new(QVirtQueue *, interface->n_queues);
  50. for (i = 0; i < interface->n_queues; i++) {
  51. interface->queues[i] = qvirtqueue_setup(vdev, alloc, i);
  52. }
  53. qvirtio_set_driver_ok(vdev);
  54. }
  55. /* virtio-net-device */
  56. static void qvirtio_net_device_destructor(QOSGraphObject *obj)
  57. {
  58. QVirtioNetDevice *v_net = (QVirtioNetDevice *) obj;
  59. virtio_net_cleanup(&v_net->net);
  60. }
  61. static void qvirtio_net_device_start_hw(QOSGraphObject *obj)
  62. {
  63. QVirtioNetDevice *v_net = (QVirtioNetDevice *) obj;
  64. QVirtioNet *interface = &v_net->net;
  65. virtio_net_setup(interface);
  66. }
  67. static void *qvirtio_net_get_driver(QVirtioNet *v_net,
  68. const char *interface)
  69. {
  70. if (!g_strcmp0(interface, "virtio-net")) {
  71. return v_net;
  72. }
  73. if (!g_strcmp0(interface, "virtio")) {
  74. return v_net->vdev;
  75. }
  76. fprintf(stderr, "%s not present in virtio-net-device\n", interface);
  77. g_assert_not_reached();
  78. }
  79. static void *qvirtio_net_device_get_driver(void *object,
  80. const char *interface)
  81. {
  82. QVirtioNetDevice *v_net = object;
  83. return qvirtio_net_get_driver(&v_net->net, interface);
  84. }
  85. static void *virtio_net_device_create(void *virtio_dev,
  86. QGuestAllocator *t_alloc,
  87. void *addr)
  88. {
  89. QVirtioNetDevice *virtio_ndevice = g_new0(QVirtioNetDevice, 1);
  90. QVirtioNet *interface = &virtio_ndevice->net;
  91. interface->vdev = virtio_dev;
  92. alloc = t_alloc;
  93. virtio_ndevice->obj.destructor = qvirtio_net_device_destructor;
  94. virtio_ndevice->obj.get_driver = qvirtio_net_device_get_driver;
  95. virtio_ndevice->obj.start_hw = qvirtio_net_device_start_hw;
  96. return &virtio_ndevice->obj;
  97. }
  98. /* virtio-net-pci */
  99. static void qvirtio_net_pci_destructor(QOSGraphObject *obj)
  100. {
  101. QVirtioNetPCI *v_net = (QVirtioNetPCI *) obj;
  102. QVirtioNet *interface = &v_net->net;
  103. QOSGraphObject *pci_vobj = &v_net->pci_vdev.obj;
  104. virtio_net_cleanup(interface);
  105. qvirtio_pci_destructor(pci_vobj);
  106. }
  107. static void qvirtio_net_pci_start_hw(QOSGraphObject *obj)
  108. {
  109. QVirtioNetPCI *v_net = (QVirtioNetPCI *) obj;
  110. QVirtioNet *interface = &v_net->net;
  111. QOSGraphObject *pci_vobj = &v_net->pci_vdev.obj;
  112. qvirtio_pci_start_hw(pci_vobj);
  113. virtio_net_setup(interface);
  114. }
  115. static void *qvirtio_net_pci_get_driver(void *object,
  116. const char *interface)
  117. {
  118. QVirtioNetPCI *v_net = object;
  119. if (!g_strcmp0(interface, "pci-device")) {
  120. return v_net->pci_vdev.pdev;
  121. }
  122. return qvirtio_net_get_driver(&v_net->net, interface);
  123. }
  124. static void *virtio_net_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
  125. void *addr)
  126. {
  127. QVirtioNetPCI *virtio_bpci = g_new0(QVirtioNetPCI, 1);
  128. QVirtioNet *interface = &virtio_bpci->net;
  129. QOSGraphObject *obj = &virtio_bpci->pci_vdev.obj;
  130. virtio_pci_init(&virtio_bpci->pci_vdev, pci_bus, addr);
  131. interface->vdev = &virtio_bpci->pci_vdev.vdev;
  132. alloc = t_alloc;
  133. g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_NET);
  134. obj->destructor = qvirtio_net_pci_destructor;
  135. obj->start_hw = qvirtio_net_pci_start_hw;
  136. obj->get_driver = qvirtio_net_pci_get_driver;
  137. return obj;
  138. }
  139. static void virtio_net_register_nodes(void)
  140. {
  141. /* FIXME: every test using these nodes needs to setup a
  142. * -netdev socket,id=hs0 otherwise QEMU is not going to start.
  143. * Therefore, we do not include "produces" edge for virtio
  144. * and pci-device yet.
  145. */
  146. QPCIAddress addr = {
  147. .devfn = QPCI_DEVFN(4, 0),
  148. };
  149. QOSGraphEdgeOptions opts = { };
  150. /* virtio-net-device */
  151. opts.extra_device_opts = "netdev=hs0";
  152. qos_node_create_driver("virtio-net-device",
  153. virtio_net_device_create);
  154. qos_node_consumes("virtio-net-device", "virtio-bus", &opts);
  155. qos_node_produces("virtio-net-device", "virtio-net");
  156. /* virtio-net-pci */
  157. opts.extra_device_opts = "netdev=hs0,addr=04.0";
  158. add_qpci_address(&opts, &addr);
  159. qos_node_create_driver("virtio-net-pci", virtio_net_pci_create);
  160. qos_node_consumes("virtio-net-pci", "pci-bus", &opts);
  161. qos_node_produces("virtio-net-pci", "virtio-net");
  162. }
  163. libqos_init(virtio_net_register_nodes);