16c3169a3SBruce Richardson /*- 26c3169a3SBruce Richardson * BSD LICENSE 36c3169a3SBruce Richardson * 46c3169a3SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 56c3169a3SBruce Richardson * All rights reserved. 66c3169a3SBruce Richardson * 76c3169a3SBruce Richardson * Redistribution and use in source and binary forms, with or without 86c3169a3SBruce Richardson * modification, are permitted provided that the following conditions 96c3169a3SBruce Richardson * are met: 106c3169a3SBruce Richardson * 116c3169a3SBruce Richardson * * Redistributions of source code must retain the above copyright 126c3169a3SBruce Richardson * notice, this list of conditions and the following disclaimer. 136c3169a3SBruce Richardson * * Redistributions in binary form must reproduce the above copyright 146c3169a3SBruce Richardson * notice, this list of conditions and the following disclaimer in 156c3169a3SBruce Richardson * the documentation and/or other materials provided with the 166c3169a3SBruce Richardson * distribution. 176c3169a3SBruce Richardson * * Neither the name of Intel Corporation nor the names of its 186c3169a3SBruce Richardson * contributors may be used to endorse or promote products derived 196c3169a3SBruce Richardson * from this software without specific prior written permission. 206c3169a3SBruce Richardson * 216c3169a3SBruce Richardson * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 226c3169a3SBruce Richardson * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 236c3169a3SBruce Richardson * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 246c3169a3SBruce Richardson * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 256c3169a3SBruce Richardson * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 266c3169a3SBruce Richardson * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 276c3169a3SBruce Richardson * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 286c3169a3SBruce Richardson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 296c3169a3SBruce Richardson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 306c3169a3SBruce Richardson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 316c3169a3SBruce Richardson * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 326c3169a3SBruce Richardson */ 336c3169a3SBruce Richardson #include <stdint.h> 346c3169a3SBruce Richardson 35c52afa68SYuanhan Liu #ifdef RTE_EXEC_ENV_LINUXAPP 36c52afa68SYuanhan Liu #include <dirent.h> 37c52afa68SYuanhan Liu #include <fcntl.h> 38c52afa68SYuanhan Liu #endif 39c52afa68SYuanhan Liu 40*631d4ee4SSantosh Shukla #include <rte_io.h> 41*631d4ee4SSantosh Shukla 426c3169a3SBruce Richardson #include "virtio_pci.h" 436c3169a3SBruce Richardson #include "virtio_logs.h" 44d5bbeefcSYuanhan Liu #include "virtqueue.h" 456c3169a3SBruce Richardson 466ba1f63bSYuanhan Liu /* 476ba1f63bSYuanhan Liu * Following macros are derived from linux/pci_regs.h, however, 486ba1f63bSYuanhan Liu * we can't simply include that header here, as there is no such 496ba1f63bSYuanhan Liu * file for non-Linux platform. 506ba1f63bSYuanhan Liu */ 516ba1f63bSYuanhan Liu #define PCI_CAPABILITY_LIST 0x34 526ba1f63bSYuanhan Liu #define PCI_CAP_ID_VNDR 0x09 536ba1f63bSYuanhan Liu 54b8f04520SDavid Marchand /* 55b8f04520SDavid Marchand * The remaining space is defined by each driver as the per-driver 56b8f04520SDavid Marchand * configuration space. 57b8f04520SDavid Marchand */ 58b8f04520SDavid Marchand #define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20) 59b86af7b1SYuanhan Liu 60595454c5SJianfeng Tan static inline int 61595454c5SJianfeng Tan check_vq_phys_addr_ok(struct virtqueue *vq) 62595454c5SJianfeng Tan { 63595454c5SJianfeng Tan /* Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit, 64595454c5SJianfeng Tan * and only accepts 32 bit page frame number. 65595454c5SJianfeng Tan * Check if the allocated physical memory exceeds 16TB. 66595454c5SJianfeng Tan */ 67595454c5SJianfeng Tan if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >> 68595454c5SJianfeng Tan (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) { 69595454c5SJianfeng Tan PMD_INIT_LOG(ERR, "vring address shouldn't be above 16TB!"); 70595454c5SJianfeng Tan return 0; 71595454c5SJianfeng Tan } 72595454c5SJianfeng Tan 73595454c5SJianfeng Tan return 1; 74595454c5SJianfeng Tan } 75595454c5SJianfeng Tan 76281ccccbSDavid Marchand /* 77281ccccbSDavid Marchand * Since we are in legacy mode: 78281ccccbSDavid Marchand * http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf 79281ccccbSDavid Marchand * 80281ccccbSDavid Marchand * "Note that this is possible because while the virtio header is PCI (i.e. 81281ccccbSDavid Marchand * little) endian, the device-specific region is encoded in the native endian of 82281ccccbSDavid Marchand * the guest (where such distinction is applicable)." 83281ccccbSDavid Marchand * 84281ccccbSDavid Marchand * For powerpc which supports both, qemu supposes that cpu is big endian and 85281ccccbSDavid Marchand * enforces this for the virtio-net stuff. 86281ccccbSDavid Marchand */ 87d5bbeefcSYuanhan Liu static void 88d5bbeefcSYuanhan Liu legacy_read_dev_config(struct virtio_hw *hw, size_t offset, 896c3169a3SBruce Richardson void *dst, int length) 906c3169a3SBruce Richardson { 91281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64 92281ccccbSDavid Marchand int size; 93281ccccbSDavid Marchand 94281ccccbSDavid Marchand while (length > 0) { 95281ccccbSDavid Marchand if (length >= 4) { 96281ccccbSDavid Marchand size = 4; 971ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), dst, size, 98281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 99281ccccbSDavid Marchand *(uint32_t *)dst = rte_be_to_cpu_32(*(uint32_t *)dst); 100281ccccbSDavid Marchand } else if (length >= 2) { 101281ccccbSDavid Marchand size = 2; 1021ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), dst, size, 103281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 104281ccccbSDavid Marchand *(uint16_t *)dst = rte_be_to_cpu_16(*(uint16_t *)dst); 105281ccccbSDavid Marchand } else { 106281ccccbSDavid Marchand size = 1; 1071ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), dst, size, 108281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 109281ccccbSDavid Marchand } 110281ccccbSDavid Marchand 111281ccccbSDavid Marchand dst = (char *)dst + size; 112281ccccbSDavid Marchand offset += size; 113281ccccbSDavid Marchand length -= size; 114281ccccbSDavid Marchand } 115281ccccbSDavid Marchand #else 1161ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), dst, length, 117b8f04520SDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 118281ccccbSDavid Marchand #endif 1196c3169a3SBruce Richardson } 1206c3169a3SBruce Richardson 121d5bbeefcSYuanhan Liu static void 122d5bbeefcSYuanhan Liu legacy_write_dev_config(struct virtio_hw *hw, size_t offset, 123d5bbeefcSYuanhan Liu const void *src, int length) 1246c3169a3SBruce Richardson { 125281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64 126281ccccbSDavid Marchand union { 127281ccccbSDavid Marchand uint32_t u32; 128281ccccbSDavid Marchand uint16_t u16; 129281ccccbSDavid Marchand } tmp; 130281ccccbSDavid Marchand int size; 131281ccccbSDavid Marchand 132281ccccbSDavid Marchand while (length > 0) { 133281ccccbSDavid Marchand if (length >= 4) { 134281ccccbSDavid Marchand size = 4; 135281ccccbSDavid Marchand tmp.u32 = rte_cpu_to_be_32(*(const uint32_t *)src); 1361ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &tmp.u32, size, 137281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 138281ccccbSDavid Marchand } else if (length >= 2) { 139281ccccbSDavid Marchand size = 2; 140281ccccbSDavid Marchand tmp.u16 = rte_cpu_to_be_16(*(const uint16_t *)src); 1411ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &tmp.u16, size, 142281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 143281ccccbSDavid Marchand } else { 144281ccccbSDavid Marchand size = 1; 1451ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), src, size, 146281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 147281ccccbSDavid Marchand } 148281ccccbSDavid Marchand 149281ccccbSDavid Marchand src = (const char *)src + size; 150281ccccbSDavid Marchand offset += size; 151281ccccbSDavid Marchand length -= size; 152281ccccbSDavid Marchand } 153281ccccbSDavid Marchand #else 1541ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), src, length, 155b8f04520SDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 156281ccccbSDavid Marchand #endif 1576c3169a3SBruce Richardson } 1586c3169a3SBruce Richardson 1593891f233SYuanhan Liu static uint64_t 160d5bbeefcSYuanhan Liu legacy_get_features(struct virtio_hw *hw) 161d5bbeefcSYuanhan Liu { 16236ea36efSYuanhan Liu uint32_t dst; 163b8f04520SDavid Marchand 1641ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 4, 1651ca893f1SYuanhan Liu VIRTIO_PCI_HOST_FEATURES); 166b8f04520SDavid Marchand return dst; 167d5bbeefcSYuanhan Liu } 168d5bbeefcSYuanhan Liu 169d5bbeefcSYuanhan Liu static void 1703891f233SYuanhan Liu legacy_set_features(struct virtio_hw *hw, uint64_t features) 171d5bbeefcSYuanhan Liu { 1723891f233SYuanhan Liu if ((features >> 32) != 0) { 1733891f233SYuanhan Liu PMD_DRV_LOG(ERR, 1743891f233SYuanhan Liu "only 32 bit features are allowed for legacy virtio!"); 1753891f233SYuanhan Liu return; 1763891f233SYuanhan Liu } 1771ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &features, 4, 178b8f04520SDavid Marchand VIRTIO_PCI_GUEST_FEATURES); 179d5bbeefcSYuanhan Liu } 180d5bbeefcSYuanhan Liu 181d5bbeefcSYuanhan Liu static uint8_t 182d5bbeefcSYuanhan Liu legacy_get_status(struct virtio_hw *hw) 183d5bbeefcSYuanhan Liu { 184b8f04520SDavid Marchand uint8_t dst; 185b8f04520SDavid Marchand 1861ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 1, VIRTIO_PCI_STATUS); 187b8f04520SDavid Marchand return dst; 188d5bbeefcSYuanhan Liu } 189d5bbeefcSYuanhan Liu 190d5bbeefcSYuanhan Liu static void 191d5bbeefcSYuanhan Liu legacy_set_status(struct virtio_hw *hw, uint8_t status) 192d5bbeefcSYuanhan Liu { 1931ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &status, 1, VIRTIO_PCI_STATUS); 194d5bbeefcSYuanhan Liu } 195d5bbeefcSYuanhan Liu 196d5bbeefcSYuanhan Liu static void 197d5bbeefcSYuanhan Liu legacy_reset(struct virtio_hw *hw) 198d5bbeefcSYuanhan Liu { 199d5bbeefcSYuanhan Liu legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 200d5bbeefcSYuanhan Liu } 201d5bbeefcSYuanhan Liu 202d5bbeefcSYuanhan Liu static uint8_t 203d5bbeefcSYuanhan Liu legacy_get_isr(struct virtio_hw *hw) 204d5bbeefcSYuanhan Liu { 205b8f04520SDavid Marchand uint8_t dst; 206b8f04520SDavid Marchand 2071ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 1, VIRTIO_PCI_ISR); 208b8f04520SDavid Marchand return dst; 209d5bbeefcSYuanhan Liu } 210d5bbeefcSYuanhan Liu 211d5bbeefcSYuanhan Liu /* Enable one vector (0) for Link State Intrerrupt */ 212d5bbeefcSYuanhan Liu static uint16_t 213d5bbeefcSYuanhan Liu legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec) 214d5bbeefcSYuanhan Liu { 215b8f04520SDavid Marchand uint16_t dst; 216b8f04520SDavid Marchand 2171ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vec, 2, 2181ca893f1SYuanhan Liu VIRTIO_MSI_CONFIG_VECTOR); 2191ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 2, 2201ca893f1SYuanhan Liu VIRTIO_MSI_CONFIG_VECTOR); 221b8f04520SDavid Marchand return dst; 222d5bbeefcSYuanhan Liu } 223d5bbeefcSYuanhan Liu 224d5bbeefcSYuanhan Liu static uint16_t 225c49526acSJianfeng Tan legacy_set_queue_irq(struct virtio_hw *hw, struct virtqueue *vq, uint16_t vec) 226c49526acSJianfeng Tan { 227c49526acSJianfeng Tan uint16_t dst; 228c49526acSJianfeng Tan 229c49526acSJianfeng Tan rte_eal_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2, 230c49526acSJianfeng Tan VIRTIO_PCI_QUEUE_SEL); 231c49526acSJianfeng Tan rte_eal_pci_ioport_write(VTPCI_IO(hw), &vec, 2, 232c49526acSJianfeng Tan VIRTIO_MSI_QUEUE_VECTOR); 233c49526acSJianfeng Tan rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 2, VIRTIO_MSI_QUEUE_VECTOR); 234c49526acSJianfeng Tan return dst; 235c49526acSJianfeng Tan } 236c49526acSJianfeng Tan 237c49526acSJianfeng Tan static uint16_t 238d5bbeefcSYuanhan Liu legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 239d5bbeefcSYuanhan Liu { 240b8f04520SDavid Marchand uint16_t dst; 241b8f04520SDavid Marchand 2421ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &queue_id, 2, 2431ca893f1SYuanhan Liu VIRTIO_PCI_QUEUE_SEL); 2441ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 2, VIRTIO_PCI_QUEUE_NUM); 245b8f04520SDavid Marchand return dst; 246d5bbeefcSYuanhan Liu } 247d5bbeefcSYuanhan Liu 248595454c5SJianfeng Tan static int 249d5bbeefcSYuanhan Liu legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 250d5bbeefcSYuanhan Liu { 251b8f04520SDavid Marchand uint32_t src; 252d5bbeefcSYuanhan Liu 253595454c5SJianfeng Tan if (!check_vq_phys_addr_ok(vq)) 254595454c5SJianfeng Tan return -1; 255595454c5SJianfeng Tan 2561ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2, 257b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 25801ad44fdSHuawei Xie src = vq->vq_ring_mem >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; 2591ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &src, 4, VIRTIO_PCI_QUEUE_PFN); 260595454c5SJianfeng Tan 261595454c5SJianfeng Tan return 0; 262d5bbeefcSYuanhan Liu } 263d5bbeefcSYuanhan Liu 264d5bbeefcSYuanhan Liu static void 265d5bbeefcSYuanhan Liu legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 266d5bbeefcSYuanhan Liu { 267b8f04520SDavid Marchand uint32_t src = 0; 268d5bbeefcSYuanhan Liu 2691ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2, 270b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 2711ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &src, 4, VIRTIO_PCI_QUEUE_PFN); 272d5bbeefcSYuanhan Liu } 273d5bbeefcSYuanhan Liu 274d5bbeefcSYuanhan Liu static void 275d5bbeefcSYuanhan Liu legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) 276d5bbeefcSYuanhan Liu { 2771ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2, 278b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_NOTIFY); 279d5bbeefcSYuanhan Liu } 280d5bbeefcSYuanhan Liu 281c52afa68SYuanhan Liu #ifdef RTE_EXEC_ENV_LINUXAPP 282c52afa68SYuanhan Liu static int 283c52afa68SYuanhan Liu legacy_virtio_has_msix(const struct rte_pci_addr *loc) 284c52afa68SYuanhan Liu { 285c52afa68SYuanhan Liu DIR *d; 286c52afa68SYuanhan Liu char dirname[PATH_MAX]; 287c52afa68SYuanhan Liu 288c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), 28953c3c30cSJan Viktorin "%s/" PCI_PRI_FMT "/msi_irqs", pci_get_sysfs_path(), 290c52afa68SYuanhan Liu loc->domain, loc->bus, loc->devid, loc->function); 291c52afa68SYuanhan Liu 292c52afa68SYuanhan Liu d = opendir(dirname); 293c52afa68SYuanhan Liu if (d) 294c52afa68SYuanhan Liu closedir(d); 295c52afa68SYuanhan Liu 296693f715dSHuawei Xie return d != NULL; 297c52afa68SYuanhan Liu } 298c52afa68SYuanhan Liu #else 299c52afa68SYuanhan Liu static int 30025294cd3SDavid Marchand legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) 301c52afa68SYuanhan Liu { 302c52afa68SYuanhan Liu /* nic_uio does not enable interrupts, return 0 (false). */ 303c52afa68SYuanhan Liu return 0; 304c52afa68SYuanhan Liu } 305b8f04520SDavid Marchand #endif 306c52afa68SYuanhan Liu 307c52afa68SYuanhan Liu static int 308b8f04520SDavid Marchand legacy_virtio_resource_init(struct rte_pci_device *pci_dev, 30962a785a6SJianfeng Tan struct virtio_hw *hw, uint32_t *dev_flags) 310c52afa68SYuanhan Liu { 3111ca893f1SYuanhan Liu if (rte_eal_pci_ioport_map(pci_dev, 0, VTPCI_IO(hw)) < 0) 312b8f04520SDavid Marchand return -1; 313b8f04520SDavid Marchand 314b8f04520SDavid Marchand if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN) 31562a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 316b8f04520SDavid Marchand else 31762a785a6SJianfeng Tan *dev_flags &= ~RTE_ETH_DEV_INTR_LSC; 318b8f04520SDavid Marchand 319c52afa68SYuanhan Liu return 0; 320c52afa68SYuanhan Liu } 321d5bbeefcSYuanhan Liu 3226d890f8aSYuanhan Liu const struct virtio_pci_ops legacy_ops = { 323d5bbeefcSYuanhan Liu .read_dev_cfg = legacy_read_dev_config, 324d5bbeefcSYuanhan Liu .write_dev_cfg = legacy_write_dev_config, 325d5bbeefcSYuanhan Liu .reset = legacy_reset, 326d5bbeefcSYuanhan Liu .get_status = legacy_get_status, 327d5bbeefcSYuanhan Liu .set_status = legacy_set_status, 328d5bbeefcSYuanhan Liu .get_features = legacy_get_features, 329d5bbeefcSYuanhan Liu .set_features = legacy_set_features, 330d5bbeefcSYuanhan Liu .get_isr = legacy_get_isr, 331d5bbeefcSYuanhan Liu .set_config_irq = legacy_set_config_irq, 332c49526acSJianfeng Tan .set_queue_irq = legacy_set_queue_irq, 333d5bbeefcSYuanhan Liu .get_queue_num = legacy_get_queue_num, 334d5bbeefcSYuanhan Liu .setup_queue = legacy_setup_queue, 335d5bbeefcSYuanhan Liu .del_queue = legacy_del_queue, 336d5bbeefcSYuanhan Liu .notify_queue = legacy_notify_queue, 337d5bbeefcSYuanhan Liu }; 338d5bbeefcSYuanhan Liu 3396ba1f63bSYuanhan Liu static inline void 3406ba1f63bSYuanhan Liu io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) 3416ba1f63bSYuanhan Liu { 342*631d4ee4SSantosh Shukla rte_write32(val & ((1ULL << 32) - 1), lo); 343*631d4ee4SSantosh Shukla rte_write32(val >> 32, hi); 3446ba1f63bSYuanhan Liu } 3456ba1f63bSYuanhan Liu 3466ba1f63bSYuanhan Liu static void 3476ba1f63bSYuanhan Liu modern_read_dev_config(struct virtio_hw *hw, size_t offset, 3486ba1f63bSYuanhan Liu void *dst, int length) 3496ba1f63bSYuanhan Liu { 3506ba1f63bSYuanhan Liu int i; 3516ba1f63bSYuanhan Liu uint8_t *p; 3526ba1f63bSYuanhan Liu uint8_t old_gen, new_gen; 3536ba1f63bSYuanhan Liu 3546ba1f63bSYuanhan Liu do { 355*631d4ee4SSantosh Shukla old_gen = rte_read8(&hw->common_cfg->config_generation); 3566ba1f63bSYuanhan Liu 3576ba1f63bSYuanhan Liu p = dst; 3586ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 359*631d4ee4SSantosh Shukla *p++ = rte_read8((uint8_t *)hw->dev_cfg + offset + i); 3606ba1f63bSYuanhan Liu 361*631d4ee4SSantosh Shukla new_gen = rte_read8(&hw->common_cfg->config_generation); 3626ba1f63bSYuanhan Liu } while (old_gen != new_gen); 3636ba1f63bSYuanhan Liu } 3646ba1f63bSYuanhan Liu 3656ba1f63bSYuanhan Liu static void 3666ba1f63bSYuanhan Liu modern_write_dev_config(struct virtio_hw *hw, size_t offset, 3676ba1f63bSYuanhan Liu const void *src, int length) 3686ba1f63bSYuanhan Liu { 3696ba1f63bSYuanhan Liu int i; 3706ba1f63bSYuanhan Liu const uint8_t *p = src; 3716ba1f63bSYuanhan Liu 3726ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 373*631d4ee4SSantosh Shukla rte_write8((*p++), (((uint8_t *)hw->dev_cfg) + offset + i)); 3746ba1f63bSYuanhan Liu } 3756ba1f63bSYuanhan Liu 3766ba1f63bSYuanhan Liu static uint64_t 3776ba1f63bSYuanhan Liu modern_get_features(struct virtio_hw *hw) 3786ba1f63bSYuanhan Liu { 3796ba1f63bSYuanhan Liu uint32_t features_lo, features_hi; 3806ba1f63bSYuanhan Liu 381*631d4ee4SSantosh Shukla rte_write32(0, &hw->common_cfg->device_feature_select); 382*631d4ee4SSantosh Shukla features_lo = rte_read32(&hw->common_cfg->device_feature); 3836ba1f63bSYuanhan Liu 384*631d4ee4SSantosh Shukla rte_write32(1, &hw->common_cfg->device_feature_select); 385*631d4ee4SSantosh Shukla features_hi = rte_read32(&hw->common_cfg->device_feature); 3866ba1f63bSYuanhan Liu 3876ba1f63bSYuanhan Liu return ((uint64_t)features_hi << 32) | features_lo; 3886ba1f63bSYuanhan Liu } 3896ba1f63bSYuanhan Liu 3906ba1f63bSYuanhan Liu static void 3916ba1f63bSYuanhan Liu modern_set_features(struct virtio_hw *hw, uint64_t features) 3926ba1f63bSYuanhan Liu { 393*631d4ee4SSantosh Shukla rte_write32(0, &hw->common_cfg->guest_feature_select); 394*631d4ee4SSantosh Shukla rte_write32(features & ((1ULL << 32) - 1), 3956ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 3966ba1f63bSYuanhan Liu 397*631d4ee4SSantosh Shukla rte_write32(1, &hw->common_cfg->guest_feature_select); 398*631d4ee4SSantosh Shukla rte_write32(features >> 32, 3996ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 4006ba1f63bSYuanhan Liu } 4016ba1f63bSYuanhan Liu 4026ba1f63bSYuanhan Liu static uint8_t 4036ba1f63bSYuanhan Liu modern_get_status(struct virtio_hw *hw) 4046ba1f63bSYuanhan Liu { 405*631d4ee4SSantosh Shukla return rte_read8(&hw->common_cfg->device_status); 4066ba1f63bSYuanhan Liu } 4076ba1f63bSYuanhan Liu 4086ba1f63bSYuanhan Liu static void 4096ba1f63bSYuanhan Liu modern_set_status(struct virtio_hw *hw, uint8_t status) 4106ba1f63bSYuanhan Liu { 411*631d4ee4SSantosh Shukla rte_write8(status, &hw->common_cfg->device_status); 4126ba1f63bSYuanhan Liu } 4136ba1f63bSYuanhan Liu 4146ba1f63bSYuanhan Liu static void 4156ba1f63bSYuanhan Liu modern_reset(struct virtio_hw *hw) 4166ba1f63bSYuanhan Liu { 4176ba1f63bSYuanhan Liu modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 4186ba1f63bSYuanhan Liu modern_get_status(hw); 4196ba1f63bSYuanhan Liu } 4206ba1f63bSYuanhan Liu 4216ba1f63bSYuanhan Liu static uint8_t 4226ba1f63bSYuanhan Liu modern_get_isr(struct virtio_hw *hw) 4236ba1f63bSYuanhan Liu { 424*631d4ee4SSantosh Shukla return rte_read8(hw->isr); 4256ba1f63bSYuanhan Liu } 4266ba1f63bSYuanhan Liu 4276ba1f63bSYuanhan Liu static uint16_t 4286ba1f63bSYuanhan Liu modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) 4296ba1f63bSYuanhan Liu { 430*631d4ee4SSantosh Shukla rte_write16(vec, &hw->common_cfg->msix_config); 431*631d4ee4SSantosh Shukla return rte_read16(&hw->common_cfg->msix_config); 4326ba1f63bSYuanhan Liu } 4336ba1f63bSYuanhan Liu 4346ba1f63bSYuanhan Liu static uint16_t 435c49526acSJianfeng Tan modern_set_queue_irq(struct virtio_hw *hw, struct virtqueue *vq, uint16_t vec) 436c49526acSJianfeng Tan { 437*631d4ee4SSantosh Shukla rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 438*631d4ee4SSantosh Shukla rte_write16(vec, &hw->common_cfg->queue_msix_vector); 439*631d4ee4SSantosh Shukla return rte_read16(&hw->common_cfg->queue_msix_vector); 440c49526acSJianfeng Tan } 441c49526acSJianfeng Tan 442c49526acSJianfeng Tan static uint16_t 4436ba1f63bSYuanhan Liu modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 4446ba1f63bSYuanhan Liu { 445*631d4ee4SSantosh Shukla rte_write16(queue_id, &hw->common_cfg->queue_select); 446*631d4ee4SSantosh Shukla return rte_read16(&hw->common_cfg->queue_size); 4476ba1f63bSYuanhan Liu } 4486ba1f63bSYuanhan Liu 449595454c5SJianfeng Tan static int 4506ba1f63bSYuanhan Liu modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 4516ba1f63bSYuanhan Liu { 4526ba1f63bSYuanhan Liu uint64_t desc_addr, avail_addr, used_addr; 4536ba1f63bSYuanhan Liu uint16_t notify_off; 4546ba1f63bSYuanhan Liu 455595454c5SJianfeng Tan if (!check_vq_phys_addr_ok(vq)) 456595454c5SJianfeng Tan return -1; 457595454c5SJianfeng Tan 45801ad44fdSHuawei Xie desc_addr = vq->vq_ring_mem; 4596ba1f63bSYuanhan Liu avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); 4606ba1f63bSYuanhan Liu used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, 4616ba1f63bSYuanhan Liu ring[vq->vq_nentries]), 4626ba1f63bSYuanhan Liu VIRTIO_PCI_VRING_ALIGN); 4636ba1f63bSYuanhan Liu 464*631d4ee4SSantosh Shukla rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 4656ba1f63bSYuanhan Liu 4666ba1f63bSYuanhan Liu io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, 4676ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 4686ba1f63bSYuanhan Liu io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, 4696ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 4706ba1f63bSYuanhan Liu io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, 4716ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 4726ba1f63bSYuanhan Liu 473*631d4ee4SSantosh Shukla notify_off = rte_read16(&hw->common_cfg->queue_notify_off); 4746ba1f63bSYuanhan Liu vq->notify_addr = (void *)((uint8_t *)hw->notify_base + 4756ba1f63bSYuanhan Liu notify_off * hw->notify_off_multiplier); 4766ba1f63bSYuanhan Liu 477*631d4ee4SSantosh Shukla rte_write16(1, &hw->common_cfg->queue_enable); 4786ba1f63bSYuanhan Liu 4796ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); 4806ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr); 4816ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr); 4826ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr); 4836ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", 4846ba1f63bSYuanhan Liu vq->notify_addr, notify_off); 485595454c5SJianfeng Tan 486595454c5SJianfeng Tan return 0; 4876ba1f63bSYuanhan Liu } 4886ba1f63bSYuanhan Liu 4896ba1f63bSYuanhan Liu static void 4906ba1f63bSYuanhan Liu modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 4916ba1f63bSYuanhan Liu { 492*631d4ee4SSantosh Shukla rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 4936ba1f63bSYuanhan Liu 4946ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, 4956ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 4966ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, 4976ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 4986ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_used_lo, 4996ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 5006ba1f63bSYuanhan Liu 501*631d4ee4SSantosh Shukla rte_write16(0, &hw->common_cfg->queue_enable); 5026ba1f63bSYuanhan Liu } 5036ba1f63bSYuanhan Liu 5046ba1f63bSYuanhan Liu static void 5056ba1f63bSYuanhan Liu modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) 5066ba1f63bSYuanhan Liu { 507*631d4ee4SSantosh Shukla rte_write16(1, vq->notify_addr); 5086ba1f63bSYuanhan Liu } 5096ba1f63bSYuanhan Liu 5106d890f8aSYuanhan Liu const struct virtio_pci_ops modern_ops = { 5116ba1f63bSYuanhan Liu .read_dev_cfg = modern_read_dev_config, 5126ba1f63bSYuanhan Liu .write_dev_cfg = modern_write_dev_config, 5136ba1f63bSYuanhan Liu .reset = modern_reset, 5146ba1f63bSYuanhan Liu .get_status = modern_get_status, 5156ba1f63bSYuanhan Liu .set_status = modern_set_status, 5166ba1f63bSYuanhan Liu .get_features = modern_get_features, 5176ba1f63bSYuanhan Liu .set_features = modern_set_features, 5186ba1f63bSYuanhan Liu .get_isr = modern_get_isr, 5196ba1f63bSYuanhan Liu .set_config_irq = modern_set_config_irq, 520c49526acSJianfeng Tan .set_queue_irq = modern_set_queue_irq, 5216ba1f63bSYuanhan Liu .get_queue_num = modern_get_queue_num, 5226ba1f63bSYuanhan Liu .setup_queue = modern_setup_queue, 5236ba1f63bSYuanhan Liu .del_queue = modern_del_queue, 5246ba1f63bSYuanhan Liu .notify_queue = modern_notify_queue, 5256ba1f63bSYuanhan Liu }; 5266ba1f63bSYuanhan Liu 5276ba1f63bSYuanhan Liu 528d5bbeefcSYuanhan Liu void 529d5bbeefcSYuanhan Liu vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, 530d5bbeefcSYuanhan Liu void *dst, int length) 531d5bbeefcSYuanhan Liu { 532553f4593SYuanhan Liu VTPCI_OPS(hw)->read_dev_cfg(hw, offset, dst, length); 533d5bbeefcSYuanhan Liu } 534d5bbeefcSYuanhan Liu 535d5bbeefcSYuanhan Liu void 536d5bbeefcSYuanhan Liu vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, 537d5bbeefcSYuanhan Liu const void *src, int length) 538d5bbeefcSYuanhan Liu { 539553f4593SYuanhan Liu VTPCI_OPS(hw)->write_dev_cfg(hw, offset, src, length); 540d5bbeefcSYuanhan Liu } 541d5bbeefcSYuanhan Liu 5423891f233SYuanhan Liu uint64_t 5433891f233SYuanhan Liu vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) 5446c3169a3SBruce Richardson { 5453891f233SYuanhan Liu uint64_t features; 546d5bbeefcSYuanhan Liu 5476c3169a3SBruce Richardson /* 5486c3169a3SBruce Richardson * Limit negotiated features to what the driver, virtqueue, and 5496c3169a3SBruce Richardson * host all support. 5506c3169a3SBruce Richardson */ 5516c3169a3SBruce Richardson features = host_features & hw->guest_features; 552553f4593SYuanhan Liu VTPCI_OPS(hw)->set_features(hw, features); 5536c3169a3SBruce Richardson 5546c3169a3SBruce Richardson return features; 5556c3169a3SBruce Richardson } 5566c3169a3SBruce Richardson 5576c3169a3SBruce Richardson void 5586c3169a3SBruce Richardson vtpci_reset(struct virtio_hw *hw) 5596c3169a3SBruce Richardson { 560553f4593SYuanhan Liu VTPCI_OPS(hw)->set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 561d5bbeefcSYuanhan Liu /* flush status write */ 562553f4593SYuanhan Liu VTPCI_OPS(hw)->get_status(hw); 5636c3169a3SBruce Richardson } 5646c3169a3SBruce Richardson 5656c3169a3SBruce Richardson void 5666c3169a3SBruce Richardson vtpci_reinit_complete(struct virtio_hw *hw) 5676c3169a3SBruce Richardson { 5686c3169a3SBruce Richardson vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK); 5696c3169a3SBruce Richardson } 5706c3169a3SBruce Richardson 5716c3169a3SBruce Richardson void 5726c3169a3SBruce Richardson vtpci_set_status(struct virtio_hw *hw, uint8_t status) 5736c3169a3SBruce Richardson { 5746c3169a3SBruce Richardson if (status != VIRTIO_CONFIG_STATUS_RESET) 575553f4593SYuanhan Liu status |= VTPCI_OPS(hw)->get_status(hw); 5766c3169a3SBruce Richardson 577553f4593SYuanhan Liu VTPCI_OPS(hw)->set_status(hw, status); 5786c3169a3SBruce Richardson } 5796c3169a3SBruce Richardson 5806c3169a3SBruce Richardson uint8_t 5816ba1f63bSYuanhan Liu vtpci_get_status(struct virtio_hw *hw) 5826ba1f63bSYuanhan Liu { 583553f4593SYuanhan Liu return VTPCI_OPS(hw)->get_status(hw); 5846ba1f63bSYuanhan Liu } 5856ba1f63bSYuanhan Liu 5866ba1f63bSYuanhan Liu uint8_t 5876c3169a3SBruce Richardson vtpci_isr(struct virtio_hw *hw) 5886c3169a3SBruce Richardson { 589553f4593SYuanhan Liu return VTPCI_OPS(hw)->get_isr(hw); 5906c3169a3SBruce Richardson } 5916c3169a3SBruce Richardson 5926ba1f63bSYuanhan Liu static void * 5936ba1f63bSYuanhan Liu get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) 5946ba1f63bSYuanhan Liu { 5956ba1f63bSYuanhan Liu uint8_t bar = cap->bar; 5966ba1f63bSYuanhan Liu uint32_t length = cap->length; 5976ba1f63bSYuanhan Liu uint32_t offset = cap->offset; 5986ba1f63bSYuanhan Liu uint8_t *base; 5996ba1f63bSYuanhan Liu 6006ba1f63bSYuanhan Liu if (bar > 5) { 6016ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "invalid bar: %u", bar); 6026ba1f63bSYuanhan Liu return NULL; 6036ba1f63bSYuanhan Liu } 6046ba1f63bSYuanhan Liu 6056ba1f63bSYuanhan Liu if (offset + length < offset) { 6066ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows", 6076ba1f63bSYuanhan Liu offset, length); 6086ba1f63bSYuanhan Liu return NULL; 6096ba1f63bSYuanhan Liu } 6106ba1f63bSYuanhan Liu 6116ba1f63bSYuanhan Liu if (offset + length > dev->mem_resource[bar].len) { 6126ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6136ba1f63bSYuanhan Liu "invalid cap: overflows bar space: %u > %" PRIu64, 6146ba1f63bSYuanhan Liu offset + length, dev->mem_resource[bar].len); 6156ba1f63bSYuanhan Liu return NULL; 6166ba1f63bSYuanhan Liu } 6176ba1f63bSYuanhan Liu 6186ba1f63bSYuanhan Liu base = dev->mem_resource[bar].addr; 6196ba1f63bSYuanhan Liu if (base == NULL) { 6206ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); 6216ba1f63bSYuanhan Liu return NULL; 6226ba1f63bSYuanhan Liu } 6236ba1f63bSYuanhan Liu 6246ba1f63bSYuanhan Liu return base + offset; 6256ba1f63bSYuanhan Liu } 6266ba1f63bSYuanhan Liu 6276ba1f63bSYuanhan Liu static int 6286ba1f63bSYuanhan Liu virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) 6296ba1f63bSYuanhan Liu { 6306ba1f63bSYuanhan Liu uint8_t pos; 6316ba1f63bSYuanhan Liu struct virtio_pci_cap cap; 6326ba1f63bSYuanhan Liu int ret; 6336ba1f63bSYuanhan Liu 6347a66c72dSDavid Marchand if (rte_eal_pci_map_device(dev)) { 6356ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to map pci device!"); 6366ba1f63bSYuanhan Liu return -1; 6376ba1f63bSYuanhan Liu } 6386ba1f63bSYuanhan Liu 6396ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); 6406ba1f63bSYuanhan Liu if (ret < 0) { 6416ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); 6426ba1f63bSYuanhan Liu return -1; 6436ba1f63bSYuanhan Liu } 6446ba1f63bSYuanhan Liu 6456ba1f63bSYuanhan Liu while (pos) { 6466ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); 6476ba1f63bSYuanhan Liu if (ret < 0) { 6486ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6496ba1f63bSYuanhan Liu "failed to read pci cap at pos: %x", pos); 6506ba1f63bSYuanhan Liu break; 6516ba1f63bSYuanhan Liu } 6526ba1f63bSYuanhan Liu 6536ba1f63bSYuanhan Liu if (cap.cap_vndr != PCI_CAP_ID_VNDR) { 6546ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6556ba1f63bSYuanhan Liu "[%2x] skipping non VNDR cap id: %02x", 6566ba1f63bSYuanhan Liu pos, cap.cap_vndr); 6576ba1f63bSYuanhan Liu goto next; 6586ba1f63bSYuanhan Liu } 6596ba1f63bSYuanhan Liu 6606ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6616ba1f63bSYuanhan Liu "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", 6626ba1f63bSYuanhan Liu pos, cap.cfg_type, cap.bar, cap.offset, cap.length); 6636ba1f63bSYuanhan Liu 6646ba1f63bSYuanhan Liu switch (cap.cfg_type) { 6656ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_COMMON_CFG: 6666ba1f63bSYuanhan Liu hw->common_cfg = get_cfg_addr(dev, &cap); 6676ba1f63bSYuanhan Liu break; 6686ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_NOTIFY_CFG: 6696ba1f63bSYuanhan Liu rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, 6706ba1f63bSYuanhan Liu 4, pos + sizeof(cap)); 6716ba1f63bSYuanhan Liu hw->notify_base = get_cfg_addr(dev, &cap); 6726ba1f63bSYuanhan Liu break; 6736ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_DEVICE_CFG: 6746ba1f63bSYuanhan Liu hw->dev_cfg = get_cfg_addr(dev, &cap); 6756ba1f63bSYuanhan Liu break; 6766ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_ISR_CFG: 6776ba1f63bSYuanhan Liu hw->isr = get_cfg_addr(dev, &cap); 6786ba1f63bSYuanhan Liu break; 6796ba1f63bSYuanhan Liu } 6806ba1f63bSYuanhan Liu 6816ba1f63bSYuanhan Liu next: 6826ba1f63bSYuanhan Liu pos = cap.cap_next; 6836ba1f63bSYuanhan Liu } 6846ba1f63bSYuanhan Liu 6856ba1f63bSYuanhan Liu if (hw->common_cfg == NULL || hw->notify_base == NULL || 6866ba1f63bSYuanhan Liu hw->dev_cfg == NULL || hw->isr == NULL) { 6876ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "no modern virtio pci device found."); 6886ba1f63bSYuanhan Liu return -1; 6896ba1f63bSYuanhan Liu } 6906ba1f63bSYuanhan Liu 6916ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "found modern virtio pci device."); 6926ba1f63bSYuanhan Liu 6936ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); 6946ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); 6956ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); 6966ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", 6976ba1f63bSYuanhan Liu hw->notify_base, hw->notify_off_multiplier); 6986ba1f63bSYuanhan Liu 6996ba1f63bSYuanhan Liu return 0; 7006ba1f63bSYuanhan Liu } 7016ba1f63bSYuanhan Liu 702ac5e1d83SHuawei Xie /* 703ac5e1d83SHuawei Xie * Return -1: 704ac5e1d83SHuawei Xie * if there is error mapping with VFIO/UIO. 705ac5e1d83SHuawei Xie * if port map error when driver type is KDRV_NONE. 7067e40200cSHuawei Xie * if whitelisted but driver type is KDRV_UNKNOWN. 707ac5e1d83SHuawei Xie * Return 1 if kernel driver is managing the device. 708ac5e1d83SHuawei Xie * Return 0 on success. 709ac5e1d83SHuawei Xie */ 710d5bbeefcSYuanhan Liu int 71162a785a6SJianfeng Tan vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw, 71262a785a6SJianfeng Tan uint32_t *dev_flags) 713d5bbeefcSYuanhan Liu { 7146ba1f63bSYuanhan Liu /* 7156ba1f63bSYuanhan Liu * Try if we can succeed reading virtio pci caps, which exists 7166ba1f63bSYuanhan Liu * only on modern pci device. If failed, we fallback to legacy 7176ba1f63bSYuanhan Liu * virtio handling. 7186ba1f63bSYuanhan Liu */ 7196ba1f63bSYuanhan Liu if (virtio_read_caps(dev, hw) == 0) { 7206ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "modern virtio pci detected."); 721553f4593SYuanhan Liu virtio_hw_internal[hw->port_id].vtpci_ops = &modern_ops; 7226ba1f63bSYuanhan Liu hw->modern = 1; 72362a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 7246ba1f63bSYuanhan Liu return 0; 7256ba1f63bSYuanhan Liu } 7266ba1f63bSYuanhan Liu 7276ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); 72862a785a6SJianfeng Tan if (legacy_virtio_resource_init(dev, hw, dev_flags) < 0) { 729ac5e1d83SHuawei Xie if (dev->kdrv == RTE_KDRV_UNKNOWN && 73013a1317dSJan Viktorin (!dev->device.devargs || 73113a1317dSJan Viktorin dev->device.devargs->type != 73213a1317dSJan Viktorin RTE_DEVTYPE_WHITELISTED_PCI)) { 733ac5e1d83SHuawei Xie PMD_INIT_LOG(INFO, 734ac5e1d83SHuawei Xie "skip kernel managed virtio device."); 735ac5e1d83SHuawei Xie return 1; 736ac5e1d83SHuawei Xie } 737c52afa68SYuanhan Liu return -1; 738ac5e1d83SHuawei Xie } 7396ba1f63bSYuanhan Liu 740553f4593SYuanhan Liu virtio_hw_internal[hw->port_id].vtpci_ops = &legacy_ops; 741c52afa68SYuanhan Liu hw->use_msix = legacy_virtio_has_msix(&dev->addr); 7426ba1f63bSYuanhan Liu hw->modern = 0; 743c52afa68SYuanhan Liu 744d5bbeefcSYuanhan Liu return 0; 7456c3169a3SBruce Richardson } 746