From owner-svn-src-all@freebsd.org Wed Feb 5 20:39:18 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id E6D3222D7DF; Wed, 5 Feb 2020 20:39:18 +0000 (UTC) (envelope-from alfredo@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 48CYMB5nRmz46wY; Wed, 5 Feb 2020 20:39:18 +0000 (UTC) (envelope-from alfredo@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id C1EA186F3; Wed, 5 Feb 2020 20:39:18 +0000 (UTC) (envelope-from alfredo@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 015KdIdB002025; Wed, 5 Feb 2020 20:39:18 GMT (envelope-from alfredo@FreeBSD.org) Received: (from alfredo@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 015KdIZt002024; Wed, 5 Feb 2020 20:39:18 GMT (envelope-from alfredo@FreeBSD.org) Message-Id: <202002052039.015KdIZt002024@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: alfredo set sender to alfredo@FreeBSD.org using -f From: "Alfredo Dal'Ava Junior" Date: Wed, 5 Feb 2020 20:39:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r357596 - head/sys/dev/virtio/pci X-SVN-Group: head X-SVN-Commit-Author: alfredo X-SVN-Commit-Paths: head/sys/dev/virtio/pci X-SVN-Commit-Revision: 357596 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Feb 2020 20:39:19 -0000 Author: alfredo Date: Wed Feb 5 20:39:18 2020 New Revision: 357596 URL: https://svnweb.freebsd.org/changeset/base/357596 Log: [virtio] Fix r/w to PCI configuration area on big endian platforms In legacy VirtIO drivers, the header must be PCI endianness (little) and the device-specific region is encoded in the native endian of the guest. This patch makes the access (read/write) to VirtIO header using the little endian order. Other read and write access are native endianness. This also sets the device's IO region as big endian if on big endian machine. PR: 205178 Submitted by: Andre Silva Reported by: Kenneth Salerno Reviewed by: bryanv, bdragon, luporl, alfredo Approved by: jhibbits (mentor) Differential Revision: https://reviews.freebsd.org/D23401 Modified: head/sys/dev/virtio/pci/virtio_pci.c Modified: head/sys/dev/virtio/pci/virtio_pci.c ============================================================================== --- head/sys/dev/virtio/pci/virtio_pci.c Wed Feb 5 20:34:22 2020 (r357595) +++ head/sys/dev/virtio/pci/virtio_pci.c Wed Feb 5 20:39:18 2020 (r357596) @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -184,6 +185,17 @@ static void vtpci_config_intr(void *); #define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v)) #define vtpci_write_config_4(sc, o, v) bus_write_4((sc)->vtpci_res, (o), (v)) +/* + * Legacy VirtIO header is always PCI endianness (little), so if we + * are in a BE machine we need to swap bytes from LE to BE when reading + * and from BE to LE when writing. + * If we are in a LE machine, there will be no swaps. + */ +#define vtpci_read_header_2(sc, o) le16toh(vtpci_read_config_2(sc, o)) +#define vtpci_read_header_4(sc, o) le32toh(vtpci_read_config_4(sc, o)) +#define vtpci_write_header_2(sc, o, v) vtpci_write_config_2(sc, o, (htole16(v))) +#define vtpci_write_header_4(sc, o, v) vtpci_write_config_4(sc, o, (htole32(v))) + /* Tunables. */ static int vtpci_disable_msix = 0; TUNABLE_INT("hw.virtio.pci.disable_msix", &vtpci_disable_msix); @@ -278,6 +290,17 @@ vtpci_attach(device_t dev) return (ENXIO); } +/* + * For legacy VirtIO, the device-specific configuration is guest + * endian, while the common configuration header is always + * PCI (little) endian and will be handled specifically in + * other parts of this file via functions + * 'vtpci_[read|write]_header_[2|4]' + */ +#if _BYTE_ORDER == _BIG_ENDIAN + rman_set_bustag(sc->vtpci_res, &bs_be_tag); +#endif + if (pci_find_cap(dev, PCIY_MSI, NULL) != 0) sc->vtpci_flags |= VTPCI_FLAG_NO_MSI; @@ -447,7 +470,7 @@ vtpci_negotiate_features(device_t dev, uint64_t child_ sc = device_get_softc(dev); - host_features = vtpci_read_config_4(sc, VIRTIO_PCI_HOST_FEATURES); + host_features = vtpci_read_header_4(sc, VIRTIO_PCI_HOST_FEATURES); vtpci_describe_features(sc, "host", host_features); /* @@ -459,7 +482,7 @@ vtpci_negotiate_features(device_t dev, uint64_t child_ sc->vtpci_features = features; vtpci_describe_features(sc, "negotiated", features); - vtpci_write_config_4(sc, VIRTIO_PCI_GUEST_FEATURES, features); + vtpci_write_header_4(sc, VIRTIO_PCI_GUEST_FEATURES, features); return (features); } @@ -502,7 +525,7 @@ vtpci_alloc_virtqueues(device_t dev, int flags, int nv info = &vq_info[idx]; vtpci_select_virtqueue(sc, idx); - size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); + size = vtpci_read_header_2(sc, VIRTIO_PCI_QUEUE_NUM); error = virtqueue_alloc(dev, idx, size, VIRTIO_PCI_VRING_ALIGN, ~(vm_paddr_t)0, info, &vq); @@ -512,7 +535,7 @@ vtpci_alloc_virtqueues(device_t dev, int flags, int nv break; } - vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, + vtpci_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); vqx->vtv_vq = *info->vqai_vq = vq; @@ -646,7 +669,7 @@ vtpci_notify_virtqueue(device_t dev, uint16_t queue) sc = device_get_softc(dev); - vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_NOTIFY, queue); + vtpci_write_header_2(sc, VIRTIO_PCI_QUEUE_NOTIFY, queue); } static uint8_t @@ -1046,10 +1069,10 @@ vtpci_register_msix_vector(struct vtpci_softc *sc, int } else vector = VIRTIO_MSI_NO_VECTOR; - vtpci_write_config_2(sc, offset, vector); + vtpci_write_header_2(sc, offset, vector); /* Read vector to determine if the host had sufficient resources. */ - if (vtpci_read_config_2(sc, offset) != vector) { + if (vtpci_read_header_2(sc, offset) != vector) { device_printf(dev, "insufficient host resources for MSIX interrupts\n"); return (ENODEV); @@ -1112,13 +1135,13 @@ vtpci_reinit_virtqueue(struct vtpci_softc *sc, int idx KASSERT(vq != NULL, ("%s: vq %d not allocated", __func__, idx)); vtpci_select_virtqueue(sc, idx); - size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); + size = vtpci_read_header_2(sc, VIRTIO_PCI_QUEUE_NUM); error = virtqueue_reinit(vq, size); if (error) return (error); - vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, + vtpci_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); return (0); @@ -1182,7 +1205,7 @@ vtpci_free_virtqueues(struct vtpci_softc *sc) vqx = &sc->vtpci_vqs[idx]; vtpci_select_virtqueue(sc, idx); - vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 0); + vtpci_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, 0); virtqueue_free(vqx->vtv_vq); vqx->vtv_vq = NULL; @@ -1207,12 +1230,12 @@ vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *s int idx; if (sc->vtpci_flags & VTPCI_FLAG_MSIX) { - vtpci_write_config_2(sc, VIRTIO_MSI_CONFIG_VECTOR, + vtpci_write_header_2(sc, VIRTIO_MSI_CONFIG_VECTOR, VIRTIO_MSI_NO_VECTOR); for (idx = 0; idx < sc->vtpci_nvqs; idx++) { vtpci_select_virtqueue(sc, idx); - vtpci_write_config_2(sc, VIRTIO_MSI_QUEUE_VECTOR, + vtpci_write_header_2(sc, VIRTIO_MSI_QUEUE_VECTOR, VIRTIO_MSI_NO_VECTOR); } } @@ -1235,7 +1258,7 @@ static void vtpci_select_virtqueue(struct vtpci_softc *sc, int idx) { - vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, idx); + vtpci_write_header_2(sc, VIRTIO_PCI_QUEUE_SEL, idx); } static void