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 35*c52afa68SYuanhan Liu #ifdef RTE_EXEC_ENV_LINUXAPP 36*c52afa68SYuanhan Liu #include <dirent.h> 37*c52afa68SYuanhan Liu #include <fcntl.h> 38*c52afa68SYuanhan Liu #endif 39*c52afa68SYuanhan Liu 406c3169a3SBruce Richardson #include "virtio_pci.h" 416c3169a3SBruce Richardson #include "virtio_logs.h" 42d5bbeefcSYuanhan Liu #include "virtqueue.h" 436c3169a3SBruce Richardson 44d5bbeefcSYuanhan Liu static void 45d5bbeefcSYuanhan Liu legacy_read_dev_config(struct virtio_hw *hw, size_t offset, 466c3169a3SBruce Richardson void *dst, int length) 476c3169a3SBruce Richardson { 486c3169a3SBruce Richardson uint64_t off; 496c3169a3SBruce Richardson uint8_t *d; 506c3169a3SBruce Richardson int size; 516c3169a3SBruce Richardson 526c3169a3SBruce Richardson off = VIRTIO_PCI_CONFIG(hw) + offset; 536c3169a3SBruce Richardson for (d = dst; length > 0; d += size, off += size, length -= size) { 546c3169a3SBruce Richardson if (length >= 4) { 556c3169a3SBruce Richardson size = 4; 566c3169a3SBruce Richardson *(uint32_t *)d = VIRTIO_READ_REG_4(hw, off); 576c3169a3SBruce Richardson } else if (length >= 2) { 586c3169a3SBruce Richardson size = 2; 596c3169a3SBruce Richardson *(uint16_t *)d = VIRTIO_READ_REG_2(hw, off); 606c3169a3SBruce Richardson } else { 616c3169a3SBruce Richardson size = 1; 626c3169a3SBruce Richardson *d = VIRTIO_READ_REG_1(hw, off); 636c3169a3SBruce Richardson } 646c3169a3SBruce Richardson } 656c3169a3SBruce Richardson } 666c3169a3SBruce Richardson 67d5bbeefcSYuanhan Liu static void 68d5bbeefcSYuanhan Liu legacy_write_dev_config(struct virtio_hw *hw, size_t offset, 69d5bbeefcSYuanhan Liu const void *src, int length) 706c3169a3SBruce Richardson { 716c3169a3SBruce Richardson uint64_t off; 72d5bbeefcSYuanhan Liu const uint8_t *s; 736c3169a3SBruce Richardson int size; 746c3169a3SBruce Richardson 756c3169a3SBruce Richardson off = VIRTIO_PCI_CONFIG(hw) + offset; 766c3169a3SBruce Richardson for (s = src; length > 0; s += size, off += size, length -= size) { 776c3169a3SBruce Richardson if (length >= 4) { 786c3169a3SBruce Richardson size = 4; 79d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s); 806c3169a3SBruce Richardson } else if (length >= 2) { 816c3169a3SBruce Richardson size = 2; 82d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s); 836c3169a3SBruce Richardson } else { 846c3169a3SBruce Richardson size = 1; 856c3169a3SBruce Richardson VIRTIO_WRITE_REG_1(hw, off, *s); 866c3169a3SBruce Richardson } 876c3169a3SBruce Richardson } 886c3169a3SBruce Richardson } 896c3169a3SBruce Richardson 90d5bbeefcSYuanhan Liu static uint32_t 91d5bbeefcSYuanhan Liu legacy_get_features(struct virtio_hw *hw) 92d5bbeefcSYuanhan Liu { 93d5bbeefcSYuanhan Liu return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES); 94d5bbeefcSYuanhan Liu } 95d5bbeefcSYuanhan Liu 96d5bbeefcSYuanhan Liu static void 97d5bbeefcSYuanhan Liu legacy_set_features(struct virtio_hw *hw, uint32_t features) 98d5bbeefcSYuanhan Liu { 99d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); 100d5bbeefcSYuanhan Liu } 101d5bbeefcSYuanhan Liu 102d5bbeefcSYuanhan Liu static uint8_t 103d5bbeefcSYuanhan Liu legacy_get_status(struct virtio_hw *hw) 104d5bbeefcSYuanhan Liu { 105d5bbeefcSYuanhan Liu return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS); 106d5bbeefcSYuanhan Liu } 107d5bbeefcSYuanhan Liu 108d5bbeefcSYuanhan Liu static void 109d5bbeefcSYuanhan Liu legacy_set_status(struct virtio_hw *hw, uint8_t status) 110d5bbeefcSYuanhan Liu { 111d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status); 112d5bbeefcSYuanhan Liu } 113d5bbeefcSYuanhan Liu 114d5bbeefcSYuanhan Liu static void 115d5bbeefcSYuanhan Liu legacy_reset(struct virtio_hw *hw) 116d5bbeefcSYuanhan Liu { 117d5bbeefcSYuanhan Liu legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 118d5bbeefcSYuanhan Liu } 119d5bbeefcSYuanhan Liu 120d5bbeefcSYuanhan Liu static uint8_t 121d5bbeefcSYuanhan Liu legacy_get_isr(struct virtio_hw *hw) 122d5bbeefcSYuanhan Liu { 123d5bbeefcSYuanhan Liu return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR); 124d5bbeefcSYuanhan Liu } 125d5bbeefcSYuanhan Liu 126d5bbeefcSYuanhan Liu /* Enable one vector (0) for Link State Intrerrupt */ 127d5bbeefcSYuanhan Liu static uint16_t 128d5bbeefcSYuanhan Liu legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec) 129d5bbeefcSYuanhan Liu { 130d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec); 131d5bbeefcSYuanhan Liu return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR); 132d5bbeefcSYuanhan Liu } 133d5bbeefcSYuanhan Liu 134d5bbeefcSYuanhan Liu static uint16_t 135d5bbeefcSYuanhan Liu legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) 136d5bbeefcSYuanhan Liu { 137d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id); 138d5bbeefcSYuanhan Liu return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM); 139d5bbeefcSYuanhan Liu } 140d5bbeefcSYuanhan Liu 141d5bbeefcSYuanhan Liu static void 142d5bbeefcSYuanhan Liu legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) 143d5bbeefcSYuanhan Liu { 144d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index); 145d5bbeefcSYuanhan Liu 146d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 147d5bbeefcSYuanhan Liu vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); 148d5bbeefcSYuanhan Liu } 149d5bbeefcSYuanhan Liu 150d5bbeefcSYuanhan Liu static void 151d5bbeefcSYuanhan Liu legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq) 152d5bbeefcSYuanhan Liu { 153d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index); 154d5bbeefcSYuanhan Liu 155d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0); 156d5bbeefcSYuanhan Liu } 157d5bbeefcSYuanhan Liu 158d5bbeefcSYuanhan Liu static void 159d5bbeefcSYuanhan Liu legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) 160d5bbeefcSYuanhan Liu { 161d5bbeefcSYuanhan Liu VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); 162d5bbeefcSYuanhan Liu } 163d5bbeefcSYuanhan Liu 164*c52afa68SYuanhan Liu #ifdef RTE_EXEC_ENV_LINUXAPP 165*c52afa68SYuanhan Liu static int 166*c52afa68SYuanhan Liu parse_sysfs_value(const char *filename, unsigned long *val) 167*c52afa68SYuanhan Liu { 168*c52afa68SYuanhan Liu FILE *f; 169*c52afa68SYuanhan Liu char buf[BUFSIZ]; 170*c52afa68SYuanhan Liu char *end = NULL; 171*c52afa68SYuanhan Liu 172*c52afa68SYuanhan Liu f = fopen(filename, "r"); 173*c52afa68SYuanhan Liu if (f == NULL) { 174*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", 175*c52afa68SYuanhan Liu __func__, filename); 176*c52afa68SYuanhan Liu return -1; 177*c52afa68SYuanhan Liu } 178*c52afa68SYuanhan Liu 179*c52afa68SYuanhan Liu if (fgets(buf, sizeof(buf), f) == NULL) { 180*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", 181*c52afa68SYuanhan Liu __func__, filename); 182*c52afa68SYuanhan Liu fclose(f); 183*c52afa68SYuanhan Liu return -1; 184*c52afa68SYuanhan Liu } 185*c52afa68SYuanhan Liu *val = strtoul(buf, &end, 0); 186*c52afa68SYuanhan Liu if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { 187*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", 188*c52afa68SYuanhan Liu __func__, filename); 189*c52afa68SYuanhan Liu fclose(f); 190*c52afa68SYuanhan Liu return -1; 191*c52afa68SYuanhan Liu } 192*c52afa68SYuanhan Liu fclose(f); 193*c52afa68SYuanhan Liu return 0; 194*c52afa68SYuanhan Liu } 195*c52afa68SYuanhan Liu 196*c52afa68SYuanhan Liu static int 197*c52afa68SYuanhan Liu get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, 198*c52afa68SYuanhan Liu unsigned int *uio_num) 199*c52afa68SYuanhan Liu { 200*c52afa68SYuanhan Liu struct dirent *e; 201*c52afa68SYuanhan Liu DIR *dir; 202*c52afa68SYuanhan Liu char dirname[PATH_MAX]; 203*c52afa68SYuanhan Liu 204*c52afa68SYuanhan Liu /* 205*c52afa68SYuanhan Liu * depending on kernel version, uio can be located in uio/uioX 206*c52afa68SYuanhan Liu * or uio:uioX 207*c52afa68SYuanhan Liu */ 208*c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), 209*c52afa68SYuanhan Liu SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", 210*c52afa68SYuanhan Liu loc->domain, loc->bus, loc->devid, loc->function); 211*c52afa68SYuanhan Liu dir = opendir(dirname); 212*c52afa68SYuanhan Liu if (dir == NULL) { 213*c52afa68SYuanhan Liu /* retry with the parent directory */ 214*c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), 215*c52afa68SYuanhan Liu SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, 216*c52afa68SYuanhan Liu loc->domain, loc->bus, loc->devid, loc->function); 217*c52afa68SYuanhan Liu dir = opendir(dirname); 218*c52afa68SYuanhan Liu 219*c52afa68SYuanhan Liu if (dir == NULL) { 220*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); 221*c52afa68SYuanhan Liu return -1; 222*c52afa68SYuanhan Liu } 223*c52afa68SYuanhan Liu } 224*c52afa68SYuanhan Liu 225*c52afa68SYuanhan Liu /* take the first file starting with "uio" */ 226*c52afa68SYuanhan Liu while ((e = readdir(dir)) != NULL) { 227*c52afa68SYuanhan Liu /* format could be uio%d ...*/ 228*c52afa68SYuanhan Liu int shortprefix_len = sizeof("uio") - 1; 229*c52afa68SYuanhan Liu /* ... or uio:uio%d */ 230*c52afa68SYuanhan Liu int longprefix_len = sizeof("uio:uio") - 1; 231*c52afa68SYuanhan Liu char *endptr; 232*c52afa68SYuanhan Liu 233*c52afa68SYuanhan Liu if (strncmp(e->d_name, "uio", 3) != 0) 234*c52afa68SYuanhan Liu continue; 235*c52afa68SYuanhan Liu 236*c52afa68SYuanhan Liu /* first try uio%d */ 237*c52afa68SYuanhan Liu errno = 0; 238*c52afa68SYuanhan Liu *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); 239*c52afa68SYuanhan Liu if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { 240*c52afa68SYuanhan Liu snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); 241*c52afa68SYuanhan Liu break; 242*c52afa68SYuanhan Liu } 243*c52afa68SYuanhan Liu 244*c52afa68SYuanhan Liu /* then try uio:uio%d */ 245*c52afa68SYuanhan Liu errno = 0; 246*c52afa68SYuanhan Liu *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); 247*c52afa68SYuanhan Liu if (errno == 0 && endptr != (e->d_name + longprefix_len)) { 248*c52afa68SYuanhan Liu snprintf(buf, buflen, "%s/uio:uio%u", dirname, 249*c52afa68SYuanhan Liu *uio_num); 250*c52afa68SYuanhan Liu break; 251*c52afa68SYuanhan Liu } 252*c52afa68SYuanhan Liu } 253*c52afa68SYuanhan Liu closedir(dir); 254*c52afa68SYuanhan Liu 255*c52afa68SYuanhan Liu /* No uio resource found */ 256*c52afa68SYuanhan Liu if (e == NULL) { 257*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "Could not find uio resource"); 258*c52afa68SYuanhan Liu return -1; 259*c52afa68SYuanhan Liu } 260*c52afa68SYuanhan Liu 261*c52afa68SYuanhan Liu return 0; 262*c52afa68SYuanhan Liu } 263*c52afa68SYuanhan Liu 264*c52afa68SYuanhan Liu static int 265*c52afa68SYuanhan Liu legacy_virtio_has_msix(const struct rte_pci_addr *loc) 266*c52afa68SYuanhan Liu { 267*c52afa68SYuanhan Liu DIR *d; 268*c52afa68SYuanhan Liu char dirname[PATH_MAX]; 269*c52afa68SYuanhan Liu 270*c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), 271*c52afa68SYuanhan Liu SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", 272*c52afa68SYuanhan Liu loc->domain, loc->bus, loc->devid, loc->function); 273*c52afa68SYuanhan Liu 274*c52afa68SYuanhan Liu d = opendir(dirname); 275*c52afa68SYuanhan Liu if (d) 276*c52afa68SYuanhan Liu closedir(d); 277*c52afa68SYuanhan Liu 278*c52afa68SYuanhan Liu return (d != NULL); 279*c52afa68SYuanhan Liu } 280*c52afa68SYuanhan Liu 281*c52afa68SYuanhan Liu /* Extract I/O port numbers from sysfs */ 282*c52afa68SYuanhan Liu static int 283*c52afa68SYuanhan Liu virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) 284*c52afa68SYuanhan Liu { 285*c52afa68SYuanhan Liu char dirname[PATH_MAX]; 286*c52afa68SYuanhan Liu char filename[PATH_MAX]; 287*c52afa68SYuanhan Liu unsigned long start, size; 288*c52afa68SYuanhan Liu unsigned int uio_num; 289*c52afa68SYuanhan Liu 290*c52afa68SYuanhan Liu if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) 291*c52afa68SYuanhan Liu return -1; 292*c52afa68SYuanhan Liu 293*c52afa68SYuanhan Liu /* get portio size */ 294*c52afa68SYuanhan Liu snprintf(filename, sizeof(filename), 295*c52afa68SYuanhan Liu "%s/portio/port0/size", dirname); 296*c52afa68SYuanhan Liu if (parse_sysfs_value(filename, &size) < 0) { 297*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "%s(): cannot parse size", 298*c52afa68SYuanhan Liu __func__); 299*c52afa68SYuanhan Liu return -1; 300*c52afa68SYuanhan Liu } 301*c52afa68SYuanhan Liu 302*c52afa68SYuanhan Liu /* get portio start */ 303*c52afa68SYuanhan Liu snprintf(filename, sizeof(filename), 304*c52afa68SYuanhan Liu "%s/portio/port0/start", dirname); 305*c52afa68SYuanhan Liu if (parse_sysfs_value(filename, &start) < 0) { 306*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", 307*c52afa68SYuanhan Liu __func__); 308*c52afa68SYuanhan Liu return -1; 309*c52afa68SYuanhan Liu } 310*c52afa68SYuanhan Liu pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; 311*c52afa68SYuanhan Liu pci_dev->mem_resource[0].len = (uint64_t)size; 312*c52afa68SYuanhan Liu PMD_INIT_LOG(DEBUG, 313*c52afa68SYuanhan Liu "PCI Port IO found start=0x%lx with size=0x%lx", 314*c52afa68SYuanhan Liu start, size); 315*c52afa68SYuanhan Liu 316*c52afa68SYuanhan Liu /* save fd */ 317*c52afa68SYuanhan Liu memset(dirname, 0, sizeof(dirname)); 318*c52afa68SYuanhan Liu snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); 319*c52afa68SYuanhan Liu pci_dev->intr_handle.fd = open(dirname, O_RDWR); 320*c52afa68SYuanhan Liu if (pci_dev->intr_handle.fd < 0) { 321*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", 322*c52afa68SYuanhan Liu dirname, strerror(errno)); 323*c52afa68SYuanhan Liu return -1; 324*c52afa68SYuanhan Liu } 325*c52afa68SYuanhan Liu 326*c52afa68SYuanhan Liu pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; 327*c52afa68SYuanhan Liu pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; 328*c52afa68SYuanhan Liu 329*c52afa68SYuanhan Liu return 0; 330*c52afa68SYuanhan Liu } 331*c52afa68SYuanhan Liu 332*c52afa68SYuanhan Liu /* Extract port I/O numbers from proc/ioports */ 333*c52afa68SYuanhan Liu static int 334*c52afa68SYuanhan Liu virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) 335*c52afa68SYuanhan Liu { 336*c52afa68SYuanhan Liu uint16_t start, end; 337*c52afa68SYuanhan Liu int size; 338*c52afa68SYuanhan Liu FILE *fp; 339*c52afa68SYuanhan Liu char *line = NULL; 340*c52afa68SYuanhan Liu char pci_id[16]; 341*c52afa68SYuanhan Liu int found = 0; 342*c52afa68SYuanhan Liu size_t linesz; 343*c52afa68SYuanhan Liu 344*c52afa68SYuanhan Liu snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, 345*c52afa68SYuanhan Liu pci_dev->addr.domain, 346*c52afa68SYuanhan Liu pci_dev->addr.bus, 347*c52afa68SYuanhan Liu pci_dev->addr.devid, 348*c52afa68SYuanhan Liu pci_dev->addr.function); 349*c52afa68SYuanhan Liu 350*c52afa68SYuanhan Liu fp = fopen("/proc/ioports", "r"); 351*c52afa68SYuanhan Liu if (fp == NULL) { 352*c52afa68SYuanhan Liu PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); 353*c52afa68SYuanhan Liu return -1; 354*c52afa68SYuanhan Liu } 355*c52afa68SYuanhan Liu 356*c52afa68SYuanhan Liu while (getdelim(&line, &linesz, '\n', fp) > 0) { 357*c52afa68SYuanhan Liu char *ptr = line; 358*c52afa68SYuanhan Liu char *left; 359*c52afa68SYuanhan Liu int n; 360*c52afa68SYuanhan Liu 361*c52afa68SYuanhan Liu n = strcspn(ptr, ":"); 362*c52afa68SYuanhan Liu ptr[n] = 0; 363*c52afa68SYuanhan Liu left = &ptr[n + 1]; 364*c52afa68SYuanhan Liu 365*c52afa68SYuanhan Liu while (*left && isspace(*left)) 366*c52afa68SYuanhan Liu left++; 367*c52afa68SYuanhan Liu 368*c52afa68SYuanhan Liu if (!strncmp(left, pci_id, strlen(pci_id))) { 369*c52afa68SYuanhan Liu found = 1; 370*c52afa68SYuanhan Liu 371*c52afa68SYuanhan Liu while (*ptr && isspace(*ptr)) 372*c52afa68SYuanhan Liu ptr++; 373*c52afa68SYuanhan Liu 374*c52afa68SYuanhan Liu sscanf(ptr, "%04hx-%04hx", &start, &end); 375*c52afa68SYuanhan Liu size = end - start + 1; 376*c52afa68SYuanhan Liu 377*c52afa68SYuanhan Liu break; 378*c52afa68SYuanhan Liu } 379*c52afa68SYuanhan Liu } 380*c52afa68SYuanhan Liu 381*c52afa68SYuanhan Liu free(line); 382*c52afa68SYuanhan Liu fclose(fp); 383*c52afa68SYuanhan Liu 384*c52afa68SYuanhan Liu if (!found) 385*c52afa68SYuanhan Liu return -1; 386*c52afa68SYuanhan Liu 387*c52afa68SYuanhan Liu pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; 388*c52afa68SYuanhan Liu pci_dev->mem_resource[0].len = (uint64_t)size; 389*c52afa68SYuanhan Liu PMD_INIT_LOG(DEBUG, 390*c52afa68SYuanhan Liu "PCI Port IO found start=0x%x with size=0x%x", 391*c52afa68SYuanhan Liu start, size); 392*c52afa68SYuanhan Liu 393*c52afa68SYuanhan Liu /* can't support lsc interrupt without uio */ 394*c52afa68SYuanhan Liu pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; 395*c52afa68SYuanhan Liu 396*c52afa68SYuanhan Liu return 0; 397*c52afa68SYuanhan Liu } 398*c52afa68SYuanhan Liu 399*c52afa68SYuanhan Liu /* Extract I/O port numbers from sysfs */ 400*c52afa68SYuanhan Liu static int 401*c52afa68SYuanhan Liu legacy_virtio_resource_init(struct rte_pci_device *pci_dev) 402*c52afa68SYuanhan Liu { 403*c52afa68SYuanhan Liu if (virtio_resource_init_by_uio(pci_dev) == 0) 404*c52afa68SYuanhan Liu return 0; 405*c52afa68SYuanhan Liu else 406*c52afa68SYuanhan Liu return virtio_resource_init_by_ioports(pci_dev); 407*c52afa68SYuanhan Liu } 408*c52afa68SYuanhan Liu 409*c52afa68SYuanhan Liu #else 410*c52afa68SYuanhan Liu static int 411*c52afa68SYuanhan Liu legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) 412*c52afa68SYuanhan Liu { 413*c52afa68SYuanhan Liu /* nic_uio does not enable interrupts, return 0 (false). */ 414*c52afa68SYuanhan Liu return 0; 415*c52afa68SYuanhan Liu } 416*c52afa68SYuanhan Liu 417*c52afa68SYuanhan Liu static int 418*c52afa68SYuanhan Liu legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) 419*c52afa68SYuanhan Liu { 420*c52afa68SYuanhan Liu /* no setup required */ 421*c52afa68SYuanhan Liu return 0; 422*c52afa68SYuanhan Liu } 423*c52afa68SYuanhan Liu #endif 424d5bbeefcSYuanhan Liu 425d5bbeefcSYuanhan Liu static const struct virtio_pci_ops legacy_ops = { 426d5bbeefcSYuanhan Liu .read_dev_cfg = legacy_read_dev_config, 427d5bbeefcSYuanhan Liu .write_dev_cfg = legacy_write_dev_config, 428d5bbeefcSYuanhan Liu .reset = legacy_reset, 429d5bbeefcSYuanhan Liu .get_status = legacy_get_status, 430d5bbeefcSYuanhan Liu .set_status = legacy_set_status, 431d5bbeefcSYuanhan Liu .get_features = legacy_get_features, 432d5bbeefcSYuanhan Liu .set_features = legacy_set_features, 433d5bbeefcSYuanhan Liu .get_isr = legacy_get_isr, 434d5bbeefcSYuanhan Liu .set_config_irq = legacy_set_config_irq, 435d5bbeefcSYuanhan Liu .get_queue_num = legacy_get_queue_num, 436d5bbeefcSYuanhan Liu .setup_queue = legacy_setup_queue, 437d5bbeefcSYuanhan Liu .del_queue = legacy_del_queue, 438d5bbeefcSYuanhan Liu .notify_queue = legacy_notify_queue, 439d5bbeefcSYuanhan Liu }; 440d5bbeefcSYuanhan Liu 441d5bbeefcSYuanhan Liu 442d5bbeefcSYuanhan Liu void 443d5bbeefcSYuanhan Liu vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, 444d5bbeefcSYuanhan Liu void *dst, int length) 445d5bbeefcSYuanhan Liu { 446d5bbeefcSYuanhan Liu hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length); 447d5bbeefcSYuanhan Liu } 448d5bbeefcSYuanhan Liu 449d5bbeefcSYuanhan Liu void 450d5bbeefcSYuanhan Liu vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, 451d5bbeefcSYuanhan Liu const void *src, int length) 452d5bbeefcSYuanhan Liu { 453d5bbeefcSYuanhan Liu hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); 454d5bbeefcSYuanhan Liu } 455d5bbeefcSYuanhan Liu 4566c3169a3SBruce Richardson uint32_t 4576c3169a3SBruce Richardson vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) 4586c3169a3SBruce Richardson { 4596c3169a3SBruce Richardson uint32_t features; 460d5bbeefcSYuanhan Liu 4616c3169a3SBruce Richardson /* 4626c3169a3SBruce Richardson * Limit negotiated features to what the driver, virtqueue, and 4636c3169a3SBruce Richardson * host all support. 4646c3169a3SBruce Richardson */ 4656c3169a3SBruce Richardson features = host_features & hw->guest_features; 466d5bbeefcSYuanhan Liu hw->vtpci_ops->set_features(hw, features); 4676c3169a3SBruce Richardson 4686c3169a3SBruce Richardson return features; 4696c3169a3SBruce Richardson } 4706c3169a3SBruce Richardson 4716c3169a3SBruce Richardson void 4726c3169a3SBruce Richardson vtpci_reset(struct virtio_hw *hw) 4736c3169a3SBruce Richardson { 474d5bbeefcSYuanhan Liu hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET); 475d5bbeefcSYuanhan Liu /* flush status write */ 476d5bbeefcSYuanhan Liu hw->vtpci_ops->get_status(hw); 4776c3169a3SBruce Richardson } 4786c3169a3SBruce Richardson 4796c3169a3SBruce Richardson void 4806c3169a3SBruce Richardson vtpci_reinit_complete(struct virtio_hw *hw) 4816c3169a3SBruce Richardson { 4826c3169a3SBruce Richardson vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK); 4836c3169a3SBruce Richardson } 4846c3169a3SBruce Richardson 4856c3169a3SBruce Richardson void 4866c3169a3SBruce Richardson vtpci_set_status(struct virtio_hw *hw, uint8_t status) 4876c3169a3SBruce Richardson { 4886c3169a3SBruce Richardson if (status != VIRTIO_CONFIG_STATUS_RESET) 489d5bbeefcSYuanhan Liu status |= hw->vtpci_ops->get_status(hw); 4906c3169a3SBruce Richardson 491d5bbeefcSYuanhan Liu hw->vtpci_ops->set_status(hw, status); 4926c3169a3SBruce Richardson } 4936c3169a3SBruce Richardson 4946c3169a3SBruce Richardson uint8_t 4956c3169a3SBruce Richardson vtpci_isr(struct virtio_hw *hw) 4966c3169a3SBruce Richardson { 497d5bbeefcSYuanhan Liu return hw->vtpci_ops->get_isr(hw); 4986c3169a3SBruce Richardson } 4996c3169a3SBruce Richardson 5006c3169a3SBruce Richardson 5016c3169a3SBruce Richardson /* Enable one vector (0) for Link State Intrerrupt */ 5026c3169a3SBruce Richardson uint16_t 5036c3169a3SBruce Richardson vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) 5046c3169a3SBruce Richardson { 505d5bbeefcSYuanhan Liu return hw->vtpci_ops->set_config_irq(hw, vec); 506d5bbeefcSYuanhan Liu } 507d5bbeefcSYuanhan Liu 508d5bbeefcSYuanhan Liu int 509*c52afa68SYuanhan Liu vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) 510d5bbeefcSYuanhan Liu { 511d5bbeefcSYuanhan Liu hw->vtpci_ops = &legacy_ops; 512d5bbeefcSYuanhan Liu 513*c52afa68SYuanhan Liu if (legacy_virtio_resource_init(dev) < 0) 514*c52afa68SYuanhan Liu return -1; 515*c52afa68SYuanhan Liu hw->use_msix = legacy_virtio_has_msix(&dev->addr); 516*c52afa68SYuanhan Liu hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; 517*c52afa68SYuanhan Liu 518d5bbeefcSYuanhan Liu return 0; 5196c3169a3SBruce Richardson } 520