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 406c3169a3SBruce Richardson #include "virtio_pci.h" 416c3169a3SBruce Richardson #include "virtio_logs.h" 42d5bbeefcSYuanhan Liu #include "virtqueue.h" 436c3169a3SBruce Richardson 446ba1f63bSYuanhan Liu /* 456ba1f63bSYuanhan Liu * Following macros are derived from linux/pci_regs.h, however, 466ba1f63bSYuanhan Liu * we can't simply include that header here, as there is no such 476ba1f63bSYuanhan Liu * file for non-Linux platform. 486ba1f63bSYuanhan Liu */ 496ba1f63bSYuanhan Liu #define PCI_CAPABILITY_LIST 0x34 506ba1f63bSYuanhan Liu #define PCI_CAP_ID_VNDR 0x09 516ba1f63bSYuanhan Liu 52b8f04520SDavid Marchand /* 53b8f04520SDavid Marchand * The remaining space is defined by each driver as the per-driver 54b8f04520SDavid Marchand * configuration space. 55b8f04520SDavid Marchand */ 56b8f04520SDavid Marchand #define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20) 57b86af7b1SYuanhan Liu 58281ccccbSDavid Marchand /* 59281ccccbSDavid Marchand * Since we are in legacy mode: 60281ccccbSDavid Marchand * http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf 61281ccccbSDavid Marchand * 62281ccccbSDavid Marchand * "Note that this is possible because while the virtio header is PCI (i.e. 63281ccccbSDavid Marchand * little) endian, the device-specific region is encoded in the native endian of 64281ccccbSDavid Marchand * the guest (where such distinction is applicable)." 65281ccccbSDavid Marchand * 66281ccccbSDavid Marchand * For powerpc which supports both, qemu supposes that cpu is big endian and 67281ccccbSDavid Marchand * enforces this for the virtio-net stuff. 68281ccccbSDavid Marchand */ 69281ccccbSDavid Marchand 70d5bbeefcSYuanhan Liu static void 71d5bbeefcSYuanhan Liu legacy_read_dev_config(struct virtio_hw *hw, size_t offset, 726c3169a3SBruce Richardson void *dst, int length) 736c3169a3SBruce Richardson { 74281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64 75281ccccbSDavid Marchand int size; 76281ccccbSDavid Marchand 77281ccccbSDavid Marchand while (length > 0) { 78281ccccbSDavid Marchand if (length >= 4) { 79281ccccbSDavid Marchand size = 4; 80281ccccbSDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, size, 81281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 82281ccccbSDavid Marchand *(uint32_t *)dst = rte_be_to_cpu_32(*(uint32_t *)dst); 83281ccccbSDavid Marchand } else if (length >= 2) { 84281ccccbSDavid Marchand size = 2; 85281ccccbSDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, size, 86281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 87281ccccbSDavid Marchand *(uint16_t *)dst = rte_be_to_cpu_16(*(uint16_t *)dst); 88281ccccbSDavid Marchand } else { 89281ccccbSDavid Marchand size = 1; 90281ccccbSDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, size, 91281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 92281ccccbSDavid Marchand } 93281ccccbSDavid Marchand 94281ccccbSDavid Marchand dst = (char *)dst + size; 95281ccccbSDavid Marchand offset += size; 96281ccccbSDavid Marchand length -= size; 97281ccccbSDavid Marchand } 98281ccccbSDavid Marchand #else 99b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, length, 100b8f04520SDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 101281ccccbSDavid Marchand #endif 1026c3169a3SBruce Richardson } 1036c3169a3SBruce Richardson 104d5bbeefcSYuanhan Liu static void 105d5bbeefcSYuanhan Liu legacy_write_dev_config(struct virtio_hw *hw, size_t offset, 106d5bbeefcSYuanhan Liu const void *src, int length) 1076c3169a3SBruce Richardson { 108281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64 109281ccccbSDavid Marchand union { 110281ccccbSDavid Marchand uint32_t u32; 111281ccccbSDavid Marchand uint16_t u16; 112281ccccbSDavid Marchand } tmp; 113281ccccbSDavid Marchand int size; 114281ccccbSDavid Marchand 115281ccccbSDavid Marchand while (length > 0) { 116281ccccbSDavid Marchand if (length >= 4) { 117281ccccbSDavid Marchand size = 4; 118281ccccbSDavid Marchand tmp.u32 = rte_cpu_to_be_32(*(const uint32_t *)src); 119281ccccbSDavid Marchand rte_eal_pci_ioport_write(&hw->io, &tmp.u32, size, 120281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 121281ccccbSDavid Marchand } else if (length >= 2) { 122281ccccbSDavid Marchand size = 2; 123281ccccbSDavid Marchand tmp.u16 = rte_cpu_to_be_16(*(const uint16_t *)src); 124281ccccbSDavid Marchand rte_eal_pci_ioport_write(&hw->io, &tmp.u16, size, 125281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 126281ccccbSDavid Marchand } else { 127281ccccbSDavid Marchand size = 1; 128281ccccbSDavid Marchand rte_eal_pci_ioport_write(&hw->io, src, size, 129281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 130281ccccbSDavid Marchand } 131281ccccbSDavid Marchand 132281ccccbSDavid Marchand src = (const char *)src + size; 133281ccccbSDavid Marchand offset += size; 134281ccccbSDavid Marchand length -= size; 135281ccccbSDavid Marchand } 136281ccccbSDavid Marchand #else 137b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, src, length, 138b8f04520SDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 139281ccccbSDavid Marchand #endif 1406c3169a3SBruce Richardson } 1416c3169a3SBruce Richardson 1423891f233SYuanhan Liu static uint64_t 143d5bbeefcSYuanhan Liu legacy_get_features(struct virtio_hw *hw) 144d5bbeefcSYuanhan Liu { 14536ea36efSYuanhan Liu uint32_t dst; 146b8f04520SDavid Marchand 147b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 4, VIRTIO_PCI_HOST_FEATURES); 148b8f04520SDavid Marchand return dst; 149d5bbeefcSYuanhan Liu } 150d5bbeefcSYuanhan Liu 151d5bbeefcSYuanhan Liu static void 1523891f233SYuanhan Liu legacy_set_features(struct virtio_hw *hw, uint64_t features) 153d5bbeefcSYuanhan Liu { 1543891f233SYuanhan Liu if ((features >> 32) != 0) { 1553891f233SYuanhan Liu PMD_DRV_LOG(ERR, 1563891f233SYuanhan Liu "only 32 bit features are allowed for legacy virtio!"); 1573891f233SYuanhan Liu return; 1583891f233SYuanhan Liu } 159b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &features, 4, 160b8f04520SDavid Marchand VIRTIO_PCI_GUEST_FEATURES); 161d5bbeefcSYuanhan Liu } 162d5bbeefcSYuanhan Liu 163d5bbeefcSYuanhan Liu static uint8_t 164d5bbeefcSYuanhan Liu legacy_get_status(struct virtio_hw *hw) 165d5bbeefcSYuanhan Liu { 166b8f04520SDavid Marchand uint8_t dst; 167b8f04520SDavid Marchand 168b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_STATUS); 169b8f04520SDavid Marchand return dst; 170d5bbeefcSYuanhan Liu } 171d5bbeefcSYuanhan Liu 172d5bbeefcSYuanhan Liu static void 173d5bbeefcSYuanhan Liu legacy_set_status(struct virtio_hw *hw, uint8_t status) 174d5bbeefcSYuanhan Liu { 175b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &status, 1, VIRTIO_PCI_STATUS); 176d5bbeefcSYuanhan Liu } 177d5bbeefcSYuanhan Liu 178d5bbeefcSYuanhan Liu static void 179d5bbeefcSYuanhan Liu legacy_reset(struct virtio_hw *hw) 180d5bbeefcSYuanhan Liu { 181d5bbeefcSYuanhan Liu legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 182d5bbeefcSYuanhan Liu } 183d5bbeefcSYuanhan Liu 184d5bbeefcSYuanhan Liu static uint8_t 185d5bbeefcSYuanhan Liu legacy_get_isr(struct virtio_hw *hw) 186d5bbeefcSYuanhan Liu { 187b8f04520SDavid Marchand uint8_t dst; 188b8f04520SDavid Marchand 189b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_ISR); 190b8f04520SDavid Marchand return dst; 191d5bbeefcSYuanhan Liu } 192d5bbeefcSYuanhan Liu 193d5bbeefcSYuanhan Liu /* Enable one vector (0) for Link State Intrerrupt */ 194d5bbeefcSYuanhan Liu static uint16_t 195d5bbeefcSYuanhan Liu legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec) 196d5bbeefcSYuanhan Liu { 197b8f04520SDavid Marchand uint16_t dst; 198b8f04520SDavid Marchand 199b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vec, 2, VIRTIO_MSI_CONFIG_VECTOR); 200b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_MSI_CONFIG_VECTOR); 201b8f04520SDavid Marchand return dst; 202d5bbeefcSYuanhan Liu } 203d5bbeefcSYuanhan Liu 204d5bbeefcSYuanhan Liu static uint16_t 205d5bbeefcSYuanhan Liu legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 206d5bbeefcSYuanhan Liu { 207b8f04520SDavid Marchand uint16_t dst; 208b8f04520SDavid Marchand 209b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &queue_id, 2, VIRTIO_PCI_QUEUE_SEL); 210b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_PCI_QUEUE_NUM); 211b8f04520SDavid Marchand return dst; 212d5bbeefcSYuanhan Liu } 213d5bbeefcSYuanhan Liu 214d5bbeefcSYuanhan Liu static void 215d5bbeefcSYuanhan Liu legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 216d5bbeefcSYuanhan Liu { 217b8f04520SDavid Marchand uint32_t src; 218d5bbeefcSYuanhan Liu 219b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2, 220b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 221*01ad44fdSHuawei Xie src = vq->vq_ring_mem >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; 222b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN); 223d5bbeefcSYuanhan Liu } 224d5bbeefcSYuanhan Liu 225d5bbeefcSYuanhan Liu static void 226d5bbeefcSYuanhan Liu legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 227d5bbeefcSYuanhan Liu { 228b8f04520SDavid Marchand uint32_t src = 0; 229d5bbeefcSYuanhan Liu 230b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2, 231b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 232b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN); 233d5bbeefcSYuanhan Liu } 234d5bbeefcSYuanhan Liu 235d5bbeefcSYuanhan Liu static void 236d5bbeefcSYuanhan Liu legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) 237d5bbeefcSYuanhan Liu { 238b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2, 239b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_NOTIFY); 240d5bbeefcSYuanhan Liu } 241d5bbeefcSYuanhan Liu 242c52afa68SYuanhan Liu #ifdef RTE_EXEC_ENV_LINUXAPP 243c52afa68SYuanhan Liu static int 244c52afa68SYuanhan Liu legacy_virtio_has_msix(const struct rte_pci_addr *loc) 245c52afa68SYuanhan Liu { 246c52afa68SYuanhan Liu DIR *d; 247c52afa68SYuanhan Liu char dirname[PATH_MAX]; 248c52afa68SYuanhan Liu 249c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), 25053c3c30cSJan Viktorin "%s/" PCI_PRI_FMT "/msi_irqs", pci_get_sysfs_path(), 251c52afa68SYuanhan Liu loc->domain, loc->bus, loc->devid, loc->function); 252c52afa68SYuanhan Liu 253c52afa68SYuanhan Liu d = opendir(dirname); 254c52afa68SYuanhan Liu if (d) 255c52afa68SYuanhan Liu closedir(d); 256c52afa68SYuanhan Liu 257693f715dSHuawei Xie return d != NULL; 258c52afa68SYuanhan Liu } 259c52afa68SYuanhan Liu #else 260c52afa68SYuanhan Liu static int 26125294cd3SDavid Marchand legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) 262c52afa68SYuanhan Liu { 263c52afa68SYuanhan Liu /* nic_uio does not enable interrupts, return 0 (false). */ 264c52afa68SYuanhan Liu return 0; 265c52afa68SYuanhan Liu } 266b8f04520SDavid Marchand #endif 267c52afa68SYuanhan Liu 268c52afa68SYuanhan Liu static int 269b8f04520SDavid Marchand legacy_virtio_resource_init(struct rte_pci_device *pci_dev, 27062a785a6SJianfeng Tan struct virtio_hw *hw, uint32_t *dev_flags) 271c52afa68SYuanhan Liu { 272b8f04520SDavid Marchand if (rte_eal_pci_ioport_map(pci_dev, 0, &hw->io) < 0) 273b8f04520SDavid Marchand return -1; 274b8f04520SDavid Marchand 275b8f04520SDavid Marchand if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN) 27662a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 277b8f04520SDavid Marchand else 27862a785a6SJianfeng Tan *dev_flags &= ~RTE_ETH_DEV_INTR_LSC; 279b8f04520SDavid Marchand 280c52afa68SYuanhan Liu return 0; 281c52afa68SYuanhan Liu } 282d5bbeefcSYuanhan Liu 283d5bbeefcSYuanhan Liu static const struct virtio_pci_ops legacy_ops = { 284d5bbeefcSYuanhan Liu .read_dev_cfg = legacy_read_dev_config, 285d5bbeefcSYuanhan Liu .write_dev_cfg = legacy_write_dev_config, 286d5bbeefcSYuanhan Liu .reset = legacy_reset, 287d5bbeefcSYuanhan Liu .get_status = legacy_get_status, 288d5bbeefcSYuanhan Liu .set_status = legacy_set_status, 289d5bbeefcSYuanhan Liu .get_features = legacy_get_features, 290d5bbeefcSYuanhan Liu .set_features = legacy_set_features, 291d5bbeefcSYuanhan Liu .get_isr = legacy_get_isr, 292d5bbeefcSYuanhan Liu .set_config_irq = legacy_set_config_irq, 293d5bbeefcSYuanhan Liu .get_queue_num = legacy_get_queue_num, 294d5bbeefcSYuanhan Liu .setup_queue = legacy_setup_queue, 295d5bbeefcSYuanhan Liu .del_queue = legacy_del_queue, 296d5bbeefcSYuanhan Liu .notify_queue = legacy_notify_queue, 297d5bbeefcSYuanhan Liu }; 298d5bbeefcSYuanhan Liu 299d5bbeefcSYuanhan Liu 3006ba1f63bSYuanhan Liu static inline uint8_t 3016ba1f63bSYuanhan Liu io_read8(uint8_t *addr) 3026ba1f63bSYuanhan Liu { 3036ba1f63bSYuanhan Liu return *(volatile uint8_t *)addr; 3046ba1f63bSYuanhan Liu } 3056ba1f63bSYuanhan Liu 3066ba1f63bSYuanhan Liu static inline void 3076ba1f63bSYuanhan Liu io_write8(uint8_t val, uint8_t *addr) 3086ba1f63bSYuanhan Liu { 3096ba1f63bSYuanhan Liu *(volatile uint8_t *)addr = val; 3106ba1f63bSYuanhan Liu } 3116ba1f63bSYuanhan Liu 3126ba1f63bSYuanhan Liu static inline uint16_t 3136ba1f63bSYuanhan Liu io_read16(uint16_t *addr) 3146ba1f63bSYuanhan Liu { 3156ba1f63bSYuanhan Liu return *(volatile uint16_t *)addr; 3166ba1f63bSYuanhan Liu } 3176ba1f63bSYuanhan Liu 3186ba1f63bSYuanhan Liu static inline void 3196ba1f63bSYuanhan Liu io_write16(uint16_t val, uint16_t *addr) 3206ba1f63bSYuanhan Liu { 3216ba1f63bSYuanhan Liu *(volatile uint16_t *)addr = val; 3226ba1f63bSYuanhan Liu } 3236ba1f63bSYuanhan Liu 3246ba1f63bSYuanhan Liu static inline uint32_t 3256ba1f63bSYuanhan Liu io_read32(uint32_t *addr) 3266ba1f63bSYuanhan Liu { 3276ba1f63bSYuanhan Liu return *(volatile uint32_t *)addr; 3286ba1f63bSYuanhan Liu } 3296ba1f63bSYuanhan Liu 3306ba1f63bSYuanhan Liu static inline void 3316ba1f63bSYuanhan Liu io_write32(uint32_t val, uint32_t *addr) 3326ba1f63bSYuanhan Liu { 3336ba1f63bSYuanhan Liu *(volatile uint32_t *)addr = val; 3346ba1f63bSYuanhan Liu } 3356ba1f63bSYuanhan Liu 3366ba1f63bSYuanhan Liu static inline void 3376ba1f63bSYuanhan Liu io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) 3386ba1f63bSYuanhan Liu { 3396ba1f63bSYuanhan Liu io_write32(val & ((1ULL << 32) - 1), lo); 3406ba1f63bSYuanhan Liu io_write32(val >> 32, hi); 3416ba1f63bSYuanhan Liu } 3426ba1f63bSYuanhan Liu 3436ba1f63bSYuanhan Liu static void 3446ba1f63bSYuanhan Liu modern_read_dev_config(struct virtio_hw *hw, size_t offset, 3456ba1f63bSYuanhan Liu void *dst, int length) 3466ba1f63bSYuanhan Liu { 3476ba1f63bSYuanhan Liu int i; 3486ba1f63bSYuanhan Liu uint8_t *p; 3496ba1f63bSYuanhan Liu uint8_t old_gen, new_gen; 3506ba1f63bSYuanhan Liu 3516ba1f63bSYuanhan Liu do { 3526ba1f63bSYuanhan Liu old_gen = io_read8(&hw->common_cfg->config_generation); 3536ba1f63bSYuanhan Liu 3546ba1f63bSYuanhan Liu p = dst; 3556ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 3566ba1f63bSYuanhan Liu *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); 3576ba1f63bSYuanhan Liu 3586ba1f63bSYuanhan Liu new_gen = io_read8(&hw->common_cfg->config_generation); 3596ba1f63bSYuanhan Liu } while (old_gen != new_gen); 3606ba1f63bSYuanhan Liu } 3616ba1f63bSYuanhan Liu 3626ba1f63bSYuanhan Liu static void 3636ba1f63bSYuanhan Liu modern_write_dev_config(struct virtio_hw *hw, size_t offset, 3646ba1f63bSYuanhan Liu const void *src, int length) 3656ba1f63bSYuanhan Liu { 3666ba1f63bSYuanhan Liu int i; 3676ba1f63bSYuanhan Liu const uint8_t *p = src; 3686ba1f63bSYuanhan Liu 3696ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 3706ba1f63bSYuanhan Liu io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); 3716ba1f63bSYuanhan Liu } 3726ba1f63bSYuanhan Liu 3736ba1f63bSYuanhan Liu static uint64_t 3746ba1f63bSYuanhan Liu modern_get_features(struct virtio_hw *hw) 3756ba1f63bSYuanhan Liu { 3766ba1f63bSYuanhan Liu uint32_t features_lo, features_hi; 3776ba1f63bSYuanhan Liu 3786ba1f63bSYuanhan Liu io_write32(0, &hw->common_cfg->device_feature_select); 3796ba1f63bSYuanhan Liu features_lo = io_read32(&hw->common_cfg->device_feature); 3806ba1f63bSYuanhan Liu 3816ba1f63bSYuanhan Liu io_write32(1, &hw->common_cfg->device_feature_select); 3826ba1f63bSYuanhan Liu features_hi = io_read32(&hw->common_cfg->device_feature); 3836ba1f63bSYuanhan Liu 3846ba1f63bSYuanhan Liu return ((uint64_t)features_hi << 32) | features_lo; 3856ba1f63bSYuanhan Liu } 3866ba1f63bSYuanhan Liu 3876ba1f63bSYuanhan Liu static void 3886ba1f63bSYuanhan Liu modern_set_features(struct virtio_hw *hw, uint64_t features) 3896ba1f63bSYuanhan Liu { 3906ba1f63bSYuanhan Liu io_write32(0, &hw->common_cfg->guest_feature_select); 3916ba1f63bSYuanhan Liu io_write32(features & ((1ULL << 32) - 1), 3926ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 3936ba1f63bSYuanhan Liu 3946ba1f63bSYuanhan Liu io_write32(1, &hw->common_cfg->guest_feature_select); 3956ba1f63bSYuanhan Liu io_write32(features >> 32, 3966ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 3976ba1f63bSYuanhan Liu } 3986ba1f63bSYuanhan Liu 3996ba1f63bSYuanhan Liu static uint8_t 4006ba1f63bSYuanhan Liu modern_get_status(struct virtio_hw *hw) 4016ba1f63bSYuanhan Liu { 4026ba1f63bSYuanhan Liu return io_read8(&hw->common_cfg->device_status); 4036ba1f63bSYuanhan Liu } 4046ba1f63bSYuanhan Liu 4056ba1f63bSYuanhan Liu static void 4066ba1f63bSYuanhan Liu modern_set_status(struct virtio_hw *hw, uint8_t status) 4076ba1f63bSYuanhan Liu { 4086ba1f63bSYuanhan Liu io_write8(status, &hw->common_cfg->device_status); 4096ba1f63bSYuanhan Liu } 4106ba1f63bSYuanhan Liu 4116ba1f63bSYuanhan Liu static void 4126ba1f63bSYuanhan Liu modern_reset(struct virtio_hw *hw) 4136ba1f63bSYuanhan Liu { 4146ba1f63bSYuanhan Liu modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 4156ba1f63bSYuanhan Liu modern_get_status(hw); 4166ba1f63bSYuanhan Liu } 4176ba1f63bSYuanhan Liu 4186ba1f63bSYuanhan Liu static uint8_t 4196ba1f63bSYuanhan Liu modern_get_isr(struct virtio_hw *hw) 4206ba1f63bSYuanhan Liu { 4216ba1f63bSYuanhan Liu return io_read8(hw->isr); 4226ba1f63bSYuanhan Liu } 4236ba1f63bSYuanhan Liu 4246ba1f63bSYuanhan Liu static uint16_t 4256ba1f63bSYuanhan Liu modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) 4266ba1f63bSYuanhan Liu { 4276ba1f63bSYuanhan Liu io_write16(vec, &hw->common_cfg->msix_config); 4286ba1f63bSYuanhan Liu return io_read16(&hw->common_cfg->msix_config); 4296ba1f63bSYuanhan Liu } 4306ba1f63bSYuanhan Liu 4316ba1f63bSYuanhan Liu static uint16_t 4326ba1f63bSYuanhan Liu modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 4336ba1f63bSYuanhan Liu { 4346ba1f63bSYuanhan Liu io_write16(queue_id, &hw->common_cfg->queue_select); 4356ba1f63bSYuanhan Liu return io_read16(&hw->common_cfg->queue_size); 4366ba1f63bSYuanhan Liu } 4376ba1f63bSYuanhan Liu 4386ba1f63bSYuanhan Liu static void 4396ba1f63bSYuanhan Liu modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 4406ba1f63bSYuanhan Liu { 4416ba1f63bSYuanhan Liu uint64_t desc_addr, avail_addr, used_addr; 4426ba1f63bSYuanhan Liu uint16_t notify_off; 4436ba1f63bSYuanhan Liu 444*01ad44fdSHuawei Xie desc_addr = vq->vq_ring_mem; 4456ba1f63bSYuanhan Liu avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); 4466ba1f63bSYuanhan Liu used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, 4476ba1f63bSYuanhan Liu ring[vq->vq_nentries]), 4486ba1f63bSYuanhan Liu VIRTIO_PCI_VRING_ALIGN); 4496ba1f63bSYuanhan Liu 4506ba1f63bSYuanhan Liu io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 4516ba1f63bSYuanhan Liu 4526ba1f63bSYuanhan Liu io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, 4536ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 4546ba1f63bSYuanhan Liu io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, 4556ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 4566ba1f63bSYuanhan Liu io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, 4576ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 4586ba1f63bSYuanhan Liu 4596ba1f63bSYuanhan Liu notify_off = io_read16(&hw->common_cfg->queue_notify_off); 4606ba1f63bSYuanhan Liu vq->notify_addr = (void *)((uint8_t *)hw->notify_base + 4616ba1f63bSYuanhan Liu notify_off * hw->notify_off_multiplier); 4626ba1f63bSYuanhan Liu 4636ba1f63bSYuanhan Liu io_write16(1, &hw->common_cfg->queue_enable); 4646ba1f63bSYuanhan Liu 4656ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); 4666ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr); 4676ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr); 4686ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr); 4696ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", 4706ba1f63bSYuanhan Liu vq->notify_addr, notify_off); 4716ba1f63bSYuanhan Liu } 4726ba1f63bSYuanhan Liu 4736ba1f63bSYuanhan Liu static void 4746ba1f63bSYuanhan Liu modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 4756ba1f63bSYuanhan Liu { 4766ba1f63bSYuanhan Liu io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 4776ba1f63bSYuanhan Liu 4786ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, 4796ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 4806ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, 4816ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 4826ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_used_lo, 4836ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 4846ba1f63bSYuanhan Liu 4856ba1f63bSYuanhan Liu io_write16(0, &hw->common_cfg->queue_enable); 4866ba1f63bSYuanhan Liu } 4876ba1f63bSYuanhan Liu 4886ba1f63bSYuanhan Liu static void 4896ba1f63bSYuanhan Liu modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) 4906ba1f63bSYuanhan Liu { 4916ba1f63bSYuanhan Liu io_write16(1, vq->notify_addr); 4926ba1f63bSYuanhan Liu } 4936ba1f63bSYuanhan Liu 4946ba1f63bSYuanhan Liu static const struct virtio_pci_ops modern_ops = { 4956ba1f63bSYuanhan Liu .read_dev_cfg = modern_read_dev_config, 4966ba1f63bSYuanhan Liu .write_dev_cfg = modern_write_dev_config, 4976ba1f63bSYuanhan Liu .reset = modern_reset, 4986ba1f63bSYuanhan Liu .get_status = modern_get_status, 4996ba1f63bSYuanhan Liu .set_status = modern_set_status, 5006ba1f63bSYuanhan Liu .get_features = modern_get_features, 5016ba1f63bSYuanhan Liu .set_features = modern_set_features, 5026ba1f63bSYuanhan Liu .get_isr = modern_get_isr, 5036ba1f63bSYuanhan Liu .set_config_irq = modern_set_config_irq, 5046ba1f63bSYuanhan Liu .get_queue_num = modern_get_queue_num, 5056ba1f63bSYuanhan Liu .setup_queue = modern_setup_queue, 5066ba1f63bSYuanhan Liu .del_queue = modern_del_queue, 5076ba1f63bSYuanhan Liu .notify_queue = modern_notify_queue, 5086ba1f63bSYuanhan Liu }; 5096ba1f63bSYuanhan Liu 5106ba1f63bSYuanhan Liu 511d5bbeefcSYuanhan Liu void 512d5bbeefcSYuanhan Liu vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, 513d5bbeefcSYuanhan Liu void *dst, int length) 514d5bbeefcSYuanhan Liu { 515d5bbeefcSYuanhan Liu hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length); 516d5bbeefcSYuanhan Liu } 517d5bbeefcSYuanhan Liu 518d5bbeefcSYuanhan Liu void 519d5bbeefcSYuanhan Liu vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, 520d5bbeefcSYuanhan Liu const void *src, int length) 521d5bbeefcSYuanhan Liu { 522d5bbeefcSYuanhan Liu hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); 523d5bbeefcSYuanhan Liu } 524d5bbeefcSYuanhan Liu 5253891f233SYuanhan Liu uint64_t 5263891f233SYuanhan Liu vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) 5276c3169a3SBruce Richardson { 5283891f233SYuanhan Liu uint64_t features; 529d5bbeefcSYuanhan Liu 5306c3169a3SBruce Richardson /* 5316c3169a3SBruce Richardson * Limit negotiated features to what the driver, virtqueue, and 5326c3169a3SBruce Richardson * host all support. 5336c3169a3SBruce Richardson */ 5346c3169a3SBruce Richardson features = host_features & hw->guest_features; 535d5bbeefcSYuanhan Liu hw->vtpci_ops->set_features(hw, features); 5366c3169a3SBruce Richardson 5376c3169a3SBruce Richardson return features; 5386c3169a3SBruce Richardson } 5396c3169a3SBruce Richardson 5406c3169a3SBruce Richardson void 5416c3169a3SBruce Richardson vtpci_reset(struct virtio_hw *hw) 5426c3169a3SBruce Richardson { 543d5bbeefcSYuanhan Liu hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 544d5bbeefcSYuanhan Liu /* flush status write */ 545d5bbeefcSYuanhan Liu hw->vtpci_ops->get_status(hw); 5466c3169a3SBruce Richardson } 5476c3169a3SBruce Richardson 5486c3169a3SBruce Richardson void 5496c3169a3SBruce Richardson vtpci_reinit_complete(struct virtio_hw *hw) 5506c3169a3SBruce Richardson { 5516c3169a3SBruce Richardson vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK); 5526c3169a3SBruce Richardson } 5536c3169a3SBruce Richardson 5546c3169a3SBruce Richardson void 5556c3169a3SBruce Richardson vtpci_set_status(struct virtio_hw *hw, uint8_t status) 5566c3169a3SBruce Richardson { 5576c3169a3SBruce Richardson if (status != VIRTIO_CONFIG_STATUS_RESET) 558d5bbeefcSYuanhan Liu status |= hw->vtpci_ops->get_status(hw); 5596c3169a3SBruce Richardson 560d5bbeefcSYuanhan Liu hw->vtpci_ops->set_status(hw, status); 5616c3169a3SBruce Richardson } 5626c3169a3SBruce Richardson 5636c3169a3SBruce Richardson uint8_t 5646ba1f63bSYuanhan Liu vtpci_get_status(struct virtio_hw *hw) 5656ba1f63bSYuanhan Liu { 5666ba1f63bSYuanhan Liu return hw->vtpci_ops->get_status(hw); 5676ba1f63bSYuanhan Liu } 5686ba1f63bSYuanhan Liu 5696ba1f63bSYuanhan Liu uint8_t 5706c3169a3SBruce Richardson vtpci_isr(struct virtio_hw *hw) 5716c3169a3SBruce Richardson { 572d5bbeefcSYuanhan Liu return hw->vtpci_ops->get_isr(hw); 5736c3169a3SBruce Richardson } 5746c3169a3SBruce Richardson 5756c3169a3SBruce Richardson 5766c3169a3SBruce Richardson /* Enable one vector (0) for Link State Intrerrupt */ 5776c3169a3SBruce Richardson uint16_t 5786c3169a3SBruce Richardson vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) 5796c3169a3SBruce Richardson { 580d5bbeefcSYuanhan Liu return hw->vtpci_ops->set_config_irq(hw, vec); 581d5bbeefcSYuanhan Liu } 582d5bbeefcSYuanhan Liu 5836ba1f63bSYuanhan Liu static void * 5846ba1f63bSYuanhan Liu get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) 5856ba1f63bSYuanhan Liu { 5866ba1f63bSYuanhan Liu uint8_t bar = cap->bar; 5876ba1f63bSYuanhan Liu uint32_t length = cap->length; 5886ba1f63bSYuanhan Liu uint32_t offset = cap->offset; 5896ba1f63bSYuanhan Liu uint8_t *base; 5906ba1f63bSYuanhan Liu 5916ba1f63bSYuanhan Liu if (bar > 5) { 5926ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "invalid bar: %u", bar); 5936ba1f63bSYuanhan Liu return NULL; 5946ba1f63bSYuanhan Liu } 5956ba1f63bSYuanhan Liu 5966ba1f63bSYuanhan Liu if (offset + length < offset) { 5976ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows", 5986ba1f63bSYuanhan Liu offset, length); 5996ba1f63bSYuanhan Liu return NULL; 6006ba1f63bSYuanhan Liu } 6016ba1f63bSYuanhan Liu 6026ba1f63bSYuanhan Liu if (offset + length > dev->mem_resource[bar].len) { 6036ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6046ba1f63bSYuanhan Liu "invalid cap: overflows bar space: %u > %" PRIu64, 6056ba1f63bSYuanhan Liu offset + length, dev->mem_resource[bar].len); 6066ba1f63bSYuanhan Liu return NULL; 6076ba1f63bSYuanhan Liu } 6086ba1f63bSYuanhan Liu 6096ba1f63bSYuanhan Liu base = dev->mem_resource[bar].addr; 6106ba1f63bSYuanhan Liu if (base == NULL) { 6116ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); 6126ba1f63bSYuanhan Liu return NULL; 6136ba1f63bSYuanhan Liu } 6146ba1f63bSYuanhan Liu 6156ba1f63bSYuanhan Liu return base + offset; 6166ba1f63bSYuanhan Liu } 6176ba1f63bSYuanhan Liu 6186ba1f63bSYuanhan Liu static int 6196ba1f63bSYuanhan Liu virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) 6206ba1f63bSYuanhan Liu { 6216ba1f63bSYuanhan Liu uint8_t pos; 6226ba1f63bSYuanhan Liu struct virtio_pci_cap cap; 6236ba1f63bSYuanhan Liu int ret; 6246ba1f63bSYuanhan Liu 6257a66c72dSDavid Marchand if (rte_eal_pci_map_device(dev)) { 6266ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to map pci device!"); 6276ba1f63bSYuanhan Liu return -1; 6286ba1f63bSYuanhan Liu } 6296ba1f63bSYuanhan Liu 6306ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); 6316ba1f63bSYuanhan Liu if (ret < 0) { 6326ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); 6336ba1f63bSYuanhan Liu return -1; 6346ba1f63bSYuanhan Liu } 6356ba1f63bSYuanhan Liu 6366ba1f63bSYuanhan Liu while (pos) { 6376ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); 6386ba1f63bSYuanhan Liu if (ret < 0) { 6396ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6406ba1f63bSYuanhan Liu "failed to read pci cap at pos: %x", pos); 6416ba1f63bSYuanhan Liu break; 6426ba1f63bSYuanhan Liu } 6436ba1f63bSYuanhan Liu 6446ba1f63bSYuanhan Liu if (cap.cap_vndr != PCI_CAP_ID_VNDR) { 6456ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6466ba1f63bSYuanhan Liu "[%2x] skipping non VNDR cap id: %02x", 6476ba1f63bSYuanhan Liu pos, cap.cap_vndr); 6486ba1f63bSYuanhan Liu goto next; 6496ba1f63bSYuanhan Liu } 6506ba1f63bSYuanhan Liu 6516ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6526ba1f63bSYuanhan Liu "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", 6536ba1f63bSYuanhan Liu pos, cap.cfg_type, cap.bar, cap.offset, cap.length); 6546ba1f63bSYuanhan Liu 6556ba1f63bSYuanhan Liu switch (cap.cfg_type) { 6566ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_COMMON_CFG: 6576ba1f63bSYuanhan Liu hw->common_cfg = get_cfg_addr(dev, &cap); 6586ba1f63bSYuanhan Liu break; 6596ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_NOTIFY_CFG: 6606ba1f63bSYuanhan Liu rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, 6616ba1f63bSYuanhan Liu 4, pos + sizeof(cap)); 6626ba1f63bSYuanhan Liu hw->notify_base = get_cfg_addr(dev, &cap); 6636ba1f63bSYuanhan Liu break; 6646ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_DEVICE_CFG: 6656ba1f63bSYuanhan Liu hw->dev_cfg = get_cfg_addr(dev, &cap); 6666ba1f63bSYuanhan Liu break; 6676ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_ISR_CFG: 6686ba1f63bSYuanhan Liu hw->isr = get_cfg_addr(dev, &cap); 6696ba1f63bSYuanhan Liu break; 6706ba1f63bSYuanhan Liu } 6716ba1f63bSYuanhan Liu 6726ba1f63bSYuanhan Liu next: 6736ba1f63bSYuanhan Liu pos = cap.cap_next; 6746ba1f63bSYuanhan Liu } 6756ba1f63bSYuanhan Liu 6766ba1f63bSYuanhan Liu if (hw->common_cfg == NULL || hw->notify_base == NULL || 6776ba1f63bSYuanhan Liu hw->dev_cfg == NULL || hw->isr == NULL) { 6786ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "no modern virtio pci device found."); 6796ba1f63bSYuanhan Liu return -1; 6806ba1f63bSYuanhan Liu } 6816ba1f63bSYuanhan Liu 6826ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "found modern virtio pci device."); 6836ba1f63bSYuanhan Liu 6846ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); 6856ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); 6866ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); 6876ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", 6886ba1f63bSYuanhan Liu hw->notify_base, hw->notify_off_multiplier); 6896ba1f63bSYuanhan Liu 6906ba1f63bSYuanhan Liu return 0; 6916ba1f63bSYuanhan Liu } 6926ba1f63bSYuanhan Liu 693ac5e1d83SHuawei Xie /* 694ac5e1d83SHuawei Xie * Return -1: 695ac5e1d83SHuawei Xie * if there is error mapping with VFIO/UIO. 696ac5e1d83SHuawei Xie * if port map error when driver type is KDRV_NONE. 697ac5e1d83SHuawei Xie * Return 1 if kernel driver is managing the device. 698ac5e1d83SHuawei Xie * Return 0 on success. 699ac5e1d83SHuawei Xie */ 700d5bbeefcSYuanhan Liu int 70162a785a6SJianfeng Tan vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw, 70262a785a6SJianfeng Tan uint32_t *dev_flags) 703d5bbeefcSYuanhan Liu { 7046ba1f63bSYuanhan Liu hw->dev = dev; 705d5bbeefcSYuanhan Liu 7066ba1f63bSYuanhan Liu /* 7076ba1f63bSYuanhan Liu * Try if we can succeed reading virtio pci caps, which exists 7086ba1f63bSYuanhan Liu * only on modern pci device. If failed, we fallback to legacy 7096ba1f63bSYuanhan Liu * virtio handling. 7106ba1f63bSYuanhan Liu */ 7116ba1f63bSYuanhan Liu if (virtio_read_caps(dev, hw) == 0) { 7126ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "modern virtio pci detected."); 7136ba1f63bSYuanhan Liu hw->vtpci_ops = &modern_ops; 7146ba1f63bSYuanhan Liu hw->modern = 1; 71562a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 7166ba1f63bSYuanhan Liu return 0; 7176ba1f63bSYuanhan Liu } 7186ba1f63bSYuanhan Liu 7196ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); 72062a785a6SJianfeng Tan if (legacy_virtio_resource_init(dev, hw, dev_flags) < 0) { 721ac5e1d83SHuawei Xie if (dev->kdrv == RTE_KDRV_UNKNOWN && 722ac5e1d83SHuawei Xie dev->devargs->type != RTE_DEVTYPE_WHITELISTED_PCI) { 723ac5e1d83SHuawei Xie PMD_INIT_LOG(INFO, 724ac5e1d83SHuawei Xie "skip kernel managed virtio device."); 725ac5e1d83SHuawei Xie return 1; 726ac5e1d83SHuawei Xie } 727c52afa68SYuanhan Liu return -1; 728ac5e1d83SHuawei Xie } 7296ba1f63bSYuanhan Liu 7306ba1f63bSYuanhan Liu hw->vtpci_ops = &legacy_ops; 731c52afa68SYuanhan Liu hw->use_msix = legacy_virtio_has_msix(&dev->addr); 7326ba1f63bSYuanhan Liu hw->modern = 0; 733c52afa68SYuanhan Liu 734d5bbeefcSYuanhan Liu return 0; 7356c3169a3SBruce Richardson } 736