From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1IzhVt-0005YH-CB for qemu-devel@nongnu.org; Tue, 04 Dec 2007 18:49:17 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1IzhVs-0005WD-OQ for qemu-devel@nongnu.org; Tue, 04 Dec 2007 18:49:16 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1IzhVs-0005Vd-8U for qemu-devel@nongnu.org; Tue, 04 Dec 2007 18:49:16 -0500 Received: from ug-out-1314.google.com ([66.249.92.168]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1IzhVr-0008DQ-Ho for qemu-devel@nongnu.org; Tue, 04 Dec 2007 18:49:15 -0500 Received: by ug-out-1314.google.com with SMTP id m2so227701uge for ; Tue, 04 Dec 2007 15:49:13 -0800 (PST) Message-ID: <4755E774.8090408@qumranet.com> Date: Wed, 05 Dec 2007 01:49:08 +0200 MIME-Version: 1.0 References: <4755CC8C.6000001@us.ibm.com> In-Reply-To: <4755CC8C.6000001@us.ibm.com> Content-Type: multipart/alternative; boundary="------------020204070004080402060608" From: Dor Laor Subject: [Qemu-devel] Re: [PATCH 2/3] virtio network device Reply-To: dor.laor@qumranet.com, qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori Cc: Rusty Russell , qemu-devel@nongnu.org This is a multi-part message in MIME format. --------------020204070004080402060608 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Anthony Liguori wrote: Index: qemu/hw/virtio-net.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/hw/virtio-net.c 2007-12-04 14:17:37.000000000 -0600 + +static void virtio_net_receive(void *opaque, const uint8_t *buf, int size) +{ + VirtIONet *n = opaque; + VirtQueueElement elem; + struct virtio_net_hdr *hdr; + int offset, i; + + /* FIXME: the drivers really need to set their status better */ + if (n->rx_vq->vring.avail == NULL) { + n->can_receive = 0; + return; + } + + if (virtqueue_pop(n->rx_vq, &elem) == 0) { + /* wait until the guest adds some rx bufs */ + n->can_receive = 0; + return; + } + + hdr = (void *)elem.in_sg[0].iov_base; + hdr->flags = 0; + hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; + + /* copy in packet. ugh */ + offset = 0; + i = 1; + while (offset < size && i < elem.in_num) { + int len = MIN(elem.in_sg[i].iov_len, size - offset); + memcpy(elem.in_sg[i].iov_base, buf + offset, len); Actually according to qemu's standard, one should use cpu_physical_memory_write/ cpu_physical_memory_read functions. This is true also for reading the ring values. + offset += len; + i++; + } + + /* signal other side */ + virtqueue_push(n->rx_vq, &elem, sizeof(*hdr) + offset); + virtio_notify(&n->vdev, n->rx_vq); +} + +/* TX */ +static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIONet *n = to_virtio_net(vdev); + VirtQueueElement elem; + + while (virtqueue_pop(vq, &elem)) { + int i; + size_t len = 0; + + /* ignore the header for now */ + for (i = 1; i < elem.out_num; i++) { + qemu_send_packet(n->vc, elem.out_sg[i].iov_base, + elem.out_sg[i].iov_len); + len += elem.out_sg[i].iov_len; + } + + virtqueue_push(vq, &elem, sizeof(struct virtio_net_hdr) + len); + virtio_notify(&n->vdev, vq); + } The virtio_notify should be left out of the while loop to minimize irq injection. +} + +void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) +{ + VirtIONet *n; + + n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000, + 0, VIRTIO_ID_NET, + 0x02, 0x00, 0x00, + 6, sizeof(VirtIONet)); + + n->vdev.update_config = virtio_net_update_config; + n->vdev.get_features = virtio_net_get_features; + n->rx_vq = virtio_add_queue(&n->vdev, 512, virtio_net_handle_rx); + n->tx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_tx); + n->can_receive = 0; + memcpy(n->mac, nd->macaddr, 6); + n->vc = qemu_new_vlan_client(nd->vlan, virtio_net_receive, + virtio_net_can_receive, n); + + return &n->vdev; +} Index: qemu/hw/pc.h =================================================================== --- qemu.orig/hw/pc.h 2007-12-04 14:15:20.000000000 -0600 +++ qemu/hw/pc.h 2007-12-04 14:43:57.000000000 -0600 @@ -142,4 +142,9 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd); +/* virtio-net.c */ + +void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn); + + #endif --------------020204070004080402060608 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Anthony Liguori wrote:
Index: qemu/hw/virtio-net.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu/hw/virtio-net.c	2007-12-04 14:17:37.000000000 -0600

+
+static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
+{
+    VirtIONet *n = opaque;
+    VirtQueueElement elem;
+    struct virtio_net_hdr *hdr;
+    int offset, i;
+
+    /* FIXME: the drivers really need to set their status better */
+    if (n->rx_vq->vring.avail == NULL) {
+	n->can_receive = 0;
+	return;
+    }
+
+    if (virtqueue_pop(n->rx_vq, &elem) == 0) {
+	/* wait until the guest adds some rx bufs */
+	n->can_receive = 0;
+	return;
+    }
+
+    hdr = (void *)elem.in_sg[0].iov_base;
+    hdr->flags = 0;
+    hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+    /* copy in packet.  ugh */
+    offset = 0;
+    i = 1;
+    while (offset < size && i < elem.in_num) {
+	int len = MIN(elem.in_sg[i].iov_len, size - offset);
+	memcpy(elem.in_sg[i].iov_base, buf + offset, len);



Actually according to qemu's standard, one should use cpu_physical_memory_write/
cpu_physical_memory_read functions.
This is true also for reading the ring values.




+	offset += len;
+	i++;
+    }
+
+    /* signal other side */
+    virtqueue_push(n->rx_vq, &elem, sizeof(*hdr) + offset);
+    virtio_notify(&n->vdev, n->rx_vq);
+}
+
+/* TX */
+static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    VirtQueueElement elem;
+
+    while (virtqueue_pop(vq, &elem)) {
+	int i;
+	size_t len = 0;
+
+	/* ignore the header for now */
+	for (i = 1; i < elem.out_num; i++) {
+	    qemu_send_packet(n->vc, elem.out_sg[i].iov_base,
+			     elem.out_sg[i].iov_len);
+	    len += elem.out_sg[i].iov_len;
+	}
+
+	virtqueue_push(vq, &elem, sizeof(struct virtio_net_hdr) + len);
+	virtio_notify(&n->vdev, vq);
+    }


The virtio_notify should be left out of the while loop to minimize 
irq injection.


+}
+
+void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
+{
+    VirtIONet *n;
+
+    n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000,
+				     0, VIRTIO_ID_NET,
+				     0x02, 0x00, 0x00,
+				     6, sizeof(VirtIONet));
+
+    n->vdev.update_config = virtio_net_update_config;
+    n->vdev.get_features = virtio_net_get_features;
+    n->rx_vq = virtio_add_queue(&n->vdev, 512, virtio_net_handle_rx);
+    n->tx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_tx);
+    n->can_receive = 0;
+    memcpy(n->mac, nd->macaddr, 6);
+    n->vc = qemu_new_vlan_client(nd->vlan, virtio_net_receive,
+				 virtio_net_can_receive, n);
+
+    return &n->vdev;
+}
Index: qemu/hw/pc.h
===================================================================
--- qemu.orig/hw/pc.h	2007-12-04 14:15:20.000000000 -0600
+++ qemu/hw/pc.h	2007-12-04 14:43:57.000000000 -0600
@@ -142,4 +142,9 @@
 
 void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd);
 
+/* virtio-net.c */
+
+void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
+
+
 #endif
--------------020204070004080402060608--