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; 951ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), 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; 1001ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), 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; 1051ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), 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 1141ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), 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); 1341ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &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); 1391ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &tmp.u16, size, 140281ccccbSDavid Marchand VIRTIO_PCI_CONFIG(hw) + offset); 141281ccccbSDavid Marchand } else { 142281ccccbSDavid Marchand size = 1; 1431ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), 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 1521ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), 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 1621ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 4, 1631ca893f1SYuanhan Liu VIRTIO_PCI_HOST_FEATURES); 164b8f04520SDavid Marchand return dst; 165d5bbeefcSYuanhan Liu } 166d5bbeefcSYuanhan Liu 167d5bbeefcSYuanhan Liu static void 1683891f233SYuanhan Liu legacy_set_features(struct virtio_hw *hw, uint64_t features) 169d5bbeefcSYuanhan Liu { 1703891f233SYuanhan Liu if ((features >> 32) != 0) { 1713891f233SYuanhan Liu PMD_DRV_LOG(ERR, 1723891f233SYuanhan Liu "only 32 bit features are allowed for legacy virtio!"); 1733891f233SYuanhan Liu return; 1743891f233SYuanhan Liu } 1751ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &features, 4, 176b8f04520SDavid Marchand VIRTIO_PCI_GUEST_FEATURES); 177d5bbeefcSYuanhan Liu } 178d5bbeefcSYuanhan Liu 179d5bbeefcSYuanhan Liu static uint8_t 180d5bbeefcSYuanhan Liu legacy_get_status(struct virtio_hw *hw) 181d5bbeefcSYuanhan Liu { 182b8f04520SDavid Marchand uint8_t dst; 183b8f04520SDavid Marchand 1841ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 1, VIRTIO_PCI_STATUS); 185b8f04520SDavid Marchand return dst; 186d5bbeefcSYuanhan Liu } 187d5bbeefcSYuanhan Liu 188d5bbeefcSYuanhan Liu static void 189d5bbeefcSYuanhan Liu legacy_set_status(struct virtio_hw *hw, uint8_t status) 190d5bbeefcSYuanhan Liu { 1911ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &status, 1, VIRTIO_PCI_STATUS); 192d5bbeefcSYuanhan Liu } 193d5bbeefcSYuanhan Liu 194d5bbeefcSYuanhan Liu static void 195d5bbeefcSYuanhan Liu legacy_reset(struct virtio_hw *hw) 196d5bbeefcSYuanhan Liu { 197d5bbeefcSYuanhan Liu legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 198d5bbeefcSYuanhan Liu } 199d5bbeefcSYuanhan Liu 200d5bbeefcSYuanhan Liu static uint8_t 201d5bbeefcSYuanhan Liu legacy_get_isr(struct virtio_hw *hw) 202d5bbeefcSYuanhan Liu { 203b8f04520SDavid Marchand uint8_t dst; 204b8f04520SDavid Marchand 2051ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 1, VIRTIO_PCI_ISR); 206b8f04520SDavid Marchand return dst; 207d5bbeefcSYuanhan Liu } 208d5bbeefcSYuanhan Liu 209d5bbeefcSYuanhan Liu /* Enable one vector (0) for Link State Intrerrupt */ 210d5bbeefcSYuanhan Liu static uint16_t 211d5bbeefcSYuanhan Liu legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec) 212d5bbeefcSYuanhan Liu { 213b8f04520SDavid Marchand uint16_t dst; 214b8f04520SDavid Marchand 2151ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vec, 2, 2161ca893f1SYuanhan Liu VIRTIO_MSI_CONFIG_VECTOR); 2171ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 2, 2181ca893f1SYuanhan Liu VIRTIO_MSI_CONFIG_VECTOR); 219b8f04520SDavid Marchand return dst; 220d5bbeefcSYuanhan Liu } 221d5bbeefcSYuanhan Liu 222d5bbeefcSYuanhan Liu static uint16_t 223d5bbeefcSYuanhan Liu legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 224d5bbeefcSYuanhan Liu { 225b8f04520SDavid Marchand uint16_t dst; 226b8f04520SDavid Marchand 2271ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &queue_id, 2, 2281ca893f1SYuanhan Liu VIRTIO_PCI_QUEUE_SEL); 2291ca893f1SYuanhan Liu rte_eal_pci_ioport_read(VTPCI_IO(hw), &dst, 2, VIRTIO_PCI_QUEUE_NUM); 230b8f04520SDavid Marchand return dst; 231d5bbeefcSYuanhan Liu } 232d5bbeefcSYuanhan Liu 233595454c5SJianfeng Tan static int 234d5bbeefcSYuanhan Liu legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 235d5bbeefcSYuanhan Liu { 236b8f04520SDavid Marchand uint32_t src; 237d5bbeefcSYuanhan Liu 238595454c5SJianfeng Tan if (!check_vq_phys_addr_ok(vq)) 239595454c5SJianfeng Tan return -1; 240595454c5SJianfeng Tan 2411ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2, 242b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 24301ad44fdSHuawei Xie src = vq->vq_ring_mem >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; 2441ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &src, 4, VIRTIO_PCI_QUEUE_PFN); 245595454c5SJianfeng Tan 246595454c5SJianfeng Tan return 0; 247d5bbeefcSYuanhan Liu } 248d5bbeefcSYuanhan Liu 249d5bbeefcSYuanhan Liu static void 250d5bbeefcSYuanhan Liu legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 251d5bbeefcSYuanhan Liu { 252b8f04520SDavid Marchand uint32_t src = 0; 253d5bbeefcSYuanhan Liu 2541ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2, 255b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL); 2561ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &src, 4, VIRTIO_PCI_QUEUE_PFN); 257d5bbeefcSYuanhan Liu } 258d5bbeefcSYuanhan Liu 259d5bbeefcSYuanhan Liu static void 260d5bbeefcSYuanhan Liu legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) 261d5bbeefcSYuanhan Liu { 2621ca893f1SYuanhan Liu rte_eal_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2, 263b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_NOTIFY); 264d5bbeefcSYuanhan Liu } 265d5bbeefcSYuanhan Liu 266c52afa68SYuanhan Liu #ifdef RTE_EXEC_ENV_LINUXAPP 267c52afa68SYuanhan Liu static int 268c52afa68SYuanhan Liu legacy_virtio_has_msix(const struct rte_pci_addr *loc) 269c52afa68SYuanhan Liu { 270c52afa68SYuanhan Liu DIR *d; 271c52afa68SYuanhan Liu char dirname[PATH_MAX]; 272c52afa68SYuanhan Liu 273c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), 27453c3c30cSJan Viktorin "%s/" PCI_PRI_FMT "/msi_irqs", pci_get_sysfs_path(), 275c52afa68SYuanhan Liu loc->domain, loc->bus, loc->devid, loc->function); 276c52afa68SYuanhan Liu 277c52afa68SYuanhan Liu d = opendir(dirname); 278c52afa68SYuanhan Liu if (d) 279c52afa68SYuanhan Liu closedir(d); 280c52afa68SYuanhan Liu 281693f715dSHuawei Xie return d != NULL; 282c52afa68SYuanhan Liu } 283c52afa68SYuanhan Liu #else 284c52afa68SYuanhan Liu static int 28525294cd3SDavid Marchand legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) 286c52afa68SYuanhan Liu { 287c52afa68SYuanhan Liu /* nic_uio does not enable interrupts, return 0 (false). */ 288c52afa68SYuanhan Liu return 0; 289c52afa68SYuanhan Liu } 290b8f04520SDavid Marchand #endif 291c52afa68SYuanhan Liu 292c52afa68SYuanhan Liu static int 293b8f04520SDavid Marchand legacy_virtio_resource_init(struct rte_pci_device *pci_dev, 29462a785a6SJianfeng Tan struct virtio_hw *hw, uint32_t *dev_flags) 295c52afa68SYuanhan Liu { 2961ca893f1SYuanhan Liu if (rte_eal_pci_ioport_map(pci_dev, 0, VTPCI_IO(hw)) < 0) 297b8f04520SDavid Marchand return -1; 298b8f04520SDavid Marchand 299b8f04520SDavid Marchand if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN) 30062a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 301b8f04520SDavid Marchand else 30262a785a6SJianfeng Tan *dev_flags &= ~RTE_ETH_DEV_INTR_LSC; 303b8f04520SDavid Marchand 304c52afa68SYuanhan Liu return 0; 305c52afa68SYuanhan Liu } 306d5bbeefcSYuanhan Liu 307*6d890f8aSYuanhan Liu const struct virtio_pci_ops legacy_ops = { 308d5bbeefcSYuanhan Liu .read_dev_cfg = legacy_read_dev_config, 309d5bbeefcSYuanhan Liu .write_dev_cfg = legacy_write_dev_config, 310d5bbeefcSYuanhan Liu .reset = legacy_reset, 311d5bbeefcSYuanhan Liu .get_status = legacy_get_status, 312d5bbeefcSYuanhan Liu .set_status = legacy_set_status, 313d5bbeefcSYuanhan Liu .get_features = legacy_get_features, 314d5bbeefcSYuanhan Liu .set_features = legacy_set_features, 315d5bbeefcSYuanhan Liu .get_isr = legacy_get_isr, 316d5bbeefcSYuanhan Liu .set_config_irq = legacy_set_config_irq, 317d5bbeefcSYuanhan Liu .get_queue_num = legacy_get_queue_num, 318d5bbeefcSYuanhan Liu .setup_queue = legacy_setup_queue, 319d5bbeefcSYuanhan Liu .del_queue = legacy_del_queue, 320d5bbeefcSYuanhan Liu .notify_queue = legacy_notify_queue, 321d5bbeefcSYuanhan Liu }; 322d5bbeefcSYuanhan Liu 323d5bbeefcSYuanhan Liu 3246ba1f63bSYuanhan Liu static inline uint8_t 3256ba1f63bSYuanhan Liu io_read8(uint8_t *addr) 3266ba1f63bSYuanhan Liu { 3276ba1f63bSYuanhan Liu return *(volatile uint8_t *)addr; 3286ba1f63bSYuanhan Liu } 3296ba1f63bSYuanhan Liu 3306ba1f63bSYuanhan Liu static inline void 3316ba1f63bSYuanhan Liu io_write8(uint8_t val, uint8_t *addr) 3326ba1f63bSYuanhan Liu { 3336ba1f63bSYuanhan Liu *(volatile uint8_t *)addr = val; 3346ba1f63bSYuanhan Liu } 3356ba1f63bSYuanhan Liu 3366ba1f63bSYuanhan Liu static inline uint16_t 3376ba1f63bSYuanhan Liu io_read16(uint16_t *addr) 3386ba1f63bSYuanhan Liu { 3396ba1f63bSYuanhan Liu return *(volatile uint16_t *)addr; 3406ba1f63bSYuanhan Liu } 3416ba1f63bSYuanhan Liu 3426ba1f63bSYuanhan Liu static inline void 3436ba1f63bSYuanhan Liu io_write16(uint16_t val, uint16_t *addr) 3446ba1f63bSYuanhan Liu { 3456ba1f63bSYuanhan Liu *(volatile uint16_t *)addr = val; 3466ba1f63bSYuanhan Liu } 3476ba1f63bSYuanhan Liu 3486ba1f63bSYuanhan Liu static inline uint32_t 3496ba1f63bSYuanhan Liu io_read32(uint32_t *addr) 3506ba1f63bSYuanhan Liu { 3516ba1f63bSYuanhan Liu return *(volatile uint32_t *)addr; 3526ba1f63bSYuanhan Liu } 3536ba1f63bSYuanhan Liu 3546ba1f63bSYuanhan Liu static inline void 3556ba1f63bSYuanhan Liu io_write32(uint32_t val, uint32_t *addr) 3566ba1f63bSYuanhan Liu { 3576ba1f63bSYuanhan Liu *(volatile uint32_t *)addr = val; 3586ba1f63bSYuanhan Liu } 3596ba1f63bSYuanhan Liu 3606ba1f63bSYuanhan Liu static inline void 3616ba1f63bSYuanhan Liu io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) 3626ba1f63bSYuanhan Liu { 3636ba1f63bSYuanhan Liu io_write32(val & ((1ULL << 32) - 1), lo); 3646ba1f63bSYuanhan Liu io_write32(val >> 32, hi); 3656ba1f63bSYuanhan Liu } 3666ba1f63bSYuanhan Liu 3676ba1f63bSYuanhan Liu static void 3686ba1f63bSYuanhan Liu modern_read_dev_config(struct virtio_hw *hw, size_t offset, 3696ba1f63bSYuanhan Liu void *dst, int length) 3706ba1f63bSYuanhan Liu { 3716ba1f63bSYuanhan Liu int i; 3726ba1f63bSYuanhan Liu uint8_t *p; 3736ba1f63bSYuanhan Liu uint8_t old_gen, new_gen; 3746ba1f63bSYuanhan Liu 3756ba1f63bSYuanhan Liu do { 3766ba1f63bSYuanhan Liu old_gen = io_read8(&hw->common_cfg->config_generation); 3776ba1f63bSYuanhan Liu 3786ba1f63bSYuanhan Liu p = dst; 3796ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 3806ba1f63bSYuanhan Liu *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); 3816ba1f63bSYuanhan Liu 3826ba1f63bSYuanhan Liu new_gen = io_read8(&hw->common_cfg->config_generation); 3836ba1f63bSYuanhan Liu } while (old_gen != new_gen); 3846ba1f63bSYuanhan Liu } 3856ba1f63bSYuanhan Liu 3866ba1f63bSYuanhan Liu static void 3876ba1f63bSYuanhan Liu modern_write_dev_config(struct virtio_hw *hw, size_t offset, 3886ba1f63bSYuanhan Liu const void *src, int length) 3896ba1f63bSYuanhan Liu { 3906ba1f63bSYuanhan Liu int i; 3916ba1f63bSYuanhan Liu const uint8_t *p = src; 3926ba1f63bSYuanhan Liu 3936ba1f63bSYuanhan Liu for (i = 0; i < length; i++) 3946ba1f63bSYuanhan Liu io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); 3956ba1f63bSYuanhan Liu } 3966ba1f63bSYuanhan Liu 3976ba1f63bSYuanhan Liu static uint64_t 3986ba1f63bSYuanhan Liu modern_get_features(struct virtio_hw *hw) 3996ba1f63bSYuanhan Liu { 4006ba1f63bSYuanhan Liu uint32_t features_lo, features_hi; 4016ba1f63bSYuanhan Liu 4026ba1f63bSYuanhan Liu io_write32(0, &hw->common_cfg->device_feature_select); 4036ba1f63bSYuanhan Liu features_lo = io_read32(&hw->common_cfg->device_feature); 4046ba1f63bSYuanhan Liu 4056ba1f63bSYuanhan Liu io_write32(1, &hw->common_cfg->device_feature_select); 4066ba1f63bSYuanhan Liu features_hi = io_read32(&hw->common_cfg->device_feature); 4076ba1f63bSYuanhan Liu 4086ba1f63bSYuanhan Liu return ((uint64_t)features_hi << 32) | features_lo; 4096ba1f63bSYuanhan Liu } 4106ba1f63bSYuanhan Liu 4116ba1f63bSYuanhan Liu static void 4126ba1f63bSYuanhan Liu modern_set_features(struct virtio_hw *hw, uint64_t features) 4136ba1f63bSYuanhan Liu { 4146ba1f63bSYuanhan Liu io_write32(0, &hw->common_cfg->guest_feature_select); 4156ba1f63bSYuanhan Liu io_write32(features & ((1ULL << 32) - 1), 4166ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 4176ba1f63bSYuanhan Liu 4186ba1f63bSYuanhan Liu io_write32(1, &hw->common_cfg->guest_feature_select); 4196ba1f63bSYuanhan Liu io_write32(features >> 32, 4206ba1f63bSYuanhan Liu &hw->common_cfg->guest_feature); 4216ba1f63bSYuanhan Liu } 4226ba1f63bSYuanhan Liu 4236ba1f63bSYuanhan Liu static uint8_t 4246ba1f63bSYuanhan Liu modern_get_status(struct virtio_hw *hw) 4256ba1f63bSYuanhan Liu { 4266ba1f63bSYuanhan Liu return io_read8(&hw->common_cfg->device_status); 4276ba1f63bSYuanhan Liu } 4286ba1f63bSYuanhan Liu 4296ba1f63bSYuanhan Liu static void 4306ba1f63bSYuanhan Liu modern_set_status(struct virtio_hw *hw, uint8_t status) 4316ba1f63bSYuanhan Liu { 4326ba1f63bSYuanhan Liu io_write8(status, &hw->common_cfg->device_status); 4336ba1f63bSYuanhan Liu } 4346ba1f63bSYuanhan Liu 4356ba1f63bSYuanhan Liu static void 4366ba1f63bSYuanhan Liu modern_reset(struct virtio_hw *hw) 4376ba1f63bSYuanhan Liu { 4386ba1f63bSYuanhan Liu modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 4396ba1f63bSYuanhan Liu modern_get_status(hw); 4406ba1f63bSYuanhan Liu } 4416ba1f63bSYuanhan Liu 4426ba1f63bSYuanhan Liu static uint8_t 4436ba1f63bSYuanhan Liu modern_get_isr(struct virtio_hw *hw) 4446ba1f63bSYuanhan Liu { 4456ba1f63bSYuanhan Liu return io_read8(hw->isr); 4466ba1f63bSYuanhan Liu } 4476ba1f63bSYuanhan Liu 4486ba1f63bSYuanhan Liu static uint16_t 4496ba1f63bSYuanhan Liu modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) 4506ba1f63bSYuanhan Liu { 4516ba1f63bSYuanhan Liu io_write16(vec, &hw->common_cfg->msix_config); 4526ba1f63bSYuanhan Liu return io_read16(&hw->common_cfg->msix_config); 4536ba1f63bSYuanhan Liu } 4546ba1f63bSYuanhan Liu 4556ba1f63bSYuanhan Liu static uint16_t 4566ba1f63bSYuanhan Liu modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 4576ba1f63bSYuanhan Liu { 4586ba1f63bSYuanhan Liu io_write16(queue_id, &hw->common_cfg->queue_select); 4596ba1f63bSYuanhan Liu return io_read16(&hw->common_cfg->queue_size); 4606ba1f63bSYuanhan Liu } 4616ba1f63bSYuanhan Liu 462595454c5SJianfeng Tan static int 4636ba1f63bSYuanhan Liu modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 4646ba1f63bSYuanhan Liu { 4656ba1f63bSYuanhan Liu uint64_t desc_addr, avail_addr, used_addr; 4666ba1f63bSYuanhan Liu uint16_t notify_off; 4676ba1f63bSYuanhan Liu 468595454c5SJianfeng Tan if (!check_vq_phys_addr_ok(vq)) 469595454c5SJianfeng Tan return -1; 470595454c5SJianfeng Tan 47101ad44fdSHuawei Xie desc_addr = vq->vq_ring_mem; 4726ba1f63bSYuanhan Liu avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); 4736ba1f63bSYuanhan Liu used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, 4746ba1f63bSYuanhan Liu ring[vq->vq_nentries]), 4756ba1f63bSYuanhan Liu VIRTIO_PCI_VRING_ALIGN); 4766ba1f63bSYuanhan Liu 4776ba1f63bSYuanhan Liu io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 4786ba1f63bSYuanhan Liu 4796ba1f63bSYuanhan Liu io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, 4806ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 4816ba1f63bSYuanhan Liu io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, 4826ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 4836ba1f63bSYuanhan Liu io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, 4846ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 4856ba1f63bSYuanhan Liu 4866ba1f63bSYuanhan Liu notify_off = io_read16(&hw->common_cfg->queue_notify_off); 4876ba1f63bSYuanhan Liu vq->notify_addr = (void *)((uint8_t *)hw->notify_base + 4886ba1f63bSYuanhan Liu notify_off * hw->notify_off_multiplier); 4896ba1f63bSYuanhan Liu 4906ba1f63bSYuanhan Liu io_write16(1, &hw->common_cfg->queue_enable); 4916ba1f63bSYuanhan Liu 4926ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); 4936ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr); 4946ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr); 4956ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr); 4966ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", 4976ba1f63bSYuanhan Liu vq->notify_addr, notify_off); 498595454c5SJianfeng Tan 499595454c5SJianfeng Tan return 0; 5006ba1f63bSYuanhan Liu } 5016ba1f63bSYuanhan Liu 5026ba1f63bSYuanhan Liu static void 5036ba1f63bSYuanhan Liu modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 5046ba1f63bSYuanhan Liu { 5056ba1f63bSYuanhan Liu io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); 5066ba1f63bSYuanhan Liu 5076ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, 5086ba1f63bSYuanhan Liu &hw->common_cfg->queue_desc_hi); 5096ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, 5106ba1f63bSYuanhan Liu &hw->common_cfg->queue_avail_hi); 5116ba1f63bSYuanhan Liu io_write64_twopart(0, &hw->common_cfg->queue_used_lo, 5126ba1f63bSYuanhan Liu &hw->common_cfg->queue_used_hi); 5136ba1f63bSYuanhan Liu 5146ba1f63bSYuanhan Liu io_write16(0, &hw->common_cfg->queue_enable); 5156ba1f63bSYuanhan Liu } 5166ba1f63bSYuanhan Liu 5176ba1f63bSYuanhan Liu static void 5186ba1f63bSYuanhan Liu modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) 5196ba1f63bSYuanhan Liu { 5206ba1f63bSYuanhan Liu io_write16(1, vq->notify_addr); 5216ba1f63bSYuanhan Liu } 5226ba1f63bSYuanhan Liu 523*6d890f8aSYuanhan Liu const struct virtio_pci_ops modern_ops = { 5246ba1f63bSYuanhan Liu .read_dev_cfg = modern_read_dev_config, 5256ba1f63bSYuanhan Liu .write_dev_cfg = modern_write_dev_config, 5266ba1f63bSYuanhan Liu .reset = modern_reset, 5276ba1f63bSYuanhan Liu .get_status = modern_get_status, 5286ba1f63bSYuanhan Liu .set_status = modern_set_status, 5296ba1f63bSYuanhan Liu .get_features = modern_get_features, 5306ba1f63bSYuanhan Liu .set_features = modern_set_features, 5316ba1f63bSYuanhan Liu .get_isr = modern_get_isr, 5326ba1f63bSYuanhan Liu .set_config_irq = modern_set_config_irq, 5336ba1f63bSYuanhan Liu .get_queue_num = modern_get_queue_num, 5346ba1f63bSYuanhan Liu .setup_queue = modern_setup_queue, 5356ba1f63bSYuanhan Liu .del_queue = modern_del_queue, 5366ba1f63bSYuanhan Liu .notify_queue = modern_notify_queue, 5376ba1f63bSYuanhan Liu }; 5386ba1f63bSYuanhan Liu 5396ba1f63bSYuanhan Liu 540d5bbeefcSYuanhan Liu void 541d5bbeefcSYuanhan Liu vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, 542d5bbeefcSYuanhan Liu void *dst, int length) 543d5bbeefcSYuanhan Liu { 544553f4593SYuanhan Liu VTPCI_OPS(hw)->read_dev_cfg(hw, offset, dst, length); 545d5bbeefcSYuanhan Liu } 546d5bbeefcSYuanhan Liu 547d5bbeefcSYuanhan Liu void 548d5bbeefcSYuanhan Liu vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, 549d5bbeefcSYuanhan Liu const void *src, int length) 550d5bbeefcSYuanhan Liu { 551553f4593SYuanhan Liu VTPCI_OPS(hw)->write_dev_cfg(hw, offset, src, length); 552d5bbeefcSYuanhan Liu } 553d5bbeefcSYuanhan Liu 5543891f233SYuanhan Liu uint64_t 5553891f233SYuanhan Liu vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) 5566c3169a3SBruce Richardson { 5573891f233SYuanhan Liu uint64_t features; 558d5bbeefcSYuanhan Liu 5596c3169a3SBruce Richardson /* 5606c3169a3SBruce Richardson * Limit negotiated features to what the driver, virtqueue, and 5616c3169a3SBruce Richardson * host all support. 5626c3169a3SBruce Richardson */ 5636c3169a3SBruce Richardson features = host_features & hw->guest_features; 564553f4593SYuanhan Liu VTPCI_OPS(hw)->set_features(hw, features); 5656c3169a3SBruce Richardson 5666c3169a3SBruce Richardson return features; 5676c3169a3SBruce Richardson } 5686c3169a3SBruce Richardson 5696c3169a3SBruce Richardson void 5706c3169a3SBruce Richardson vtpci_reset(struct virtio_hw *hw) 5716c3169a3SBruce Richardson { 572553f4593SYuanhan Liu VTPCI_OPS(hw)->set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 573d5bbeefcSYuanhan Liu /* flush status write */ 574553f4593SYuanhan Liu VTPCI_OPS(hw)->get_status(hw); 5756c3169a3SBruce Richardson } 5766c3169a3SBruce Richardson 5776c3169a3SBruce Richardson void 5786c3169a3SBruce Richardson vtpci_reinit_complete(struct virtio_hw *hw) 5796c3169a3SBruce Richardson { 5806c3169a3SBruce Richardson vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK); 5816c3169a3SBruce Richardson } 5826c3169a3SBruce Richardson 5836c3169a3SBruce Richardson void 5846c3169a3SBruce Richardson vtpci_set_status(struct virtio_hw *hw, uint8_t status) 5856c3169a3SBruce Richardson { 5866c3169a3SBruce Richardson if (status != VIRTIO_CONFIG_STATUS_RESET) 587553f4593SYuanhan Liu status |= VTPCI_OPS(hw)->get_status(hw); 5886c3169a3SBruce Richardson 589553f4593SYuanhan Liu VTPCI_OPS(hw)->set_status(hw, status); 5906c3169a3SBruce Richardson } 5916c3169a3SBruce Richardson 5926c3169a3SBruce Richardson uint8_t 5936ba1f63bSYuanhan Liu vtpci_get_status(struct virtio_hw *hw) 5946ba1f63bSYuanhan Liu { 595553f4593SYuanhan Liu return VTPCI_OPS(hw)->get_status(hw); 5966ba1f63bSYuanhan Liu } 5976ba1f63bSYuanhan Liu 5986ba1f63bSYuanhan Liu uint8_t 5996c3169a3SBruce Richardson vtpci_isr(struct virtio_hw *hw) 6006c3169a3SBruce Richardson { 601553f4593SYuanhan Liu return VTPCI_OPS(hw)->get_isr(hw); 6026c3169a3SBruce Richardson } 6036c3169a3SBruce Richardson 6046c3169a3SBruce Richardson 6056c3169a3SBruce Richardson /* Enable one vector (0) for Link State Intrerrupt */ 6066c3169a3SBruce Richardson uint16_t 6076c3169a3SBruce Richardson vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) 6086c3169a3SBruce Richardson { 609553f4593SYuanhan Liu return VTPCI_OPS(hw)->set_config_irq(hw, vec); 610d5bbeefcSYuanhan Liu } 611d5bbeefcSYuanhan Liu 6126ba1f63bSYuanhan Liu static void * 6136ba1f63bSYuanhan Liu get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) 6146ba1f63bSYuanhan Liu { 6156ba1f63bSYuanhan Liu uint8_t bar = cap->bar; 6166ba1f63bSYuanhan Liu uint32_t length = cap->length; 6176ba1f63bSYuanhan Liu uint32_t offset = cap->offset; 6186ba1f63bSYuanhan Liu uint8_t *base; 6196ba1f63bSYuanhan Liu 6206ba1f63bSYuanhan Liu if (bar > 5) { 6216ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "invalid bar: %u", bar); 6226ba1f63bSYuanhan Liu return NULL; 6236ba1f63bSYuanhan Liu } 6246ba1f63bSYuanhan Liu 6256ba1f63bSYuanhan Liu if (offset + length < offset) { 6266ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows", 6276ba1f63bSYuanhan Liu offset, length); 6286ba1f63bSYuanhan Liu return NULL; 6296ba1f63bSYuanhan Liu } 6306ba1f63bSYuanhan Liu 6316ba1f63bSYuanhan Liu if (offset + length > dev->mem_resource[bar].len) { 6326ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6336ba1f63bSYuanhan Liu "invalid cap: overflows bar space: %u > %" PRIu64, 6346ba1f63bSYuanhan Liu offset + length, dev->mem_resource[bar].len); 6356ba1f63bSYuanhan Liu return NULL; 6366ba1f63bSYuanhan Liu } 6376ba1f63bSYuanhan Liu 6386ba1f63bSYuanhan Liu base = dev->mem_resource[bar].addr; 6396ba1f63bSYuanhan Liu if (base == NULL) { 6406ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); 6416ba1f63bSYuanhan Liu return NULL; 6426ba1f63bSYuanhan Liu } 6436ba1f63bSYuanhan Liu 6446ba1f63bSYuanhan Liu return base + offset; 6456ba1f63bSYuanhan Liu } 6466ba1f63bSYuanhan Liu 6476ba1f63bSYuanhan Liu static int 6486ba1f63bSYuanhan Liu virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) 6496ba1f63bSYuanhan Liu { 6506ba1f63bSYuanhan Liu uint8_t pos; 6516ba1f63bSYuanhan Liu struct virtio_pci_cap cap; 6526ba1f63bSYuanhan Liu int ret; 6536ba1f63bSYuanhan Liu 6547a66c72dSDavid Marchand if (rte_eal_pci_map_device(dev)) { 6556ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to map pci device!"); 6566ba1f63bSYuanhan Liu return -1; 6576ba1f63bSYuanhan Liu } 6586ba1f63bSYuanhan Liu 6596ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); 6606ba1f63bSYuanhan Liu if (ret < 0) { 6616ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); 6626ba1f63bSYuanhan Liu return -1; 6636ba1f63bSYuanhan Liu } 6646ba1f63bSYuanhan Liu 6656ba1f63bSYuanhan Liu while (pos) { 6666ba1f63bSYuanhan Liu ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); 6676ba1f63bSYuanhan Liu if (ret < 0) { 6686ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, 6696ba1f63bSYuanhan Liu "failed to read pci cap at pos: %x", pos); 6706ba1f63bSYuanhan Liu break; 6716ba1f63bSYuanhan Liu } 6726ba1f63bSYuanhan Liu 6736ba1f63bSYuanhan Liu if (cap.cap_vndr != PCI_CAP_ID_VNDR) { 6746ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6756ba1f63bSYuanhan Liu "[%2x] skipping non VNDR cap id: %02x", 6766ba1f63bSYuanhan Liu pos, cap.cap_vndr); 6776ba1f63bSYuanhan Liu goto next; 6786ba1f63bSYuanhan Liu } 6796ba1f63bSYuanhan Liu 6806ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, 6816ba1f63bSYuanhan Liu "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", 6826ba1f63bSYuanhan Liu pos, cap.cfg_type, cap.bar, cap.offset, cap.length); 6836ba1f63bSYuanhan Liu 6846ba1f63bSYuanhan Liu switch (cap.cfg_type) { 6856ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_COMMON_CFG: 6866ba1f63bSYuanhan Liu hw->common_cfg = get_cfg_addr(dev, &cap); 6876ba1f63bSYuanhan Liu break; 6886ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_NOTIFY_CFG: 6896ba1f63bSYuanhan Liu rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, 6906ba1f63bSYuanhan Liu 4, pos + sizeof(cap)); 6916ba1f63bSYuanhan Liu hw->notify_base = get_cfg_addr(dev, &cap); 6926ba1f63bSYuanhan Liu break; 6936ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_DEVICE_CFG: 6946ba1f63bSYuanhan Liu hw->dev_cfg = get_cfg_addr(dev, &cap); 6956ba1f63bSYuanhan Liu break; 6966ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_ISR_CFG: 6976ba1f63bSYuanhan Liu hw->isr = get_cfg_addr(dev, &cap); 6986ba1f63bSYuanhan Liu break; 6996ba1f63bSYuanhan Liu } 7006ba1f63bSYuanhan Liu 7016ba1f63bSYuanhan Liu next: 7026ba1f63bSYuanhan Liu pos = cap.cap_next; 7036ba1f63bSYuanhan Liu } 7046ba1f63bSYuanhan Liu 7056ba1f63bSYuanhan Liu if (hw->common_cfg == NULL || hw->notify_base == NULL || 7066ba1f63bSYuanhan Liu hw->dev_cfg == NULL || hw->isr == NULL) { 7076ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "no modern virtio pci device found."); 7086ba1f63bSYuanhan Liu return -1; 7096ba1f63bSYuanhan Liu } 7106ba1f63bSYuanhan Liu 7116ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "found modern virtio pci device."); 7126ba1f63bSYuanhan Liu 7136ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); 7146ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); 7156ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); 7166ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", 7176ba1f63bSYuanhan Liu hw->notify_base, hw->notify_off_multiplier); 7186ba1f63bSYuanhan Liu 7196ba1f63bSYuanhan Liu return 0; 7206ba1f63bSYuanhan Liu } 7216ba1f63bSYuanhan Liu 722ac5e1d83SHuawei Xie /* 723ac5e1d83SHuawei Xie * Return -1: 724ac5e1d83SHuawei Xie * if there is error mapping with VFIO/UIO. 725ac5e1d83SHuawei Xie * if port map error when driver type is KDRV_NONE. 7267e40200cSHuawei Xie * if whitelisted but driver type is KDRV_UNKNOWN. 727ac5e1d83SHuawei Xie * Return 1 if kernel driver is managing the device. 728ac5e1d83SHuawei Xie * Return 0 on success. 729ac5e1d83SHuawei Xie */ 730d5bbeefcSYuanhan Liu int 73162a785a6SJianfeng Tan vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw, 73262a785a6SJianfeng Tan uint32_t *dev_flags) 733d5bbeefcSYuanhan Liu { 7346ba1f63bSYuanhan Liu hw->dev = dev; 735d5bbeefcSYuanhan Liu 7366ba1f63bSYuanhan Liu /* 7376ba1f63bSYuanhan Liu * Try if we can succeed reading virtio pci caps, which exists 7386ba1f63bSYuanhan Liu * only on modern pci device. If failed, we fallback to legacy 7396ba1f63bSYuanhan Liu * virtio handling. 7406ba1f63bSYuanhan Liu */ 7416ba1f63bSYuanhan Liu if (virtio_read_caps(dev, hw) == 0) { 7426ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "modern virtio pci detected."); 743553f4593SYuanhan Liu virtio_hw_internal[hw->port_id].vtpci_ops = &modern_ops; 7446ba1f63bSYuanhan Liu hw->modern = 1; 74562a785a6SJianfeng Tan *dev_flags |= RTE_ETH_DEV_INTR_LSC; 7466ba1f63bSYuanhan Liu return 0; 7476ba1f63bSYuanhan Liu } 7486ba1f63bSYuanhan Liu 7496ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); 75062a785a6SJianfeng Tan if (legacy_virtio_resource_init(dev, hw, dev_flags) < 0) { 751ac5e1d83SHuawei Xie if (dev->kdrv == RTE_KDRV_UNKNOWN && 75213a1317dSJan Viktorin (!dev->device.devargs || 75313a1317dSJan Viktorin dev->device.devargs->type != 75413a1317dSJan Viktorin RTE_DEVTYPE_WHITELISTED_PCI)) { 755ac5e1d83SHuawei Xie PMD_INIT_LOG(INFO, 756ac5e1d83SHuawei Xie "skip kernel managed virtio device."); 757ac5e1d83SHuawei Xie return 1; 758ac5e1d83SHuawei Xie } 759c52afa68SYuanhan Liu return -1; 760ac5e1d83SHuawei Xie } 7616ba1f63bSYuanhan Liu 762553f4593SYuanhan Liu virtio_hw_internal[hw->port_id].vtpci_ops = &legacy_ops; 763c52afa68SYuanhan Liu hw->use_msix = legacy_virtio_has_msix(&dev->addr); 7646ba1f63bSYuanhan Liu hw->modern = 0; 765c52afa68SYuanhan Liu 766d5bbeefcSYuanhan Liu return 0; 7676c3169a3SBruce Richardson } 768