From patchwork Wed Apr 6 12:40:24 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 65179 Delivered-To: patch@linaro.org Received: by 10.112.199.169 with SMTP id jl9csp1027781lbc; Wed, 6 Apr 2016 05:41:26 -0700 (PDT) X-Received: by 10.66.174.134 with SMTP id bs6mr33585993pac.53.1459946470947; Wed, 06 Apr 2016 05:41:10 -0700 (PDT) Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id r7si4433703pfa.99.2016.04.06.05.41.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Apr 2016 05:41:10 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 6DA971A1FD7; Wed, 6 Apr 2016 05:40:59 -0700 (PDT) X-Original-To: edk2-devel@ml01.01.org Delivered-To: edk2-devel@ml01.01.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D29B71A1FC6 for ; Wed, 6 Apr 2016 05:40:58 -0700 (PDT) Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4C4E5164C6F; Wed, 6 Apr 2016 12:40:58 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com ([10.3.113.15]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u36CeV8Z027635; Wed, 6 Apr 2016 08:40:56 -0400 From: Laszlo Ersek To: edk2-devel-01 Date: Wed, 6 Apr 2016 14:40:24 +0200 Message-Id: <1459946427-15771-15-git-send-email-lersek@redhat.com> In-Reply-To: <1459946427-15771-1-git-send-email-lersek@redhat.com> References: <1459946427-15771-1-git-send-email-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Wed, 06 Apr 2016 12:40:58 +0000 (UTC) Subject: [edk2] [wave 3 PATCH v2 14/17] OvmfPkg: VirtioNetDxe: adapt virtio-net packet header size to virtio-1.0 X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Jordan Justen , Ard Biesheuvel MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" In virtio-0.9.5, the size of the virtio-net packet header depends on whether the VIRTIO_NET_F_MRG_RXBUF feature is negotiated -- the "num_buffers" field is only appended to the header if the feature is negotiated. Since we never negotiate this feature, VirtioNetDxe never allocates room for the "num_buffers" field. With virtio-1.0, the "num_buffers" field is always there (although it doesn't carry useful information without VIRTIO_NET_F_MRG_RXBUF). Adapt the buffers that depend on the virtio-net header size (otherwise we have skewed / truncated packets). Cc: Ard Biesheuvel Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Tested-by: Ard Biesheuvel Reviewed-by: Jordan Justen --- Notes: v2: - rename the "Legacy" field in VIRTIO_1_0_NET_REQ to "V0_9_5" [Jordan] - no need to include explicitly, exposes all versions [Jordan] OvmfPkg/VirtioNetDxe/VirtioNet.h | 2 +- OvmfPkg/VirtioNetDxe/SnpInitialize.c | 36 ++++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) -- 1.8.3.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h index 2d3f3d87eb11..710859bc6115 100644 --- a/OvmfPkg/VirtioNetDxe/VirtioNet.h +++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h @@ -85,15 +85,15 @@ typedef struct { UINT8 *RxBuf; // VirtioNetInitRx UINT16 RxLastUsed; // VirtioNetInitRx VRING TxRing; // VirtioNetInitRing UINT16 TxMaxPending; // VirtioNetInitTx UINT16 TxCurPending; // VirtioNetInitTx UINT16 *TxFreeStack; // VirtioNetInitTx - VIRTIO_NET_REQ TxSharedReq; // VirtioNetInitTx + VIRTIO_1_0_NET_REQ TxSharedReq; // VirtioNetInitTx UINT16 TxLastUsed; // VirtioNetInitTx } VNET_DEV; // // In order to avoid duplication of interface documentation, please find all // leading comments near the respective function / variable definitions (not diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c b/OvmfPkg/VirtioNetDxe/SnpInitialize.c index 38012a0df8d6..430670a980f2 100644 --- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c +++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c @@ -134,52 +134,66 @@ ReleaseQueue: STATIC EFI_STATUS EFIAPI VirtioNetInitTx ( IN OUT VNET_DEV *Dev ) { + UINTN TxSharedReqSize; UINTN PktIdx; Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2, VNET_MAX_PENDING); Dev->TxCurPending = 0; Dev->TxFreeStack = AllocatePool (Dev->TxMaxPending * sizeof *Dev->TxFreeStack); if (Dev->TxFreeStack == NULL) { return EFI_OUT_OF_RESOURCES; } + // + // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on + // VIRTIO_NET_F_MRG_RXBUF, which we never negotiate. + // + TxSharedReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ? + sizeof Dev->TxSharedReq.V0_9_5 : + sizeof Dev->TxSharedReq; + for (PktIdx = 0; PktIdx < Dev->TxMaxPending; ++PktIdx) { UINT16 DescIdx; DescIdx = (UINT16) (2 * PktIdx); Dev->TxFreeStack[PktIdx] = DescIdx; // // For each possibly pending packet, lay out the descriptor for the common // (unmodified by the host) virtio-net request header. // Dev->TxRing.Desc[DescIdx].Addr = (UINTN) &Dev->TxSharedReq; - Dev->TxRing.Desc[DescIdx].Len = sizeof Dev->TxSharedReq; + Dev->TxRing.Desc[DescIdx].Len = (UINT32) TxSharedReqSize; Dev->TxRing.Desc[DescIdx].Flags = VRING_DESC_F_NEXT; Dev->TxRing.Desc[DescIdx].Next = (UINT16) (DescIdx + 1); // // The second descriptor of each pending TX packet is updated on the fly, // but it always terminates the descriptor chain of the packet. // Dev->TxRing.Desc[DescIdx + 1].Flags = 0; } // // virtio-0.9.5, Appendix C, Packet Transmission // - Dev->TxSharedReq.Flags = 0; - Dev->TxSharedReq.GsoType = VIRTIO_NET_HDR_GSO_NONE; + Dev->TxSharedReq.V0_9_5.Flags = 0; + Dev->TxSharedReq.V0_9_5.GsoType = VIRTIO_NET_HDR_GSO_NONE; + + // + // For VirtIo 1.0 only -- the field exists, but it is unused + // + Dev->TxSharedReq.NumBuffers = 0; // // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device // MemoryFence (); Dev->TxLastUsed = *Dev->TxRing.Used.Idx; ASSERT (Dev->TxLastUsed == 0); @@ -219,27 +233,36 @@ STATIC EFI_STATUS EFIAPI VirtioNetInitRx ( IN OUT VNET_DEV *Dev ) { EFI_STATUS Status; + UINTN VirtioNetReqSize; UINTN RxBufSize; UINT16 RxAlwaysPending; UINTN PktIdx; UINT16 DescIdx; UINT8 *RxPtr; // + // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on + // VIRTIO_NET_F_MRG_RXBUF, which we never negotiate. + // + VirtioNetReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ? + sizeof (VIRTIO_NET_REQ) : + sizeof (VIRTIO_1_0_NET_REQ); + + // // For each incoming packet we must supply two descriptors: // - the recipient for the virtio-net request header, plus // - the recipient for the network data (which consists of Ethernet header // and Ethernet payload). // - RxBufSize = sizeof (VIRTIO_NET_REQ) + + RxBufSize = VirtioNetReqSize + (Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize); // // Limit the number of pending RX packets if the queue is big. The division // by two is due to the above "two descriptors per packet" trait. // RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING); @@ -276,22 +299,21 @@ VirtioNetInitRx ( // Dev->RxRing.Avail.Ring[PktIdx] = DescIdx; // // virtio-0.9.5, 2.4.1.1 Placing Buffers into the Descriptor Table // Dev->RxRing.Desc[DescIdx].Addr = (UINTN) RxPtr; - Dev->RxRing.Desc[DescIdx].Len = sizeof (VIRTIO_NET_REQ); + Dev->RxRing.Desc[DescIdx].Len = (UINT32) VirtioNetReqSize; Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT; Dev->RxRing.Desc[DescIdx].Next = (UINT16) (DescIdx + 1); RxPtr += Dev->RxRing.Desc[DescIdx++].Len; Dev->RxRing.Desc[DescIdx].Addr = (UINTN) RxPtr; - Dev->RxRing.Desc[DescIdx].Len = (UINT32) (RxBufSize - - sizeof (VIRTIO_NET_REQ)); + Dev->RxRing.Desc[DescIdx].Len = (UINT32) (RxBufSize - VirtioNetReqSize); Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE; RxPtr += Dev->RxRing.Desc[DescIdx++].Len; } // // virtio-0.9.5, 2.4.1.3 Updating the Index Field //