From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pf0-f174.google.com (mail-pf0-f174.google.com [209.85.192.174]) by dpdk.org (Postfix) with ESMTP id E625C2C4A for ; Thu, 2 Jun 2016 05:30:10 +0200 (CEST) Received: by mail-pf0-f174.google.com with SMTP id f144so25659676pfa.3 for ; Wed, 01 Jun 2016 20:30:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=igel-co-jp.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=MHjsDxql/18BlOqUIn44npBcSxUppphUexPg1Vs0Ero=; b=Zy6xfCmIbcEZ0gKlUoUK4Ug1Uy1lxtrlFUGE5dEAdiCfI0b6UwRNTDukTFgZuVL0g9 8yszpZ8hNPzRSAGXWdXCJOwwZft0V34MoJ3Q8RMe5ohgTKSexmYEe/uitNxCcIzRD/pF P2q/XNrnwdTCeaVuLEsc2LeBehggHCULEiEHD8M82D2VcjHunmgzsmwOSCv1Vi9+5mnS wh+H94u3aOhgE8kmxR8u5M1JIVKTrXZ2RBGqvREqtceK8muu690fFJiglRvI0pzCL0Q0 wXFNyhHGdCvt19TBWBlNbhC6s2hGMZ7ujHg/tWipvPndN3UurtpirvNxel0EKda7OlJ5 REtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=MHjsDxql/18BlOqUIn44npBcSxUppphUexPg1Vs0Ero=; b=DHyuQKjiPOzP8i9fo2ZAytK1VlMqc4cyGJBdlMCzOjpJl3f3wQCJ0x6KcwmAgRObev apm3+VITjS6xquGYPd5UWDFLn6eZGTgKp7tPJtA2TAKazzKP+B7TqYMZ08vx9DGQ8t0N Wua/R5HIzhbURz1PYBGeOVcQfgFbAMNRLURNHOH++sFKIdRBghV2FOxOWkoQw4Bsj34D EvB3vFehvBvUjDYzhx2VlKBEh5Bbiw33ONRsuKM+Nxb2qOgwd/H+Sgqa6OCdohm3M3CC nntpPbHrBbE16x5N2TO5ccbWfuUlbFxjMd4knlH6QoFJmExEItu1l1Qp0+KcQPoS5BML 8Mog== X-Gm-Message-State: ALyK8tJUCSbE4bGGrpAwqE3glhVshK7yL1qzsOvScBTU4leC80UUIgzhTbRwNc+FAoaBVA== X-Received: by 10.98.68.203 with SMTP id m72mr319677pfi.135.1464838210047; Wed, 01 Jun 2016 20:30:10 -0700 (PDT) Received: from localhost.localdomain (napt.igel.co.jp. [219.106.231.132]) by smtp.gmail.com with ESMTPSA id th5sm59830828pab.31.2016.06.01.20.30.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Jun 2016 20:30:07 -0700 (PDT) From: Tetsuya Mukawa To: dev@dpdk.org Cc: yuanhan.liu@linux.intel.com, jianfeng.tan@intel.com, huawei.xie@intel.com, Tetsuya Mukawa Date: Thu, 2 Jun 2016 12:29:44 +0900 Message-Id: <1464838185-21751-6-git-send-email-mukawa@igel.co.jp> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1464838185-21751-1-git-send-email-mukawa@igel.co.jp> References: <1464838185-21751-1-git-send-email-mukawa@igel.co.jp> In-Reply-To: <1457512409-24403-12-git-send-email-mukawa@igel.co.jp> References: <1457512409-24403-12-git-send-email-mukawa@igel.co.jp> Subject: [dpdk-dev] [PATCH v5 5/6] virtio: Add QTest support to vtpci abstraction X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 02 Jun 2016 03:30:11 -0000 The patch adds QTest support to vtpci abstraction. With this patch, only modern virtio device will be supported. This implementation will be used by later QTest extension patch of virtio-net PMD. Signed-off-by: Tetsuya Mukawa --- drivers/net/virtio/Makefile | 1 + drivers/net/virtio/virtio_qtest/virtio_qtest_pci.c | 407 +++++++++++++++++++++ drivers/net/virtio/virtio_qtest/virtio_qtest_pci.h | 39 ++ 3 files changed, 447 insertions(+) create mode 100644 drivers/net/virtio/virtio_qtest/virtio_qtest_pci.c create mode 100644 drivers/net/virtio/virtio_qtest/virtio_qtest_pci.h diff --git a/drivers/net/virtio/Makefile b/drivers/net/virtio/Makefile index 0b1ccff..1c86d9d 100644 --- a/drivers/net/virtio/Makefile +++ b/drivers/net/virtio/Makefile @@ -65,6 +65,7 @@ endif ifeq ($(CONFIG_RTE_VIRTIO_QTEST),y) SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_qtest/qtest_utils.c +SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_qtest/virtio_qtest_pci.c endif # this lib depends upon: diff --git a/drivers/net/virtio/virtio_qtest/virtio_qtest_pci.c b/drivers/net/virtio/virtio_qtest/virtio_qtest_pci.c new file mode 100644 index 0000000..d715b13 --- /dev/null +++ b/drivers/net/virtio/virtio_qtest/virtio_qtest_pci.c @@ -0,0 +1,407 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "../virtio_logs.h" +#include "../virtio_pci.h" +#include "../virtqueue.h" + +#include "qtest_utils.h" +#include "virtio_qtest_pci.h" + +static inline int +check_vq_phys_addr_ok(struct virtqueue *vq) +{ + /* Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit, + * and only accepts 32 bit page frame number. + * Check if the allocated physical memory exceeds 16TB. + */ + if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >> + (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) { + PMD_INIT_LOG(ERR, "vring address shouldn't be above 16TB!"); + return 0; + } + + return 1; +} + +static inline uint8_t +qtest_read8(struct virtio_hw *hw, uint8_t *addr) +{ + return qtest_read(hw->virtio_user_dev, (uint64_t)addr, 'b'); +} + +static inline void +qtest_write8(struct virtio_hw *hw, uint8_t val, uint8_t *addr) +{ + return qtest_write(hw->virtio_user_dev, (uint64_t)addr, val, 'b'); +} + +static inline uint16_t +qtest_read16(struct virtio_hw *hw, uint16_t *addr) +{ + return qtest_read(hw->virtio_user_dev, (uint64_t)addr, 'w'); +} + +static inline void +qtest_write16(struct virtio_hw *hw, uint16_t val, uint16_t *addr) +{ + return qtest_write(hw->virtio_user_dev, (uint64_t)addr, val, 'w'); +} + +static inline uint32_t +qtest_read32(struct virtio_hw *hw, uint32_t *addr) +{ + return qtest_read(hw->virtio_user_dev, (uint64_t)addr, 'l'); +} + +static inline void +qtest_write32(struct virtio_hw *hw, uint32_t val, uint32_t *addr) +{ + return qtest_write(hw->virtio_user_dev, (uint64_t)addr, val, 'l'); +} + +static inline void +qtest_write64_twopart(struct virtio_hw *hw, + uint64_t val, uint32_t *lo, uint32_t *hi) +{ + qtest_write32(hw, val & ((1ULL << 32) - 1), lo); + qtest_write32(hw, val >> 32, hi); +} + +static void +qtest_read_dev_config(struct virtio_hw *hw, size_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = qtest_read8(hw, &hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = qtest_read8(hw, (uint8_t *)hw->dev_cfg + offset + i); + + new_gen = qtest_read8(hw, &hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +qtest_write_dev_config(struct virtio_hw *hw, size_t offset, + const void *src, int length) +{ + int i; + const uint8_t *p = src; + + for (i = 0; i < length; i++) + qtest_write8(hw, *p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +qtest_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + qtest_write32(hw, 0, &hw->common_cfg->device_feature_select); + features_lo = qtest_read32(hw, &hw->common_cfg->device_feature); + + qtest_write32(hw, 1, &hw->common_cfg->device_feature_select); + features_hi = qtest_read32(hw, &hw->common_cfg->device_feature); + + return ((uint64_t)features_hi << 32) | features_lo; +} + +static void +qtest_set_features(struct virtio_hw *hw, uint64_t features) +{ + qtest_write32(hw, 0, &hw->common_cfg->guest_feature_select); + qtest_write32(hw, features & ((1ULL << 32) - 1), + &hw->common_cfg->guest_feature); + + qtest_write32(hw, 1, &hw->common_cfg->guest_feature_select); + qtest_write32(hw, features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +qtest_get_status(struct virtio_hw *hw) +{ + return qtest_read8(hw, &hw->common_cfg->device_status); +} + +static void +qtest_set_status(struct virtio_hw *hw, uint8_t status) +{ + qtest_write8(hw, status, &hw->common_cfg->device_status); +} + +static void +qtest_reset(struct virtio_hw *hw) +{ + qtest_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + qtest_get_status(hw); +} + +static uint8_t +qtest_get_isr(struct virtio_hw *hw) +{ + return qtest_read8(hw, hw->isr); +} + +static uint16_t +qtest_set_config_irq(struct virtio_hw *hw, uint16_t vec) +{ + qtest_write16(hw, vec, &hw->common_cfg->msix_config); + return qtest_read16(hw, &hw->common_cfg->msix_config); +} + +static uint16_t +qtest_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + qtest_write16(hw, queue_id, &hw->common_cfg->queue_select); + return qtest_read16(hw, &hw->common_cfg->queue_size); +} + +static int +qtest_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + if (!check_vq_phys_addr_ok(vq)) + return -1; + + desc_addr = (uint64_t)vq->mz->addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + qtest_write16(hw, vq->vq_queue_index, &hw->common_cfg->queue_select); + + qtest_write64_twopart(hw, desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + qtest_write64_twopart(hw, avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + qtest_write64_twopart(hw, used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = qtest_read16(hw, &hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + qtest_write16(hw, 1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); + + return 0; +} + +static void +qtest_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + qtest_write16(hw, vq->vq_queue_index, &hw->common_cfg->queue_select); + + qtest_write64_twopart(hw, 0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + qtest_write64_twopart(hw, 0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + qtest_write64_twopart(hw, 0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + qtest_write16(hw, 0, &hw->common_cfg->queue_enable); +} + +static void +qtest_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + qtest_write16(hw, 1, vq->notify_addr); +} + +const struct virtio_pci_ops modern_qtest_ops = { + .read_dev_cfg = qtest_read_dev_config, + .write_dev_cfg = qtest_write_dev_config, + .reset = qtest_reset, + .get_status = qtest_get_status, + .set_status = qtest_set_status, + .get_features = qtest_get_features, + .set_features = qtest_set_features, + .get_isr = qtest_get_isr, + .set_config_irq = qtest_set_config_irq, + .get_queue_num = qtest_get_queue_num, + .setup_queue = qtest_setup_queue, + .del_queue = qtest_del_queue, + .notify_queue = qtest_notify_queue, +}; + +static void * +get_cfg_addr(struct virtio_hw *hw, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base = NULL; + uint64_t size = 0; + + if (bar > 5) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (offset + length < offset) { + PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows", + offset, length); + return NULL; + } + + qtest_get_bar_size(hw->virtio_user_dev, "virtio-net", bar, &size); + qtest_get_bar_addr(hw->virtio_user_dev, "virtio-net", bar, + (uint64_t **)&base); + + if (offset + length > size) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %" PRIu64, + offset + length, size); + return NULL; + } + + if (base == NULL) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + ret = qtest_read_pci_cfg(hw->virtio_user_dev, "virtio-net", + &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = qtest_read_pci_cfg(hw->virtio_user_dev, "virtio-net", + &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(hw, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + qtest_read_pci_cfg(hw->virtio_user_dev, "virtio-net", + &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(hw, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(hw, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + hw->isr = get_cfg_addr(hw, &cap); + break; + } + +next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL || hw->isr == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + +int +qtest_vtpci_init(struct virtio_hw *hw, uint32_t *dev_flags) +{ + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. + */ + if (virtio_read_caps(hw) == 0) { + PMD_INIT_LOG(INFO, "modern virtio pci detected."); + hw->vtpci_ops = &modern_qtest_ops; + hw->modern = 1; + /* So far, we don't support LSC interrupt */ + *dev_flags = 0; + return 0; + } + + PMD_INIT_LOG(INFO, "So far, legacy virtio device isn't supported"); + return -EFAULT; +} diff --git a/drivers/net/virtio/virtio_qtest/virtio_qtest_pci.h b/drivers/net/virtio/virtio_qtest/virtio_qtest_pci.h new file mode 100644 index 0000000..6024e27 --- /dev/null +++ b/drivers/net/virtio/virtio_qtest/virtio_qtest_pci.h @@ -0,0 +1,39 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _VIRTIO_QTEST_PCI_H +#define _VIRTIO_QTEST_PCI_H + +int qtest_vtpci_init(struct virtio_hw *hw, uint32_t *dev_flags); + +#endif -- 2.7.4