LCOV - code coverage report
Current view: top level - lib/virtio - virtio_pci.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 370 0.0 %
Date: 2024-12-16 20:53:32 Functions: 0 28 0.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2010-2014 Intel Corporation. All rights reserved.
       3             :  *   All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk/stdinc.h"
       7             : 
       8             : #include "spdk/memory.h"
       9             : #include "spdk/mmio.h"
      10             : #include "spdk/string.h"
      11             : #include "spdk/env.h"
      12             : 
      13             : #include "spdk_internal/virtio.h"
      14             : #include <linux/virtio_ids.h>
      15             : 
      16             : struct virtio_hw {
      17             :         uint8_t     use_msix;
      18             :         uint32_t    notify_off_multiplier;
      19             :         uint8_t     *isr;
      20             :         uint16_t    *notify_base;
      21             : 
      22             :         struct {
      23             :                 /** Mem-mapped resources from given PCI BAR */
      24             :                 void        *vaddr;
      25             : 
      26             :                 /** Length of the address space */
      27             :                 uint32_t    len;
      28             :         } pci_bar[6];
      29             : 
      30             :         struct virtio_pci_common_cfg *common_cfg;
      31             :         struct spdk_pci_device *pci_dev;
      32             : 
      33             :         /** Device-specific PCI config space */
      34             :         void *dev_cfg;
      35             : 
      36             :         struct virtio_dev *vdev;
      37             :         bool is_remapped;
      38             :         bool is_removing;
      39             :         TAILQ_ENTRY(virtio_hw) tailq;
      40             : };
      41             : 
      42             : struct virtio_pci_probe_ctx {
      43             :         virtio_pci_create_cb enum_cb;
      44             :         void *enum_ctx;
      45             :         uint16_t device_id;
      46             : };
      47             : 
      48             : static TAILQ_HEAD(, virtio_hw) g_virtio_hws = TAILQ_HEAD_INITIALIZER(g_virtio_hws);
      49             : static pthread_mutex_t g_hw_mutex = PTHREAD_MUTEX_INITIALIZER;
      50             : __thread struct virtio_hw *g_thread_virtio_hw = NULL;
      51             : static uint16_t g_signal_lock;
      52             : static bool g_sigset = false;
      53             : 
      54             : /*
      55             :  * Following macros are derived from linux/pci_regs.h, however,
      56             :  * we can't simply include that header here, as there is no such
      57             :  * file for non-Linux platform.
      58             :  */
      59             : #define PCI_CAPABILITY_LIST     0x34
      60             : #define PCI_CAP_ID_VNDR         0x09
      61             : #define PCI_CAP_ID_MSIX         0x11
      62             : 
      63             : static void
      64           0 : virtio_pci_dev_sigbus_handler(const void *failure_addr, void *ctx)
      65             : {
      66           0 :         void *map_address = NULL;
      67           0 :         uint16_t flag = 0;
      68             :         int i;
      69             : 
      70           0 :         if (!__atomic_compare_exchange_n(&g_signal_lock, &flag, 1, false, __ATOMIC_ACQUIRE,
      71             :                                          __ATOMIC_RELAXED)) {
      72           0 :                 SPDK_DEBUGLOG(virtio_pci, "request g_signal_lock failed\n");
      73           0 :                 return;
      74             :         }
      75             : 
      76           0 :         if (g_thread_virtio_hw == NULL || g_thread_virtio_hw->is_remapped) {
      77           0 :                 __atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
      78           0 :                 return;
      79             :         }
      80             : 
      81             :         /* We remap each bar to the same VA to avoid subsequent sigbus error.
      82             :          * Because it is mapped to the same VA, such as hw->common_cfg and so on
      83             :          * do not need to be modified.
      84             :          */
      85           0 :         for (i = 0; i < 6; ++i) {
      86           0 :                 if (g_thread_virtio_hw->pci_bar[i].vaddr == NULL) {
      87           0 :                         continue;
      88             :                 }
      89             : 
      90           0 :                 map_address = mmap(g_thread_virtio_hw->pci_bar[i].vaddr,
      91           0 :                                    g_thread_virtio_hw->pci_bar[i].len,
      92             :                                    PROT_READ | PROT_WRITE,
      93             :                                    MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
      94           0 :                 if (map_address == MAP_FAILED) {
      95           0 :                         SPDK_ERRLOG("mmap failed\n");
      96           0 :                         goto fail;
      97             :                 }
      98           0 :                 memset(map_address, 0xFF, g_thread_virtio_hw->pci_bar[i].len);
      99             :         }
     100             : 
     101           0 :         g_thread_virtio_hw->is_remapped = true;
     102           0 :         __atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
     103           0 :         return;
     104           0 : fail:
     105           0 :         for (--i; i >= 0; i--) {
     106           0 :                 if (g_thread_virtio_hw->pci_bar[i].vaddr == NULL) {
     107           0 :                         continue;
     108             :                 }
     109             : 
     110           0 :                 munmap(g_thread_virtio_hw->pci_bar[i].vaddr, g_thread_virtio_hw->pci_bar[i].len);
     111             :         }
     112           0 :         __atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
     113             : }
     114             : 
     115             : static struct virtio_hw *
     116           0 : virtio_pci_dev_get_by_addr(struct spdk_pci_addr *traddr)
     117             : {
     118             :         struct virtio_hw *hw;
     119           0 :         struct spdk_pci_addr addr;
     120             : 
     121           0 :         pthread_mutex_lock(&g_hw_mutex);
     122           0 :         TAILQ_FOREACH(hw, &g_virtio_hws, tailq) {
     123           0 :                 addr = spdk_pci_device_get_addr(hw->pci_dev);
     124           0 :                 if (!spdk_pci_addr_compare(&addr, traddr)) {
     125           0 :                         pthread_mutex_unlock(&g_hw_mutex);
     126           0 :                         return hw;
     127             :                 }
     128             :         }
     129           0 :         pthread_mutex_unlock(&g_hw_mutex);
     130             : 
     131           0 :         return NULL;
     132             : }
     133             : 
     134             : static const char *
     135           0 : virtio_pci_dev_check(struct virtio_hw *hw, uint16_t device_id_match)
     136             : {
     137             :         uint16_t pci_device_id, device_id;
     138             : 
     139           0 :         pci_device_id = spdk_pci_device_get_device_id(hw->pci_dev);
     140           0 :         if (pci_device_id < 0x1040) {
     141             :                 /* Transitional devices: use the PCI subsystem device id as
     142             :                  * virtio device id, same as legacy driver always did.
     143             :                  */
     144           0 :                 device_id = spdk_pci_device_get_subdevice_id(hw->pci_dev);
     145             :         } else {
     146             :                 /* Modern devices: simply use PCI device id, but start from 0x1040. */
     147           0 :                 device_id = pci_device_id - 0x1040;
     148             :         }
     149             : 
     150           0 :         if (device_id == device_id_match) {
     151           0 :                 hw->is_removing = true;
     152           0 :                 return hw->vdev->name;
     153             :         }
     154             : 
     155           0 :         return NULL;
     156             : }
     157             : 
     158             : const char *
     159           0 : virtio_pci_dev_event_process(int fd, uint16_t device_id)
     160             : {
     161           0 :         struct spdk_pci_event event;
     162             :         struct virtio_hw *hw, *tmp;
     163             :         const char *vdev_name;
     164             : 
     165             :         /* UIO remove handler */
     166           0 :         if (spdk_pci_get_event(fd, &event) > 0) {
     167           0 :                 if (event.action == SPDK_UEVENT_REMOVE) {
     168           0 :                         hw = virtio_pci_dev_get_by_addr(&event.traddr);
     169           0 :                         if (hw == NULL || hw->is_removing) {
     170           0 :                                 return NULL;
     171             :                         }
     172             : 
     173           0 :                         vdev_name = virtio_pci_dev_check(hw, device_id);
     174           0 :                         if (vdev_name != NULL) {
     175           0 :                                 return vdev_name;
     176             :                         }
     177             :                 }
     178             :         }
     179             : 
     180             :         /* VFIO remove handler */
     181           0 :         pthread_mutex_lock(&g_hw_mutex);
     182           0 :         TAILQ_FOREACH_SAFE(hw, &g_virtio_hws, tailq, tmp) {
     183           0 :                 if (spdk_pci_device_is_removed(hw->pci_dev) && !hw->is_removing) {
     184           0 :                         vdev_name = virtio_pci_dev_check(hw, device_id);
     185           0 :                         if (vdev_name != NULL) {
     186           0 :                                 pthread_mutex_unlock(&g_hw_mutex);
     187           0 :                                 return vdev_name;
     188             :                         }
     189             :                 }
     190             :         }
     191           0 :         pthread_mutex_unlock(&g_hw_mutex);
     192             : 
     193           0 :         return NULL;
     194             : }
     195             : 
     196             : static inline int
     197           0 : check_vq_phys_addr_ok(struct virtqueue *vq)
     198             : {
     199             :         /* Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit,
     200             :          * and only accepts 32 bit page frame number.
     201             :          * Check if the allocated physical memory exceeds 16TB.
     202             :          */
     203           0 :         if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >>
     204             :             (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) {
     205           0 :                 SPDK_ERRLOG("vring address shouldn't be above 16TB!\n");
     206           0 :                 return 0;
     207             :         }
     208             : 
     209           0 :         return 1;
     210             : }
     211             : 
     212             : static void
     213           0 : free_virtio_hw(struct virtio_hw *hw)
     214             : {
     215             :         unsigned i;
     216             : 
     217           0 :         for (i = 0; i < 6; ++i) {
     218           0 :                 if (hw->pci_bar[i].vaddr == NULL) {
     219           0 :                         continue;
     220             :                 }
     221             : 
     222           0 :                 spdk_pci_device_unmap_bar(hw->pci_dev, i, hw->pci_bar[i].vaddr);
     223             :         }
     224             : 
     225           0 :         free(hw);
     226           0 : }
     227             : 
     228             : static void
     229           0 : pci_dump_json_info(struct virtio_dev *dev, struct spdk_json_write_ctx *w)
     230             : {
     231           0 :         struct virtio_hw *hw = dev->ctx;
     232           0 :         struct spdk_pci_addr pci_addr = spdk_pci_device_get_addr((struct spdk_pci_device *)hw->pci_dev);
     233           0 :         char addr[32];
     234             : 
     235           0 :         spdk_json_write_name(w, "type");
     236           0 :         if (dev->modern) {
     237           0 :                 spdk_json_write_string(w, "pci-modern");
     238             :         } else {
     239           0 :                 spdk_json_write_string(w, "pci-legacy");
     240             :         }
     241             : 
     242           0 :         spdk_pci_addr_fmt(addr, sizeof(addr), &pci_addr);
     243           0 :         spdk_json_write_named_string(w, "pci_address", addr);
     244           0 : }
     245             : 
     246             : static void
     247           0 : pci_write_json_config(struct virtio_dev *dev, struct spdk_json_write_ctx *w)
     248             : {
     249           0 :         struct virtio_hw *hw = dev->ctx;
     250           0 :         struct spdk_pci_addr pci_addr = spdk_pci_device_get_addr(hw->pci_dev);
     251           0 :         char addr[32];
     252             : 
     253           0 :         spdk_pci_addr_fmt(addr, sizeof(addr), &pci_addr);
     254             : 
     255           0 :         spdk_json_write_named_string(w, "trtype", "pci");
     256           0 :         spdk_json_write_named_string(w, "traddr", addr);
     257           0 : }
     258             : 
     259             : static inline void
     260           0 : io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
     261             : {
     262           0 :         spdk_mmio_write_4(lo, val & ((1ULL << 32) - 1));
     263           0 :         spdk_mmio_write_4(hi, val >> 32);
     264           0 : }
     265             : 
     266             : static int
     267           0 : modern_read_dev_config(struct virtio_dev *dev, size_t offset,
     268             :                        void *dst, int length)
     269             : {
     270           0 :         struct virtio_hw *hw = dev->ctx;
     271             :         int i;
     272             :         uint8_t *p;
     273             :         uint8_t old_gen, new_gen;
     274             : 
     275           0 :         g_thread_virtio_hw = hw;
     276             :         do {
     277           0 :                 old_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
     278             : 
     279           0 :                 p = dst;
     280           0 :                 for (i = 0;  i < length; i++) {
     281           0 :                         *p++ = spdk_mmio_read_1((uint8_t *)hw->dev_cfg + offset + i);
     282             :                 }
     283             : 
     284           0 :                 new_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
     285           0 :         } while (old_gen != new_gen);
     286           0 :         g_thread_virtio_hw = NULL;
     287             : 
     288           0 :         return 0;
     289             : }
     290             : 
     291             : static int
     292           0 : modern_write_dev_config(struct virtio_dev *dev, size_t offset,
     293             :                         const void *src, int length)
     294             : {
     295           0 :         struct virtio_hw *hw = dev->ctx;
     296             :         int i;
     297           0 :         const uint8_t *p = src;
     298             : 
     299           0 :         g_thread_virtio_hw = hw;
     300           0 :         for (i = 0;  i < length; i++) {
     301           0 :                 spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++);
     302             :         }
     303           0 :         g_thread_virtio_hw = NULL;
     304             : 
     305           0 :         return 0;
     306             : }
     307             : 
     308             : static uint64_t
     309           0 : modern_get_features(struct virtio_dev *dev)
     310             : {
     311           0 :         struct virtio_hw *hw = dev->ctx;
     312             :         uint32_t features_lo, features_hi;
     313             : 
     314           0 :         g_thread_virtio_hw = hw;
     315           0 :         spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 0);
     316           0 :         features_lo = spdk_mmio_read_4(&hw->common_cfg->device_feature);
     317             : 
     318           0 :         spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 1);
     319           0 :         features_hi = spdk_mmio_read_4(&hw->common_cfg->device_feature);
     320           0 :         g_thread_virtio_hw = NULL;
     321             : 
     322           0 :         return ((uint64_t)features_hi << 32) | features_lo;
     323             : }
     324             : 
     325             : static int
     326           0 : modern_set_features(struct virtio_dev *dev, uint64_t features)
     327             : {
     328           0 :         struct virtio_hw *hw = dev->ctx;
     329             : 
     330           0 :         if ((features & (1ULL << VIRTIO_F_VERSION_1)) == 0) {
     331           0 :                 SPDK_ERRLOG("VIRTIO_F_VERSION_1 feature is not enabled.\n");
     332           0 :                 return -EINVAL;
     333             :         }
     334             : 
     335           0 :         g_thread_virtio_hw = hw;
     336           0 :         spdk_mmio_write_4(&hw->common_cfg->guest_feature_select, 0);
     337           0 :         spdk_mmio_write_4(&hw->common_cfg->guest_feature, features & ((1ULL << 32) - 1));
     338             : 
     339           0 :         spdk_mmio_write_4(&hw->common_cfg->guest_feature_select, 1);
     340           0 :         spdk_mmio_write_4(&hw->common_cfg->guest_feature, features >> 32);
     341           0 :         g_thread_virtio_hw = NULL;
     342             : 
     343           0 :         dev->negotiated_features = features;
     344             : 
     345           0 :         return 0;
     346             : }
     347             : 
     348             : static void
     349           0 : modern_destruct_dev(struct virtio_dev *vdev)
     350             : {
     351           0 :         struct virtio_hw *hw = vdev->ctx;
     352             :         struct spdk_pci_device *pci_dev;
     353             : 
     354           0 :         if (hw != NULL) {
     355           0 :                 pthread_mutex_lock(&g_hw_mutex);
     356           0 :                 TAILQ_REMOVE(&g_virtio_hws, hw, tailq);
     357           0 :                 pthread_mutex_unlock(&g_hw_mutex);
     358           0 :                 pci_dev = hw->pci_dev;
     359           0 :                 free_virtio_hw(hw);
     360           0 :                 if (pci_dev) {
     361           0 :                         spdk_pci_device_detach(pci_dev);
     362             :                 }
     363             :         }
     364           0 : }
     365             : 
     366             : static uint8_t
     367           0 : modern_get_status(struct virtio_dev *dev)
     368             : {
     369           0 :         struct virtio_hw *hw = dev->ctx;
     370             :         uint8_t ret;
     371             : 
     372           0 :         g_thread_virtio_hw = hw;
     373           0 :         ret = spdk_mmio_read_1(&hw->common_cfg->device_status);
     374           0 :         g_thread_virtio_hw = NULL;
     375             : 
     376           0 :         return ret;
     377             : }
     378             : 
     379             : static void
     380           0 : modern_set_status(struct virtio_dev *dev, uint8_t status)
     381             : {
     382           0 :         struct virtio_hw *hw = dev->ctx;
     383             : 
     384           0 :         g_thread_virtio_hw = hw;
     385           0 :         spdk_mmio_write_1(&hw->common_cfg->device_status, status);
     386           0 :         g_thread_virtio_hw = NULL;
     387           0 : }
     388             : 
     389             : static uint16_t
     390           0 : modern_get_queue_size(struct virtio_dev *dev, uint16_t queue_id)
     391             : {
     392           0 :         struct virtio_hw *hw = dev->ctx;
     393             :         uint16_t ret;
     394             : 
     395           0 :         g_thread_virtio_hw = hw;
     396           0 :         spdk_mmio_write_2(&hw->common_cfg->queue_select, queue_id);
     397           0 :         ret = spdk_mmio_read_2(&hw->common_cfg->queue_size);
     398           0 :         g_thread_virtio_hw = NULL;
     399             : 
     400           0 :         return ret;
     401             : }
     402             : 
     403             : static int
     404           0 : modern_setup_queue(struct virtio_dev *dev, struct virtqueue *vq)
     405             : {
     406           0 :         struct virtio_hw *hw = dev->ctx;
     407             :         uint64_t desc_addr, avail_addr, used_addr;
     408             :         uint16_t notify_off;
     409             :         void *queue_mem;
     410             :         uint64_t queue_mem_phys_addr;
     411             : 
     412             :         /* To ensure physical address contiguity we make the queue occupy
     413             :          * only a single hugepage (2MB). As of Virtio 1.0, the queue size
     414             :          * always falls within this limit.
     415             :          */
     416           0 :         if (vq->vq_ring_size > VALUE_2MB) {
     417           0 :                 return -ENOMEM;
     418             :         }
     419             : 
     420           0 :         queue_mem = spdk_zmalloc(vq->vq_ring_size, VALUE_2MB, NULL,
     421             :                                  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     422           0 :         if (queue_mem == NULL) {
     423           0 :                 return -ENOMEM;
     424             :         }
     425             : 
     426           0 :         queue_mem_phys_addr = spdk_vtophys(queue_mem, NULL);
     427           0 :         if (queue_mem_phys_addr == SPDK_VTOPHYS_ERROR) {
     428           0 :                 spdk_free(queue_mem);
     429           0 :                 return -EFAULT;
     430             :         }
     431             : 
     432           0 :         vq->vq_ring_mem = queue_mem_phys_addr;
     433           0 :         vq->vq_ring_virt_mem = queue_mem;
     434             : 
     435           0 :         if (!check_vq_phys_addr_ok(vq)) {
     436           0 :                 spdk_free(queue_mem);
     437           0 :                 return -ENOMEM;
     438             :         }
     439             : 
     440           0 :         desc_addr = vq->vq_ring_mem;
     441           0 :         avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
     442           0 :         used_addr = (avail_addr + offsetof(struct vring_avail, ring[vq->vq_nentries])
     443           0 :                      + VIRTIO_PCI_VRING_ALIGN - 1) & ~(VIRTIO_PCI_VRING_ALIGN - 1);
     444             : 
     445           0 :         g_thread_virtio_hw = hw;
     446           0 :         spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
     447             : 
     448           0 :         io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
     449           0 :                            &hw->common_cfg->queue_desc_hi);
     450           0 :         io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
     451           0 :                            &hw->common_cfg->queue_avail_hi);
     452           0 :         io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
     453           0 :                            &hw->common_cfg->queue_used_hi);
     454             : 
     455           0 :         notify_off = spdk_mmio_read_2(&hw->common_cfg->queue_notify_off);
     456           0 :         vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
     457           0 :                                    notify_off * hw->notify_off_multiplier);
     458             : 
     459           0 :         spdk_mmio_write_2(&hw->common_cfg->queue_enable, 1);
     460           0 :         g_thread_virtio_hw = NULL;
     461             : 
     462           0 :         SPDK_DEBUGLOG(virtio_pci, "queue %"PRIu16" addresses:\n", vq->vq_queue_index);
     463           0 :         SPDK_DEBUGLOG(virtio_pci, "\t desc_addr: %" PRIx64 "\n", desc_addr);
     464           0 :         SPDK_DEBUGLOG(virtio_pci, "\t aval_addr: %" PRIx64 "\n", avail_addr);
     465           0 :         SPDK_DEBUGLOG(virtio_pci, "\t used_addr: %" PRIx64 "\n", used_addr);
     466           0 :         SPDK_DEBUGLOG(virtio_pci, "\t notify addr: %p (notify offset: %"PRIu16")\n",
     467             :                       vq->notify_addr, notify_off);
     468             : 
     469           0 :         return 0;
     470             : }
     471             : 
     472             : static void
     473           0 : modern_del_queue(struct virtio_dev *dev, struct virtqueue *vq)
     474             : {
     475           0 :         struct virtio_hw *hw = dev->ctx;
     476             : 
     477           0 :         g_thread_virtio_hw = hw;
     478           0 :         spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
     479             : 
     480           0 :         io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
     481           0 :                            &hw->common_cfg->queue_desc_hi);
     482           0 :         io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
     483           0 :                            &hw->common_cfg->queue_avail_hi);
     484           0 :         io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
     485           0 :                            &hw->common_cfg->queue_used_hi);
     486             : 
     487           0 :         spdk_mmio_write_2(&hw->common_cfg->queue_enable, 0);
     488           0 :         g_thread_virtio_hw = NULL;
     489             : 
     490           0 :         spdk_free(vq->vq_ring_virt_mem);
     491           0 : }
     492             : 
     493             : static void
     494           0 : modern_notify_queue(struct virtio_dev *dev, struct virtqueue *vq)
     495             : {
     496           0 :         g_thread_virtio_hw = dev->ctx;
     497           0 :         spdk_mmio_write_2(vq->notify_addr, vq->vq_queue_index);
     498           0 :         g_thread_virtio_hw = NULL;
     499           0 : }
     500             : 
     501             : static const struct virtio_dev_ops modern_ops = {
     502             :         .read_dev_cfg   = modern_read_dev_config,
     503             :         .write_dev_cfg  = modern_write_dev_config,
     504             :         .get_status     = modern_get_status,
     505             :         .set_status     = modern_set_status,
     506             :         .get_features   = modern_get_features,
     507             :         .set_features   = modern_set_features,
     508             :         .destruct_dev   = modern_destruct_dev,
     509             :         .get_queue_size = modern_get_queue_size,
     510             :         .setup_queue    = modern_setup_queue,
     511             :         .del_queue      = modern_del_queue,
     512             :         .notify_queue   = modern_notify_queue,
     513             :         .dump_json_info = pci_dump_json_info,
     514             :         .write_json_config = pci_write_json_config,
     515             : };
     516             : 
     517             : static void *
     518           0 : get_cfg_addr(struct virtio_hw *hw, struct virtio_pci_cap *cap)
     519             : {
     520           0 :         uint8_t  bar    = cap->bar;
     521           0 :         uint32_t length = cap->length;
     522           0 :         uint32_t offset = cap->offset;
     523             : 
     524           0 :         if (bar > 5) {
     525           0 :                 SPDK_ERRLOG("invalid bar: %"PRIu8"\n", bar);
     526           0 :                 return NULL;
     527             :         }
     528             : 
     529           0 :         if (offset + length < offset) {
     530           0 :                 SPDK_ERRLOG("offset(%"PRIu32") + length(%"PRIu32") overflows\n",
     531             :                             offset, length);
     532           0 :                 return NULL;
     533             :         }
     534             : 
     535           0 :         if (offset + length > hw->pci_bar[bar].len) {
     536           0 :                 SPDK_ERRLOG("invalid cap: overflows bar space: %"PRIu32" > %"PRIu32"\n",
     537             :                             offset + length, hw->pci_bar[bar].len);
     538           0 :                 return NULL;
     539             :         }
     540             : 
     541           0 :         if (hw->pci_bar[bar].vaddr == NULL) {
     542           0 :                 SPDK_ERRLOG("bar %"PRIu8" base addr is NULL\n", bar);
     543           0 :                 return NULL;
     544             :         }
     545             : 
     546           0 :         return hw->pci_bar[bar].vaddr + offset;
     547             : }
     548             : 
     549             : static int
     550           0 : virtio_read_caps(struct virtio_hw *hw)
     551             : {
     552           0 :         uint8_t pos;
     553           0 :         struct virtio_pci_cap cap;
     554             :         int ret;
     555             : 
     556           0 :         ret = spdk_pci_device_cfg_read(hw->pci_dev, &pos, 1, PCI_CAPABILITY_LIST);
     557           0 :         if (ret < 0) {
     558           0 :                 SPDK_DEBUGLOG(virtio_pci, "failed to read pci capability list\n");
     559           0 :                 return ret;
     560             :         }
     561             : 
     562           0 :         while (pos) {
     563           0 :                 ret = spdk_pci_device_cfg_read(hw->pci_dev, &cap, sizeof(cap), pos);
     564           0 :                 if (ret < 0) {
     565           0 :                         SPDK_ERRLOG("failed to read pci cap at pos: %"PRIx8"\n", pos);
     566           0 :                         break;
     567             :                 }
     568             : 
     569           0 :                 if (cap.cap_vndr == PCI_CAP_ID_MSIX) {
     570           0 :                         hw->use_msix = 1;
     571             :                 }
     572             : 
     573           0 :                 if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
     574           0 :                         SPDK_DEBUGLOG(virtio_pci,
     575             :                                       "[%2"PRIx8"] skipping non VNDR cap id: %02"PRIx8"\n",
     576             :                                       pos, cap.cap_vndr);
     577           0 :                         goto next;
     578             :                 }
     579             : 
     580           0 :                 SPDK_DEBUGLOG(virtio_pci,
     581             :                               "[%2"PRIx8"] cfg type: %"PRIu8", bar: %"PRIu8", offset: %04"PRIx32", len: %"PRIu32"\n",
     582             :                               pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
     583             : 
     584           0 :                 switch (cap.cfg_type) {
     585           0 :                 case VIRTIO_PCI_CAP_COMMON_CFG:
     586           0 :                         hw->common_cfg = get_cfg_addr(hw, &cap);
     587           0 :                         break;
     588           0 :                 case VIRTIO_PCI_CAP_NOTIFY_CFG:
     589           0 :                         spdk_pci_device_cfg_read(hw->pci_dev, &hw->notify_off_multiplier,
     590             :                                                  4, pos + sizeof(cap));
     591           0 :                         hw->notify_base = get_cfg_addr(hw, &cap);
     592           0 :                         break;
     593           0 :                 case VIRTIO_PCI_CAP_DEVICE_CFG:
     594           0 :                         hw->dev_cfg = get_cfg_addr(hw, &cap);
     595           0 :                         break;
     596           0 :                 case VIRTIO_PCI_CAP_ISR_CFG:
     597           0 :                         hw->isr = get_cfg_addr(hw, &cap);
     598           0 :                         break;
     599             :                 }
     600             : 
     601           0 : next:
     602           0 :                 pos = cap.cap_next;
     603             :         }
     604             : 
     605           0 :         if (hw->common_cfg == NULL || hw->notify_base == NULL ||
     606           0 :             hw->dev_cfg == NULL    || hw->isr == NULL) {
     607           0 :                 SPDK_DEBUGLOG(virtio_pci, "no modern virtio pci device found.\n");
     608           0 :                 if (ret < 0) {
     609           0 :                         return ret;
     610             :                 } else {
     611           0 :                         return -EINVAL;
     612             :                 }
     613             :         }
     614             : 
     615           0 :         SPDK_DEBUGLOG(virtio_pci, "found modern virtio pci device.\n");
     616             : 
     617           0 :         SPDK_DEBUGLOG(virtio_pci, "common cfg mapped at: %p\n", hw->common_cfg);
     618           0 :         SPDK_DEBUGLOG(virtio_pci, "device cfg mapped at: %p\n", hw->dev_cfg);
     619           0 :         SPDK_DEBUGLOG(virtio_pci, "isr cfg mapped at: %p\n", hw->isr);
     620           0 :         SPDK_DEBUGLOG(virtio_pci, "notify base: %p, notify off multiplier: %u\n",
     621             :                       hw->notify_base, hw->notify_off_multiplier);
     622             : 
     623           0 :         return 0;
     624             : }
     625             : 
     626             : static int
     627           0 : virtio_pci_dev_probe(struct spdk_pci_device *pci_dev, struct virtio_pci_probe_ctx *ctx)
     628             : {
     629             :         struct virtio_hw *hw;
     630           0 :         uint8_t *bar_vaddr;
     631           0 :         uint64_t bar_paddr, bar_len;
     632             :         int rc;
     633             :         unsigned i;
     634           0 :         char bdf[32];
     635           0 :         struct spdk_pci_addr addr;
     636             : 
     637           0 :         addr = spdk_pci_device_get_addr(pci_dev);
     638           0 :         rc = spdk_pci_addr_fmt(bdf, sizeof(bdf), &addr);
     639           0 :         if (rc != 0) {
     640           0 :                 SPDK_ERRLOG("Ignoring a device with non-parseable PCI address\n");
     641           0 :                 return -1;
     642             :         }
     643             : 
     644           0 :         hw = calloc(1, sizeof(*hw));
     645           0 :         if (hw == NULL) {
     646           0 :                 SPDK_ERRLOG("%s: calloc failed\n", bdf);
     647           0 :                 return -1;
     648             :         }
     649             : 
     650           0 :         hw->pci_dev = pci_dev;
     651             : 
     652           0 :         for (i = 0; i < 6; ++i) {
     653           0 :                 rc = spdk_pci_device_map_bar(pci_dev, i, (void *) &bar_vaddr, &bar_paddr,
     654             :                                              &bar_len);
     655           0 :                 if (rc != 0) {
     656           0 :                         SPDK_ERRLOG("%s: failed to memmap PCI BAR %u\n", bdf, i);
     657           0 :                         free_virtio_hw(hw);
     658           0 :                         return -1;
     659             :                 }
     660             : 
     661           0 :                 hw->pci_bar[i].vaddr = bar_vaddr;
     662           0 :                 hw->pci_bar[i].len = bar_len;
     663             :         }
     664             : 
     665             :         /* Virtio PCI caps exist only on modern PCI devices.
     666             :          * Legacy devices are not supported.
     667             :          */
     668           0 :         if (virtio_read_caps(hw) != 0) {
     669           0 :                 SPDK_NOTICELOG("Ignoring legacy PCI device at %s\n", bdf);
     670           0 :                 free_virtio_hw(hw);
     671           0 :                 return -1;
     672             :         }
     673             : 
     674           0 :         rc = ctx->enum_cb((struct virtio_pci_ctx *)hw, ctx->enum_ctx);
     675           0 :         if (rc != 0) {
     676           0 :                 free_virtio_hw(hw);
     677           0 :                 return rc;
     678             :         }
     679             : 
     680           0 :         if (g_sigset != true) {
     681           0 :                 spdk_pci_register_error_handler(virtio_pci_dev_sigbus_handler,
     682             :                                                 NULL);
     683           0 :                 g_sigset = true;
     684             :         }
     685             : 
     686           0 :         pthread_mutex_lock(&g_hw_mutex);
     687           0 :         TAILQ_INSERT_TAIL(&g_virtio_hws, hw, tailq);
     688           0 :         pthread_mutex_unlock(&g_hw_mutex);
     689             : 
     690           0 :         return 0;
     691             : }
     692             : 
     693             : static int
     694           0 : virtio_pci_dev_probe_cb(void *probe_ctx, struct spdk_pci_device *pci_dev)
     695             : {
     696           0 :         struct virtio_pci_probe_ctx *ctx = probe_ctx;
     697           0 :         uint16_t pci_device_id = spdk_pci_device_get_device_id(pci_dev);
     698             :         uint16_t device_id;
     699             : 
     700           0 :         if (pci_device_id < 0x1000 || pci_device_id > 0x107f) {
     701           0 :                 SPDK_ERRLOG("Probe device is not a virtio device\n");
     702           0 :                 return 1;
     703             :         }
     704             : 
     705           0 :         if (pci_device_id < 0x1040) {
     706             :                 /* Transitional devices: use the PCI subsystem device id as
     707             :                  * virtio device id, same as legacy driver always did.
     708             :                  */
     709           0 :                 device_id = spdk_pci_device_get_subdevice_id(pci_dev);
     710             :         } else {
     711             :                 /* Modern devices: simply use PCI device id, but start from 0x1040. */
     712           0 :                 device_id = pci_device_id - 0x1040;
     713             :         }
     714             : 
     715           0 :         if (device_id != ctx->device_id) {
     716           0 :                 return 1;
     717             :         }
     718             : 
     719           0 :         return virtio_pci_dev_probe(pci_dev, ctx);
     720             : }
     721             : 
     722             : int
     723           0 : virtio_pci_dev_enumerate(virtio_pci_create_cb enum_cb, void *enum_ctx,
     724             :                          uint16_t pci_device_id)
     725             : {
     726           0 :         struct virtio_pci_probe_ctx ctx;
     727             : 
     728           0 :         if (!spdk_process_is_primary()) {
     729           0 :                 SPDK_WARNLOG("virtio_pci secondary process support is not implemented yet.\n");
     730           0 :                 return 0;
     731             :         }
     732             : 
     733           0 :         ctx.enum_cb = enum_cb;
     734           0 :         ctx.enum_ctx = enum_ctx;
     735           0 :         ctx.device_id = pci_device_id;
     736             : 
     737           0 :         return spdk_pci_enumerate(spdk_pci_virtio_get_driver(),
     738             :                                   virtio_pci_dev_probe_cb, &ctx);
     739             : }
     740             : 
     741             : int
     742           0 : virtio_pci_dev_attach(virtio_pci_create_cb enum_cb, void *enum_ctx,
     743             :                       uint16_t device_id, struct spdk_pci_addr *pci_address)
     744             : {
     745           0 :         struct virtio_pci_probe_ctx ctx;
     746             : 
     747           0 :         if (!spdk_process_is_primary()) {
     748           0 :                 SPDK_WARNLOG("virtio_pci secondary process support is not implemented yet.\n");
     749           0 :                 return 0;
     750             :         }
     751             : 
     752           0 :         ctx.enum_cb = enum_cb;
     753           0 :         ctx.enum_ctx = enum_ctx;
     754           0 :         ctx.device_id = device_id;
     755             : 
     756           0 :         return spdk_pci_device_attach(spdk_pci_virtio_get_driver(),
     757             :                                       virtio_pci_dev_probe_cb, &ctx, pci_address);
     758             : }
     759             : 
     760             : int
     761           0 : virtio_pci_dev_init(struct virtio_dev *vdev, const char *name,
     762             :                     struct virtio_pci_ctx *pci_ctx)
     763             : {
     764             :         int rc;
     765           0 :         struct virtio_hw *hw = (struct virtio_hw *)pci_ctx;
     766             : 
     767           0 :         rc = virtio_dev_construct(vdev, name, &modern_ops, pci_ctx);
     768           0 :         if (rc != 0) {
     769           0 :                 return rc;
     770             :         }
     771             : 
     772           0 :         vdev->is_hw = 1;
     773           0 :         vdev->modern = 1;
     774           0 :         hw->vdev = vdev;
     775             : 
     776           0 :         return 0;
     777             : }
     778             : 
     779           0 : SPDK_LOG_REGISTER_COMPONENT(virtio_pci)

Generated by: LCOV version 1.15