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 58595454c5SJianfeng Tan static inline int 59595454c5SJianfeng Tan check_vq_phys_addr_ok(struct virtqueue *vq) 60595454c5SJianfeng Tan { 61595454c5SJianfeng Tan /* Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit, 62595454c5SJianfeng Tan * and only accepts 32 bit page frame number. 63595454c5SJianfeng Tan * Check if the allocated physical memory exceeds 16TB. 64595454c5SJianfeng Tan */ 65595454c5SJianfeng Tan if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >> 66595454c5SJianfeng Tan (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) { 67595454c5SJianfeng Tan PMD_INIT_LOG(ERR, "vring address shouldn't be above 16TB!"); 68595454c5SJianfeng Tan return 0; 69595454c5SJianfeng Tan } 70595454c5SJianfeng Tan 71595454c5SJianfeng Tan return 1; 72595454c5SJianfeng Tan } 73595454c5SJianfeng Tan 74281ccccbSDavid Marchand /* 75281ccccbSDavid Marchand * Since we are in legacy mode: 76281ccccbSDavid Marchand * http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf 77281ccccbSDavid Marchand * 78281ccccbSDavid Marchand * "Note that this is possible because while the virtio header is PCI (i.e. 79281ccccbSDavid Marchand * little) endian, the device-specific region is encoded in the native endian of 80281ccccbSDavid Marchand * the guest (where such distinction is applicable)." 81281ccccbSDavid Marchand * 82281ccccbSDavid Marchand * For powerpc which supports both, qemu supposes that cpu is big endian and 83281ccccbSDavid Marchand * enforces this for the virtio-net stuff. 84281ccccbSDavid Marchand */ 85d5bbeefcSYuanhan Liu static void 86d5bbeefcSYuanhan Liu legacy_read_dev_config(struct virtio_hw *hw, size_t offset, 876c3169a3SBruce Richardson void *dst, int length) 886c3169a3SBruce Richardson { 89281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64 90281ccccbSDavid Marchand int size; 91281ccccbSDavid Marchand 92281ccccbSDavid Marchand while (length > 0) { 93281ccccbSDavid Marchand if (length >= 4) { 94281ccccbSDavid Marchand size = 4; 95281ccccbSDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, size, 96281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 97281ccccbSDavid Marchand *(uint32_t *)dst = rte_be_to_cpu_32(*(uint32_t *)dst); 98281ccccbSDavid Marchand } else if (length >= 2) { 99281ccccbSDavid Marchand size = 2; 100281ccccbSDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, size, 101281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 102281ccccbSDavid Marchand *(uint16_t *)dst = rte_be_to_cpu_16(*(uint16_t *)dst); 103281ccccbSDavid Marchand } else { 104281ccccbSDavid Marchand size = 1; 105281ccccbSDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, size, 106281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 107281ccccbSDavid Marchand } 108281ccccbSDavid Marchand 109281ccccbSDavid Marchand dst = (char *)dst + size; 110281ccccbSDavid Marchand offset += size; 111281ccccbSDavid Marchand length -= size; 112281ccccbSDavid Marchand } 113281ccccbSDavid Marchand #else 114b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, dst, length, 115b8f04520SDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 116281ccccbSDavid Marchand #endif 1176c3169a3SBruce Richardson } 1186c3169a3SBruce Richardson 119d5bbeefcSYuanhan Liu static void 120d5bbeefcSYuanhan Liu legacy_write_dev_config(struct virtio_hw *hw, size_t offset, 121d5bbeefcSYuanhan Liu const void *src, int length) 1226c3169a3SBruce Richardson { 123281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64 124281ccccbSDavid Marchand union { 125281ccccbSDavid Marchand uint32_t u32; 126281ccccbSDavid Marchand uint16_t u16; 127281ccccbSDavid Marchand } tmp; 128281ccccbSDavid Marchand int size; 129281ccccbSDavid Marchand 130281ccccbSDavid Marchand while (length > 0) { 131281ccccbSDavid Marchand if (length >= 4) { 132281ccccbSDavid Marchand size = 4; 133281ccccbSDavid Marchand tmp.u32 = rte_cpu_to_be_32(*(const uint32_t *)src); 134281ccccbSDavid Marchand rte_eal_pci_ioport_write(&hw->io, &tmp.u32, size, 135281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 136281ccccbSDavid Marchand } else if (length >= 2) { 137281ccccbSDavid Marchand size = 2; 138281ccccbSDavid Marchand tmp.u16 = rte_cpu_to_be_16(*(const uint16_t *)src); 139281ccccbSDavid Marchand rte_eal_pci_ioport_write(&hw->io, &tmp.u16, size, 140281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 141281ccccbSDavid Marchand } else { 142281ccccbSDavid Marchand size = 1; 143281ccccbSDavid Marchand rte_eal_pci_ioport_write(&hw->io, src, size, 144281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 145281ccccbSDavid Marchand } 146281ccccbSDavid Marchand 147281ccccbSDavid Marchand src = (const char *)src + size; 148281ccccbSDavid Marchand offset += size; 149281ccccbSDavid Marchand length -= size; 150281ccccbSDavid Marchand } 151281ccccbSDavid Marchand #else 152b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, src, length, 153b8f04520SDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 154281ccccbSDavid Marchand #endif 1556c3169a3SBruce Richardson } 1566c3169a3SBruce Richardson 1573891f233SYuanhan Liu static uint64_t 158d5bbeefcSYuanhan Liu legacy_get_features(struct virtio_hw *hw) 159d5bbeefcSYuanhan Liu { 16036ea36efSYuanhan Liu uint32_t dst; 161b8f04520SDavid Marchand 162b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 4, VIRTIO_PCI_HOST_FEATURES); 163b8f04520SDavid Marchand return dst; 164d5bbeefcSYuanhan Liu } 165d5bbeefcSYuanhan Liu 166d5bbeefcSYuanhan Liu static void 1673891f233SYuanhan Liu legacy_set_features(struct virtio_hw *hw, uint64_t features) 168d5bbeefcSYuanhan Liu { 1693891f233SYuanhan Liu if ((features >> 32) != 0) { 1703891f233SYuanhan Liu PMD_DRV_LOG(ERR, 1713891f233SYuanhan Liu "only 32 bit features are allowed for legacy virtio!"); 1723891f233SYuanhan Liu return; 1733891f233SYuanhan Liu } 174b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &features, 4, 175b8f04520SDavid Marchand VIRTIO_PCI_GUEST_FEATURES); 176d5bbeefcSYuanhan Liu } 177d5bbeefcSYuanhan Liu 178d5bbeefcSYuanhan Liu static uint8_t 179d5bbeefcSYuanhan Liu legacy_get_status(struct virtio_hw *hw) 180d5bbeefcSYuanhan Liu { 181b8f04520SDavid Marchand uint8_t dst; 182b8f04520SDavid Marchand 183b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_STATUS); 184b8f04520SDavid Marchand return dst; 185d5bbeefcSYuanhan Liu } 186d5bbeefcSYuanhan Liu 187d5bbeefcSYuanhan Liu static void 188d5bbeefcSYuanhan Liu legacy_set_status(struct virtio_hw *hw, uint8_t status) 189d5bbeefcSYuanhan Liu { 190b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &status, 1, VIRTIO_PCI_STATUS); 191d5bbeefcSYuanhan Liu } 192d5bbeefcSYuanhan Liu 193d5bbeefcSYuanhan Liu static void 194d5bbeefcSYuanhan Liu legacy_reset(struct virtio_hw *hw) 195d5bbeefcSYuanhan Liu { 196d5bbeefcSYuanhan Liu legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 197d5bbeefcSYuanhan Liu } 198d5bbeefcSYuanhan Liu 199d5bbeefcSYuanhan Liu static uint8_t 200d5bbeefcSYuanhan Liu legacy_get_isr(struct virtio_hw *hw) 201d5bbeefcSYuanhan Liu { 202b8f04520SDavid Marchand uint8_t dst; 203b8f04520SDavid Marchand 204b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_ISR); 205b8f04520SDavid Marchand return dst; 206d5bbeefcSYuanhan Liu } 207d5bbeefcSYuanhan Liu 208d5bbeefcSYuanhan Liu /* Enable one vector (0) for Link State Intrerrupt */ 209d5bbeefcSYuanhan Liu static uint16_t 210d5bbeefcSYuanhan Liu legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec) 211d5bbeefcSYuanhan Liu { 212b8f04520SDavid Marchand uint16_t dst; 213b8f04520SDavid Marchand 214b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vec, 2, VIRTIO_MSI_CONFIG_VECTOR); 215b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_MSI_CONFIG_VECTOR); 216b8f04520SDavid Marchand return dst; 217d5bbeefcSYuanhan Liu } 218d5bbeefcSYuanhan Liu 219d5bbeefcSYuanhan Liu static uint16_t 220d5bbeefcSYuanhan Liu legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 221d5bbeefcSYuanhan Liu { 222b8f04520SDavid Marchand uint16_t dst; 223b8f04520SDavid Marchand 224b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &queue_id, 2, VIRTIO_PCI_QUEUE_SEL); 225b8f04520SDavid Marchand rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_PCI_QUEUE_NUM); 226b8f04520SDavid Marchand return dst; 227d5bbeefcSYuanhan Liu } 228d5bbeefcSYuanhan Liu 229595454c5SJianfeng Tan static int 230d5bbeefcSYuanhan Liu legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 231d5bbeefcSYuanhan Liu { 232b8f04520SDavid Marchand uint32_t src; 233d5bbeefcSYuanhan Liu 234595454c5SJianfeng Tan if (!check_vq_phys_addr_ok(vq)) 235595454c5SJianfeng Tan return -1; 236595454c5SJianfeng Tan 237b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2, 238b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 23901ad44fdSHuawei Xie src = vq->vq_ring_mem >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; 240b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN); 241595454c5SJianfeng Tan 242595454c5SJianfeng Tan return 0; 243d5bbeefcSYuanhan Liu } 244d5bbeefcSYuanhan Liu 245d5bbeefcSYuanhan Liu static void 246d5bbeefcSYuanhan Liu legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 247d5bbeefcSYuanhan Liu { 248b8f04520SDavid Marchand uint32_t src = 0; 249d5bbeefcSYuanhan Liu 250b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2, 251b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 252b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN); 253d5bbeefcSYuanhan Liu } 254d5bbeefcSYuanhan Liu 255d5bbeefcSYuanhan Liu static void 256d5bbeefcSYuanhan Liu legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) 257d5bbeefcSYuanhan Liu { 258b8f04520SDavid Marchand rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2, 259b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_NOTIFY); 260d5bbeefcSYuanhan Liu } 261d5bbeefcSYuanhan Liu 262c52afa68SYuanhan Liu #ifdef RTE_EXEC_ENV_LINUXAPP 263c52afa68SYuanhan Liu static int 264c52afa68SYuanhan Liu legacy_virtio_has_msix(const struct rte_pci_addr *loc) 265c52afa68SYuanhan Liu { 266c52afa68SYuanhan Liu DIR *d; 267c52afa68SYuanhan Liu char dirname[PATH_MAX]; 268c52afa68SYuanhan Liu 269c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), 27053c3c30cSJan Viktorin "%s/" PCI_PRI_FMT "/msi_irqs", pci_get_sysfs_path(), 271c52afa68SYuanhan Liu loc->domain, loc->bus, loc->devid, loc->function); 272c52afa68SYuanhan Liu 273c52afa68SYuanhan Liu d = opendir(dirname); 274c52afa68SYuanhan Liu if (d) 275c52afa68SYuanhan Liu closedir(d); 276c52afa68SYuanhan Liu 277693f715dSHuawei Xie return d != NULL; 278c52afa68SYuanhan Liu } 279c52afa68SYuanhan Liu #else 280c52afa68SYuanhan Liu static int 28125294cd3SDavid Marchand legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) 282c52afa68SYuanhan Liu { 283c52afa68SYuanhan Liu /* nic_uio does not enable interrupts, return 0 (false). */ 284c52afa68SYuanhan Liu return 0; 285c52afa68SYuanhan Liu } 286b8f04520SDavid Marchand #endif 287c52afa68SYuanhan Liu 288c52afa68SYuanhan Liu static int 289b8f04520SDavid Marchand legacy_virtio_resource_init(struct rte_pci_device *pci_dev, 29062a785a6SJianfeng Tan struct virtio_hw *hw, uint32_t *dev_flags) 291c52afa68SYuanhan Liu { 292b8f04520SDavid Marchand if (rte_eal_pci_ioport_map(pci_dev, 0, &hw->io) < 0) 293b8f04520SDavid Marchand return -1; 294b8f04520SDavid Marchand 295b8f04520SDavid Marchand if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN) 29662a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 297b8f04520SDavid Marchand else 29862a785a6SJianfeng Tan *dev_flags &= ~RTE_ETH_DEV_INTR_LSC; 299b8f04520SDavid Marchand 300c52afa68SYuanhan Liu return 0; 301c52afa68SYuanhan Liu } 302d5bbeefcSYuanhan Liu 303d5bbeefcSYuanhan Liu static const struct virtio_pci_ops legacy_ops = { 304d5bbeefcSYuanhan Liu .read_dev_cfg = legacy_read_dev_config, 305d5bbeefcSYuanhan Liu .write_dev_cfg = legacy_write_dev_config, 306d5bbeefcSYuanhan Liu .reset = legacy_reset, 307d5bbeefcSYuanhan Liu .get_status = legacy_get_status, 308d5bbeefcSYuanhan Liu .set_status = legacy_set_status, 309d5bbeefcSYuanhan Liu .get_features = legacy_get_features, 310d5bbeefcSYuanhan Liu .set_features = legacy_set_features, 311d5bbeefcSYuanhan Liu .get_isr = legacy_get_isr, 312d5bbeefcSYuanhan Liu .set_config_irq = legacy_set_config_irq, 313d5bbeefcSYuanhan Liu .get_queue_num = legacy_get_queue_num, 314d5bbeefcSYuanhan Liu .setup_queue = legacy_setup_queue, 315d5bbeefcSYuanhan Liu .del_queue = legacy_del_queue, 316d5bbeefcSYuanhan Liu .notify_queue = legacy_notify_queue, 317d5bbeefcSYuanhan Liu }; 318d5bbeefcSYuanhan Liu 319d5bbeefcSYuanhan Liu 3206ba1f63bSYuanhan Liu static inline uint8_t 3216ba1f63bSYuanhan Liu io_read8(uint8_t *addr) 3226ba1f63bSYuanhan Liu { 3236ba1f63bSYuanhan Liu return *(volatile uint8_t *)addr; 3246ba1f63bSYuanhan Liu } 3256ba1f63bSYuanhan Liu 3266ba1f63bSYuanhan Liu static inline void 3276ba1f63bSYuanhan Liu io_write8(uint8_t val, uint8_t *addr) 3286ba1f63bSYuanhan Liu { 3296ba1f63bSYuanhan Liu *(volatile uint8_t *)addr = val; 3306ba1f63bSYuanhan Liu } 3316ba1f63bSYuanhan Liu 3326ba1f63bSYuanhan Liu static inline uint16_t 3336ba1f63bSYuanhan Liu io_read16(uint16_t *addr) 3346ba1f63bSYuanhan Liu { 3356ba1f63bSYuanhan Liu return *(volatile uint16_t *)addr; 3366ba1f63bSYuanhan Liu } 3376ba1f63bSYuanhan Liu 3386ba1f63bSYuanhan Liu static inline void 3396ba1f63bSYuanhan Liu io_write16(uint16_t val, uint16_t *addr) 3406ba1f63bSYuanhan Liu { 3416ba1f63bSYuanhan Liu *(volatile uint16_t *)addr = val; 3426ba1f63bSYuanhan Liu } 3436ba1f63bSYuanhan Liu 3446ba1f63bSYuanhan Liu static inline uint32_t 3456ba1f63bSYuanhan Liu io_read32(uint32_t *addr) 3466ba1f63bSYuanhan Liu { 3476ba1f63bSYuanhan Liu return *(volatile uint32_t *)addr; 3486ba1f63bSYuanhan Liu } 3496ba1f63bSYuanhan Liu 3506ba1f63bSYuanhan Liu static inline void 3516ba1f63bSYuanhan Liu io_write32(uint32_t val, uint32_t *addr) 3526ba1f63bSYuanhan Liu { 3536ba1f63bSYuanhan Liu *(volatile uint32_t *)addr = val; 3546ba1f63bSYuanhan Liu } 3556ba1f63bSYuanhan Liu 3566ba1f63bSYuanhan Liu static inline void 3576ba1f63bSYuanhan Liu io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) 3586ba1f63bSYuanhan Liu { 3596ba1f63bSYuanhan Liu io_write32(val & ((1ULL << 32) - 1), lo); 3606ba1f63bSYuanhan Liu io_write32(val >> 32, hi); 3616ba1f63bSYuanhan Liu } 3626ba1f63bSYuanhan Liu 3636ba1f63bSYuanhan Liu static void 3646ba1f63bSYuanhan Liu modern_read_dev_config(struct virtio_hw *hw, size_t offset, 3656ba1f63bSYuanhan Liu void *dst, int length) 3666ba1f63bSYuanhan Liu { 3676ba1f63bSYuanhan Liu int i; 3686ba1f63bSYuanhan Liu uint8_t *p; 3696ba1f63bSYuanhan Liu uint8_t old_gen, new_gen; 3706ba1f63bSYuanhan Liu 3716ba1f63bSYuanhan Liu do { 3726ba1f63bSYuanhan Liu old_gen = io_read8(&hw->common_cfg->config_generation); 3736ba1f63bSYuanhan Liu 3746ba1f63bSYuanhan Liu p = dst; 3756ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 3766ba1f63bSYuanhan Liu *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); 3776ba1f63bSYuanhan Liu 3786ba1f63bSYuanhan Liu new_gen = io_read8(&hw->common_cfg->config_generation); 3796ba1f63bSYuanhan Liu } while (old_gen != new_gen); 3806ba1f63bSYuanhan Liu } 3816ba1f63bSYuanhan Liu 3826ba1f63bSYuanhan Liu static void 3836ba1f63bSYuanhan Liu modern_write_dev_config(struct virtio_hw *hw, size_t offset, 3846ba1f63bSYuanhan Liu const void *src, int length) 3856ba1f63bSYuanhan Liu { 3866ba1f63bSYuanhan Liu int i; 3876ba1f63bSYuanhan Liu const uint8_t *p = src; 3886ba1f63bSYuanhan Liu 3896ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 3906ba1f63bSYuanhan Liu io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); 3916ba1f63bSYuanhan Liu } 3926ba1f63bSYuanhan Liu 3936ba1f63bSYuanhan Liu static uint64_t 3946ba1f63bSYuanhan Liu modern_get_features(struct virtio_hw *hw) 3956ba1f63bSYuanhan Liu { 3966ba1f63bSYuanhan Liu uint32_t features_lo, features_hi; 3976ba1f63bSYuanhan Liu 3986ba1f63bSYuanhan Liu io_write32(0, &hw->common_cfg->device_feature_select); 3996ba1f63bSYuanhan Liu features_lo = io_read32(&hw->common_cfg->device_feature); 4006ba1f63bSYuanhan Liu 4016ba1f63bSYuanhan Liu io_write32(1, &hw->common_cfg->device_feature_select); 4026ba1f63bSYuanhan Liu features_hi = io_read32(&hw->common_cfg->device_feature); 4036ba1f63bSYuanhan Liu 4046ba1f63bSYuanhan Liu return ((uint64_t)features_hi << 32) | features_lo; 4056ba1f63bSYuanhan Liu } 4066ba1f63bSYuanhan Liu 4076ba1f63bSYuanhan Liu static void 4086ba1f63bSYuanhan Liu modern_set_features(struct virtio_hw *hw, uint64_t features) 4096ba1f63bSYuanhan Liu { 4106ba1f63bSYuanhan Liu io_write32(0, &hw->common_cfg->guest_feature_select); 4116ba1f63bSYuanhan Liu io_write32(features & ((1ULL << 32) - 1), 4126ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 4136ba1f63bSYuanhan Liu 4146ba1f63bSYuanhan Liu io_write32(1, &hw->common_cfg->guest_feature_select); 4156ba1f63bSYuanhan Liu io_write32(features >> 32, 4166ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 4176ba1f63bSYuanhan Liu } 4186ba1f63bSYuanhan Liu 4196ba1f63bSYuanhan Liu static uint8_t 4206ba1f63bSYuanhan Liu modern_get_status(struct virtio_hw *hw) 4216ba1f63bSYuanhan Liu { 4226ba1f63bSYuanhan Liu return io_read8(&hw->common_cfg->device_status); 4236ba1f63bSYuanhan Liu } 4246ba1f63bSYuanhan Liu 4256ba1f63bSYuanhan Liu static void 4266ba1f63bSYuanhan Liu modern_set_status(struct virtio_hw *hw, uint8_t status) 4276ba1f63bSYuanhan Liu { 4286ba1f63bSYuanhan Liu io_write8(status, &hw->common_cfg->device_status); 4296ba1f63bSYuanhan Liu } 4306ba1f63bSYuanhan Liu 4316ba1f63bSYuanhan Liu static void 4326ba1f63bSYuanhan Liu modern_reset(struct virtio_hw *hw) 4336ba1f63bSYuanhan Liu { 4346ba1f63bSYuanhan Liu modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 4356ba1f63bSYuanhan Liu modern_get_status(hw); 4366ba1f63bSYuanhan Liu } 4376ba1f63bSYuanhan Liu 4386ba1f63bSYuanhan Liu static uint8_t 4396ba1f63bSYuanhan Liu modern_get_isr(struct virtio_hw *hw) 4406ba1f63bSYuanhan Liu { 4416ba1f63bSYuanhan Liu return io_read8(hw->isr); 4426ba1f63bSYuanhan Liu } 4436ba1f63bSYuanhan Liu 4446ba1f63bSYuanhan Liu static uint16_t 4456ba1f63bSYuanhan Liu modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) 4466ba1f63bSYuanhan Liu { 4476ba1f63bSYuanhan Liu io_write16(vec, &hw->common_cfg->msix_config); 4486ba1f63bSYuanhan Liu return io_read16(&hw->common_cfg->msix_config); 4496ba1f63bSYuanhan Liu } 4506ba1f63bSYuanhan Liu 4516ba1f63bSYuanhan Liu static uint16_t 4526ba1f63bSYuanhan Liu modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 4536ba1f63bSYuanhan Liu { 4546ba1f63bSYuanhan Liu io_write16(queue_id, &hw->common_cfg->queue_select); 4556ba1f63bSYuanhan Liu return io_read16(&hw->common_cfg->queue_size); 4566ba1f63bSYuanhan Liu } 4576ba1f63bSYuanhan Liu 458595454c5SJianfeng Tan static int 4596ba1f63bSYuanhan Liu modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 4606ba1f63bSYuanhan Liu { 4616ba1f63bSYuanhan Liu uint64_t desc_addr, avail_addr, used_addr; 4626ba1f63bSYuanhan Liu uint16_t notify_off; 4636ba1f63bSYuanhan Liu 464595454c5SJianfeng Tan if (!check_vq_phys_addr_ok(vq)) 465595454c5SJianfeng Tan return -1; 466595454c5SJianfeng Tan 46701ad44fdSHuawei Xie desc_addr = vq->vq_ring_mem; 4686ba1f63bSYuanhan Liu avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); 4696ba1f63bSYuanhan Liu used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, 4706ba1f63bSYuanhan Liu ring[vq->vq_nentries]), 4716ba1f63bSYuanhan Liu VIRTIO_PCI_VRING_ALIGN); 4726ba1f63bSYuanhan Liu 4736ba1f63bSYuanhan Liu io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 4746ba1f63bSYuanhan Liu 4756ba1f63bSYuanhan Liu io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, 4766ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 4776ba1f63bSYuanhan Liu io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, 4786ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 4796ba1f63bSYuanhan Liu io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, 4806ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 4816ba1f63bSYuanhan Liu 4826ba1f63bSYuanhan Liu notify_off = io_read16(&hw->common_cfg->queue_notify_off); 4836ba1f63bSYuanhan Liu vq->notify_addr = (void *)((uint8_t *)hw->notify_base + 4846ba1f63bSYuanhan Liu notify_off * hw->notify_off_multiplier); 4856ba1f63bSYuanhan Liu 4866ba1f63bSYuanhan Liu io_write16(1, &hw->common_cfg->queue_enable); 4876ba1f63bSYuanhan Liu 4886ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); 4896ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr); 4906ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr); 4916ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr); 4926ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", 4936ba1f63bSYuanhan Liu vq->notify_addr, notify_off); 494595454c5SJianfeng Tan 495595454c5SJianfeng Tan return 0; 4966ba1f63bSYuanhan Liu } 4976ba1f63bSYuanhan Liu 4986ba1f63bSYuanhan Liu static void 4996ba1f63bSYuanhan Liu modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 5006ba1f63bSYuanhan Liu { 5016ba1f63bSYuanhan Liu io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 5026ba1f63bSYuanhan Liu 5036ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, 5046ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 5056ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, 5066ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 5076ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_used_lo, 5086ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 5096ba1f63bSYuanhan Liu 5106ba1f63bSYuanhan Liu io_write16(0, &hw->common_cfg->queue_enable); 5116ba1f63bSYuanhan Liu } 5126ba1f63bSYuanhan Liu 5136ba1f63bSYuanhan Liu static void 5146ba1f63bSYuanhan Liu modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) 5156ba1f63bSYuanhan Liu { 5166ba1f63bSYuanhan Liu io_write16(1, vq->notify_addr); 5176ba1f63bSYuanhan Liu } 5186ba1f63bSYuanhan Liu 5196ba1f63bSYuanhan Liu static const struct virtio_pci_ops modern_ops = { 5206ba1f63bSYuanhan Liu .read_dev_cfg = modern_read_dev_config, 5216ba1f63bSYuanhan Liu .write_dev_cfg = modern_write_dev_config, 5226ba1f63bSYuanhan Liu .reset = modern_reset, 5236ba1f63bSYuanhan Liu .get_status = modern_get_status, 5246ba1f63bSYuanhan Liu .set_status = modern_set_status, 5256ba1f63bSYuanhan Liu .get_features = modern_get_features, 5266ba1f63bSYuanhan Liu .set_features = modern_set_features, 5276ba1f63bSYuanhan Liu .get_isr = modern_get_isr, 5286ba1f63bSYuanhan Liu .set_config_irq = modern_set_config_irq, 5296ba1f63bSYuanhan Liu .get_queue_num = modern_get_queue_num, 5306ba1f63bSYuanhan Liu .setup_queue = modern_setup_queue, 5316ba1f63bSYuanhan Liu .del_queue = modern_del_queue, 5326ba1f63bSYuanhan Liu .notify_queue = modern_notify_queue, 5336ba1f63bSYuanhan Liu }; 5346ba1f63bSYuanhan Liu 5356ba1f63bSYuanhan Liu 536d5bbeefcSYuanhan Liu void 537d5bbeefcSYuanhan Liu vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, 538d5bbeefcSYuanhan Liu void *dst, int length) 539d5bbeefcSYuanhan Liu { 540*553f4593SYuanhan Liu VTPCI_OPS(hw)->read_dev_cfg(hw, offset, dst, length); 541d5bbeefcSYuanhan Liu } 542d5bbeefcSYuanhan Liu 543d5bbeefcSYuanhan Liu void 544d5bbeefcSYuanhan Liu vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, 545d5bbeefcSYuanhan Liu const void *src, int length) 546d5bbeefcSYuanhan Liu { 547*553f4593SYuanhan Liu VTPCI_OPS(hw)->write_dev_cfg(hw, offset, src, length); 548d5bbeefcSYuanhan Liu } 549d5bbeefcSYuanhan Liu 5503891f233SYuanhan Liu uint64_t 5513891f233SYuanhan Liu vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) 5526c3169a3SBruce Richardson { 5533891f233SYuanhan Liu uint64_t features; 554d5bbeefcSYuanhan Liu 5556c3169a3SBruce Richardson /* 5566c3169a3SBruce Richardson * Limit negotiated features to what the driver, virtqueue, and 5576c3169a3SBruce Richardson * host all support. 5586c3169a3SBruce Richardson */ 5596c3169a3SBruce Richardson features = host_features & hw->guest_features; 560*553f4593SYuanhan Liu VTPCI_OPS(hw)->set_features(hw, features); 5616c3169a3SBruce Richardson 5626c3169a3SBruce Richardson return features; 5636c3169a3SBruce Richardson } 5646c3169a3SBruce Richardson 5656c3169a3SBruce Richardson void 5666c3169a3SBruce Richardson vtpci_reset(struct virtio_hw *hw) 5676c3169a3SBruce Richardson { 568*553f4593SYuanhan Liu VTPCI_OPS(hw)->set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 569d5bbeefcSYuanhan Liu /* flush status write */ 570*553f4593SYuanhan Liu VTPCI_OPS(hw)->get_status(hw); 5716c3169a3SBruce Richardson } 5726c3169a3SBruce Richardson 5736c3169a3SBruce Richardson void 5746c3169a3SBruce Richardson vtpci_reinit_complete(struct virtio_hw *hw) 5756c3169a3SBruce Richardson { 5766c3169a3SBruce Richardson vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK); 5776c3169a3SBruce Richardson } 5786c3169a3SBruce Richardson 5796c3169a3SBruce Richardson void 5806c3169a3SBruce Richardson vtpci_set_status(struct virtio_hw *hw, uint8_t status) 5816c3169a3SBruce Richardson { 5826c3169a3SBruce Richardson if (status != VIRTIO_CONFIG_STATUS_RESET) 583*553f4593SYuanhan Liu status |= VTPCI_OPS(hw)->get_status(hw); 5846c3169a3SBruce Richardson 585*553f4593SYuanhan Liu VTPCI_OPS(hw)->set_status(hw, status); 5866c3169a3SBruce Richardson } 5876c3169a3SBruce Richardson 5886c3169a3SBruce Richardson uint8_t 5896ba1f63bSYuanhan Liu vtpci_get_status(struct virtio_hw *hw) 5906ba1f63bSYuanhan Liu { 591*553f4593SYuanhan Liu return VTPCI_OPS(hw)->get_status(hw); 5926ba1f63bSYuanhan Liu } 5936ba1f63bSYuanhan Liu 5946ba1f63bSYuanhan Liu uint8_t 5956c3169a3SBruce Richardson vtpci_isr(struct virtio_hw *hw) 5966c3169a3SBruce Richardson { 597*553f4593SYuanhan Liu return VTPCI_OPS(hw)->get_isr(hw); 5986c3169a3SBruce Richardson } 5996c3169a3SBruce Richardson 6006c3169a3SBruce Richardson 6016c3169a3SBruce Richardson /* Enable one vector (0) for Link State Intrerrupt */ 6026c3169a3SBruce Richardson uint16_t 6036c3169a3SBruce Richardson vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) 6046c3169a3SBruce Richardson { 605*553f4593SYuanhan Liu return VTPCI_OPS(hw)->set_config_irq(hw, vec); 606d5bbeefcSYuanhan Liu } 607d5bbeefcSYuanhan Liu 6086ba1f63bSYuanhan Liu static void * 6096ba1f63bSYuanhan Liu get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) 6106ba1f63bSYuanhan Liu { 6116ba1f63bSYuanhan Liu uint8_t bar = cap->bar; 6126ba1f63bSYuanhan Liu uint32_t length = cap->length; 6136ba1f63bSYuanhan Liu uint32_t offset = cap->offset; 6146ba1f63bSYuanhan Liu uint8_t *base; 6156ba1f63bSYuanhan Liu 6166ba1f63bSYuanhan Liu if (bar > 5) { 6176ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "invalid bar: %u", bar); 6186ba1f63bSYuanhan Liu return NULL; 6196ba1f63bSYuanhan Liu } 6206ba1f63bSYuanhan Liu 6216ba1f63bSYuanhan Liu if (offset + length < offset) { 6226ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows", 6236ba1f63bSYuanhan Liu offset, length); 6246ba1f63bSYuanhan Liu return NULL; 6256ba1f63bSYuanhan Liu } 6266ba1f63bSYuanhan Liu 6276ba1f63bSYuanhan Liu if (offset + length > dev->mem_resource[bar].len) { 6286ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6296ba1f63bSYuanhan Liu "invalid cap: overflows bar space: %u > %" PRIu64, 6306ba1f63bSYuanhan Liu offset + length, dev->mem_resource[bar].len); 6316ba1f63bSYuanhan Liu return NULL; 6326ba1f63bSYuanhan Liu } 6336ba1f63bSYuanhan Liu 6346ba1f63bSYuanhan Liu base = dev->mem_resource[bar].addr; 6356ba1f63bSYuanhan Liu if (base == NULL) { 6366ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); 6376ba1f63bSYuanhan Liu return NULL; 6386ba1f63bSYuanhan Liu } 6396ba1f63bSYuanhan Liu 6406ba1f63bSYuanhan Liu return base + offset; 6416ba1f63bSYuanhan Liu } 6426ba1f63bSYuanhan Liu 6436ba1f63bSYuanhan Liu static int 6446ba1f63bSYuanhan Liu virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) 6456ba1f63bSYuanhan Liu { 6466ba1f63bSYuanhan Liu uint8_t pos; 6476ba1f63bSYuanhan Liu struct virtio_pci_cap cap; 6486ba1f63bSYuanhan Liu int ret; 6496ba1f63bSYuanhan Liu 6507a66c72dSDavid Marchand if (rte_eal_pci_map_device(dev)) { 6516ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to map pci device!"); 6526ba1f63bSYuanhan Liu return -1; 6536ba1f63bSYuanhan Liu } 6546ba1f63bSYuanhan Liu 6556ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); 6566ba1f63bSYuanhan Liu if (ret < 0) { 6576ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); 6586ba1f63bSYuanhan Liu return -1; 6596ba1f63bSYuanhan Liu } 6606ba1f63bSYuanhan Liu 6616ba1f63bSYuanhan Liu while (pos) { 6626ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); 6636ba1f63bSYuanhan Liu if (ret < 0) { 6646ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6656ba1f63bSYuanhan Liu "failed to read pci cap at pos: %x", pos); 6666ba1f63bSYuanhan Liu break; 6676ba1f63bSYuanhan Liu } 6686ba1f63bSYuanhan Liu 6696ba1f63bSYuanhan Liu if (cap.cap_vndr != PCI_CAP_ID_VNDR) { 6706ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6716ba1f63bSYuanhan Liu "[%2x] skipping non VNDR cap id: %02x", 6726ba1f63bSYuanhan Liu pos, cap.cap_vndr); 6736ba1f63bSYuanhan Liu goto next; 6746ba1f63bSYuanhan Liu } 6756ba1f63bSYuanhan Liu 6766ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6776ba1f63bSYuanhan Liu "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", 6786ba1f63bSYuanhan Liu pos, cap.cfg_type, cap.bar, cap.offset, cap.length); 6796ba1f63bSYuanhan Liu 6806ba1f63bSYuanhan Liu switch (cap.cfg_type) { 6816ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_COMMON_CFG: 6826ba1f63bSYuanhan Liu hw->common_cfg = get_cfg_addr(dev, &cap); 6836ba1f63bSYuanhan Liu break; 6846ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_NOTIFY_CFG: 6856ba1f63bSYuanhan Liu rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, 6866ba1f63bSYuanhan Liu 4, pos + sizeof(cap)); 6876ba1f63bSYuanhan Liu hw->notify_base = get_cfg_addr(dev, &cap); 6886ba1f63bSYuanhan Liu break; 6896ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_DEVICE_CFG: 6906ba1f63bSYuanhan Liu hw->dev_cfg = get_cfg_addr(dev, &cap); 6916ba1f63bSYuanhan Liu break; 6926ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_ISR_CFG: 6936ba1f63bSYuanhan Liu hw->isr = get_cfg_addr(dev, &cap); 6946ba1f63bSYuanhan Liu break; 6956ba1f63bSYuanhan Liu } 6966ba1f63bSYuanhan Liu 6976ba1f63bSYuanhan Liu next: 6986ba1f63bSYuanhan Liu pos = cap.cap_next; 6996ba1f63bSYuanhan Liu } 7006ba1f63bSYuanhan Liu 7016ba1f63bSYuanhan Liu if (hw->common_cfg == NULL || hw->notify_base == NULL || 7026ba1f63bSYuanhan Liu hw->dev_cfg == NULL || hw->isr == NULL) { 7036ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "no modern virtio pci device found."); 7046ba1f63bSYuanhan Liu return -1; 7056ba1f63bSYuanhan Liu } 7066ba1f63bSYuanhan Liu 7076ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "found modern virtio pci device."); 7086ba1f63bSYuanhan Liu 7096ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); 7106ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); 7116ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); 7126ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", 7136ba1f63bSYuanhan Liu hw->notify_base, hw->notify_off_multiplier); 7146ba1f63bSYuanhan Liu 7156ba1f63bSYuanhan Liu return 0; 7166ba1f63bSYuanhan Liu } 7176ba1f63bSYuanhan Liu 718ac5e1d83SHuawei Xie /* 719ac5e1d83SHuawei Xie * Return -1: 720ac5e1d83SHuawei Xie * if there is error mapping with VFIO/UIO. 721ac5e1d83SHuawei Xie * if port map error when driver type is KDRV_NONE. 7227e40200cSHuawei Xie * if whitelisted but driver type is KDRV_UNKNOWN. 723ac5e1d83SHuawei Xie * Return 1 if kernel driver is managing the device. 724ac5e1d83SHuawei Xie * Return 0 on success. 725ac5e1d83SHuawei Xie */ 726d5bbeefcSYuanhan Liu int 72762a785a6SJianfeng Tan vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw, 72862a785a6SJianfeng Tan uint32_t *dev_flags) 729d5bbeefcSYuanhan Liu { 7306ba1f63bSYuanhan Liu hw->dev = dev; 731d5bbeefcSYuanhan Liu 7326ba1f63bSYuanhan Liu /* 7336ba1f63bSYuanhan Liu * Try if we can succeed reading virtio pci caps, which exists 7346ba1f63bSYuanhan Liu * only on modern pci device. If failed, we fallback to legacy 7356ba1f63bSYuanhan Liu * virtio handling. 7366ba1f63bSYuanhan Liu */ 7376ba1f63bSYuanhan Liu if (virtio_read_caps(dev, hw) == 0) { 7386ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "modern virtio pci detected."); 739*553f4593SYuanhan Liu virtio_hw_internal[hw->port_id].vtpci_ops = &modern_ops; 7406ba1f63bSYuanhan Liu hw->modern = 1; 74162a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 7426ba1f63bSYuanhan Liu return 0; 7436ba1f63bSYuanhan Liu } 7446ba1f63bSYuanhan Liu 7456ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); 74662a785a6SJianfeng Tan if (legacy_virtio_resource_init(dev, hw, dev_flags) < 0) { 747ac5e1d83SHuawei Xie if (dev->kdrv == RTE_KDRV_UNKNOWN && 74813a1317dSJan Viktorin (!dev->device.devargs || 74913a1317dSJan Viktorin dev->device.devargs->type != 75013a1317dSJan Viktorin RTE_DEVTYPE_WHITELISTED_PCI)) { 751ac5e1d83SHuawei Xie PMD_INIT_LOG(INFO, 752ac5e1d83SHuawei Xie "skip kernel managed virtio device."); 753ac5e1d83SHuawei Xie return 1; 754ac5e1d83SHuawei Xie } 755c52afa68SYuanhan Liu return -1; 756ac5e1d83SHuawei Xie } 7576ba1f63bSYuanhan Liu 758*553f4593SYuanhan Liu virtio_hw_internal[hw->port_id].vtpci_ops = &legacy_ops; 759c52afa68SYuanhan Liu hw->use_msix = legacy_virtio_has_msix(&dev->addr); 7606ba1f63bSYuanhan Liu hw->modern = 0; 761c52afa68SYuanhan Liu 762d5bbeefcSYuanhan Liu return 0; 7636c3169a3SBruce Richardson } 764