From 86180bd4ceceafb8636a018290ea12f7e742fcd6 Mon Sep 17 00:00:00 2001 From: dongshen Date: Tue, 7 Aug 2018 18:21:23 -0700 Subject: [PATCH] HV: Calling into VPCI init/unit functions for partition hypervisor V4: - Clear address cache info after a full cf8/cfc access - Add NULL pointer checking when calling init/deinit ops V3: - Do not use ASSERT - Loop through the vdev list defined in vm_desctiption table to call the vdev init/unit functions - Make the cached vbdf info struct per vm instead of per pcpu V2: - Fixed MISRA violations Reviewed-by: Anthony Xu Acked-by: Anthony Xu Signed-off-by: dongshen --- hypervisor/arch/x86/guest/vm.c | 8 ++ hypervisor/dm/vpci/pci_priv.h | 81 ++++++++++++++ hypervisor/dm/vpci/vpci.c | 175 ++++++++++++++++++++++++++++++ hypervisor/include/dm/vpci/vpci.h | 3 + 4 files changed, 267 insertions(+) create mode 100644 hypervisor/dm/vpci/pci_priv.h create mode 100644 hypervisor/dm/vpci/vpci.c diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 0210d9b1b..e95702c01 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -186,6 +186,10 @@ int create_vm(struct vm_description *vm_desc, struct vm **rtn_vm) } vm->vpic = vpic_init(vm); +#ifdef CONFIG_PARTITION_MODE + vpci_init(vm); +#endif + /* vpic wire_mode default is INTR */ vm->wire_mode = VPIC_WIRE_INTR; @@ -290,6 +294,10 @@ int shutdown_vm(struct vm *vm) vpic_cleanup(vm); } +#ifdef CONFIG_PARTITION_MODE + vpci_cleanup(vm); +#endif + free(vm->hw.vcpu_array); /* TODO: De-Configure HV-SW */ diff --git a/hypervisor/dm/vpci/pci_priv.h b/hypervisor/dm/vpci/pci_priv.h new file mode 100644 index 000000000..9f03a9e25 --- /dev/null +++ b/hypervisor/dm/vpci/pci_priv.h @@ -0,0 +1,81 @@ +/*- +* Copyright (c) 2011 NetApp, Inc. +* Copyright (c) 2018 Intel Corporation +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. 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. +* +* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``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 NETAPP, INC 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. +* +* $FreeBSD$ +*/ + +#ifndef PCI_PRIV_H_ +#define PCI_PRIV_H_ + +#include +#include "vpci.h" + +#define PCIM_BAR_MEM_BASE 0xfffffff0U +#define PCI_BAR_BASE(val) ((val) & PCIM_BAR_MEM_BASE) +#define PCI_BAR(base, type) ((base) | (type)) + +#define PCI_BUS(bdf) (((bdf) >> 8) & 0xFFU) +#define PCI_SLOT(bdf) (((bdf) >> 3) & 0x1FU) +#define PCI_FUNC(bdf) ((bdf) & 0x07U) + +#define LOBYTE(w) ((uint8_t)((w) & 0xffU)) + +#define PCI_BUSMAX 0xffU +#define PCI_SLOTMAX 0x1fU +#define PCI_FUNCMAX 0x7U + +#define MAXBUSES (PCI_BUSMAX + 1U) +#define MAXSLOTS (PCI_SLOTMAX + 1U) +#define MAXFUNCS (PCI_FUNCMAX + 1U) + +#define PCIR_VENDOR 0x00U +#define PCIR_DEVICE 0x02U +#define PCIR_COMMAND 0x04U +#define PCIM_CMD_MEMEN 0x0002U +#define PCIR_REVID 0x08U +#define PCIR_SUBCLASS 0x0aU +#define PCIR_CLASS 0x0bU +#define PCIR_HDRTYPE 0x0eU +#define PCIM_HDRTYPE_NORMAL 0x00U +#define PCIM_MFDEV 0x80U + +#define PCIR_BARS 0x10U +#define PCIR_BAR(x) (PCIR_BARS + ((x) * 4U)) + +#define PCIM_BAR_MEM_SPACE 0U + +#define PCIC_BRIDGE 0x06U +#define PCIS_BRIDGE_HOST 0x00U + +#define PCI_CONFIG_ADDR 0xcf8U +#define PCI_CONFIG_DATA 0xcfcU + +#define PCI_CFG_ENABLE 0x80000000U + +void pci_vdev_cfg_handler(struct vpci *vpci, uint32_t in, uint16_t vbdf, + uint32_t offset, uint32_t bytes, uint32_t *val); + +#endif /* PCI_PRIV_H_ */ diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c new file mode 100644 index 000000000..42ea09c96 --- /dev/null +++ b/hypervisor/dm/vpci/vpci.c @@ -0,0 +1,175 @@ +/*- +* Copyright (c) 2011 NetApp, Inc. +* Copyright (c) 2018 Intel Corporation +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. 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. +* +* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``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 NETAPP, INC 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. +* +* $FreeBSD$ +*/ + +#include +#include +#include +#include +#include +#include "pci_priv.h" + + +static bool is_cfg_addr(uint16_t addr) +{ + return (addr >= PCI_CONFIG_ADDR) && (addr < (PCI_CONFIG_ADDR + 4)); +} + +static bool is_cfg_data(uint16_t addr) +{ + return (addr >= PCI_CONFIG_DATA) && (addr < (PCI_CONFIG_DATA + 4)); +} + +static void pci_cfg_clear_cache(struct pci_addr_info *pi) +{ + pi->cached_bdf = 0xffffU; + pi->cached_reg = 0U; + pi->cached_enable = 0U; +} + +static uint32_t pci_cfg_io_read(__unused struct vm_io_handler *hdlr, + struct vm *vm, uint16_t addr, size_t bytes) +{ + uint32_t val = 0xffffffffU; + struct vpci *vpci = &vm->vpci; + struct pci_addr_info *pi = &vpci->addr_info; + + if (is_cfg_addr(addr)) { + /* TODO: handling the non 4 bytes access */ + if (bytes == 4U) { + val = (PCI_BUS(pi->cached_bdf) << 16) + | (PCI_SLOT(pi->cached_bdf) << 11) + | (PCI_FUNC(pi->cached_bdf) << 8) + | pi->cached_reg; + + if (pi->cached_enable) { + val |= PCI_CFG_ENABLE; + } + } + } else if (is_cfg_data(addr)) { + if (pi->cached_enable) { + uint16_t offset = addr - 0xcfc; + + pci_vdev_cfg_handler(&vm->vpci, 1U, pi->cached_bdf, + pi->cached_reg + offset, bytes, &val); + + pci_cfg_clear_cache(pi); + } + } else { + val = 0xffffffffU; + } + + return val; +} + +static void pci_cfg_io_write(__unused struct vm_io_handler *hdlr, + struct vm *vm, uint16_t addr, size_t bytes, uint32_t val) +{ + struct vpci *vpci = &vm->vpci; + struct pci_addr_info *pi = &vpci->addr_info; + + if (is_cfg_addr(addr)) { + /* TODO: handling the non 4 bytes access */ + if (bytes == 4U) { + pi->cached_bdf = PCI_BDF( + ((val >> 16) & PCI_BUSMAX), + ((val >> 11) & PCI_SLOTMAX), + ((val >> 8) & PCI_FUNCMAX)); + + pi->cached_reg = val & PCI_REGMAX; + pi->cached_enable = + (val & PCI_CFG_ENABLE) == PCI_CFG_ENABLE; + } + } else if (is_cfg_data(addr)) { + if (pi->cached_enable) { + uint16_t offset = addr - 0xcfc; + + pci_vdev_cfg_handler(&vm->vpci, 0U, pi->cached_bdf, + pi->cached_reg + offset, bytes, &val); + + pci_cfg_clear_cache(pi); + } + } else { + pr_err("Not PCI cfg data/addr port access!"); + } + +} + +void vpci_init(struct vm *vm) +{ + struct vpci *vpci = &vm->vpci; + struct vpci_vdev_array *vdev_array; + struct pci_vdev *vdev; + int i; + int ret; + struct vm_io_range pci_cfg_range = {.flags = IO_ATTR_RW, + .base = PCI_CONFIG_ADDR, .len = 8U}; + + vpci->vm = vm; + vdev_array = vm->vm_desc->vpci_vdev_array; + + for (i = 0; i < vdev_array->num_pci_vdev; i++) { + vdev = &vdev_array->vpci_vdev_list[i]; + vdev->vpci = vpci; + if ((vdev->ops != NULL) && (vdev->ops->init != NULL)) { + ret = vdev->ops->init(vdev); + if (ret) { + pr_err("vdev->ops->init failed!"); + } + } + } + + register_io_emulation_handler(vm, &pci_cfg_range, + &pci_cfg_io_read, &pci_cfg_io_write); +} + +void vpci_cleanup(struct vm *vm) +{ + struct vpci_vdev_array *vdev_array; + struct pci_vdev *vdev; + int i; + int ret; + + vdev_array = vm->vm_desc->vpci_vdev_array; + + for (i = 0; i < vdev_array->num_pci_vdev; i++) { + vdev = &vdev_array->vpci_vdev_list[i]; + if ((vdev->ops != NULL) && (vdev->ops->deinit != NULL)) { + ret = vdev->ops->deinit(vdev); + if (ret) { + pr_err("vdev->ops->deinit failed!"); + } + } + } +} + +void pci_vdev_cfg_handler(struct vpci *vpci, uint32_t in, uint16_t vbdf, + uint32_t offset, uint32_t bytes, uint32_t *val) +{ + /* vm-exit handler */ +} diff --git a/hypervisor/include/dm/vpci/vpci.h b/hypervisor/include/dm/vpci/vpci.h index 51cc7f020..d864dc02d 100644 --- a/hypervisor/include/dm/vpci/vpci.h +++ b/hypervisor/include/dm/vpci/vpci.h @@ -92,4 +92,7 @@ struct vpci { struct pci_addr_info addr_info; }; +void vpci_init(struct vm *vm); +void vpci_cleanup(struct vm *vm); + #endif /* VPCI_H_ */