virtio_pci: add sigbus handler

Add the sigbus handler to virtio pci device
such as virtio_blk and virtio_scsi.

Change-Id: I07f2f175a585a425ef14050e2bf83bacb6e4c3bc
Signed-off-by: Jin Yu <jin.yu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/5769
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Jin Yu 2021-01-05 03:14:39 +08:00 committed by Jim Harris
parent 303d670f8e
commit 5ee049eeec

View File

@ -59,6 +59,8 @@ struct virtio_hw {
/** Device-specific PCI config space */
void *dev_cfg;
bool is_remapped;
};
struct virtio_pci_probe_ctx {
@ -67,6 +69,10 @@ struct virtio_pci_probe_ctx {
uint16_t device_id;
};
__thread struct virtio_hw *g_thread_virtio_hw = NULL;
static uint16_t g_signal_lock;
static bool g_sigset = false;
/*
* Following macros are derived from linux/pci_regs.h, however,
* we can't simply include that header here, as there is no such
@ -76,6 +82,58 @@ struct virtio_pci_probe_ctx {
#define PCI_CAP_ID_VNDR 0x09
#define PCI_CAP_ID_MSIX 0x11
static void
virtio_pci_dev_sigbus_handler(siginfo_t *info, void *ctx)
{
void *map_address = NULL;;
uint16_t flag = 0;
int i;
if (!__atomic_compare_exchange_n(&g_signal_lock, &flag, 1, false, __ATOMIC_ACQUIRE,
__ATOMIC_RELAXED)) {
SPDK_DEBUGLOG(virtio_pci, "request g_signal_lock failed\n");
return;
}
if (g_thread_virtio_hw == NULL || g_thread_virtio_hw->is_remapped) {
__atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
return;
}
/* We remap each bar to the same VA to avoid subsequent sigbus error.
* Because it is mapped to the same VA, such as hw->common_cfg and so on
* do not need to be modified.
*/
for (i = 0; i < 6; ++i) {
if (g_thread_virtio_hw->pci_bar[i].vaddr == NULL) {
continue;
}
map_address = mmap(g_thread_virtio_hw->pci_bar[i].vaddr,
g_thread_virtio_hw->pci_bar[i].len,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (map_address == MAP_FAILED) {
SPDK_ERRLOG("mmap failed\n");
goto fail;
}
memset(map_address, 0xFF, g_thread_virtio_hw->pci_bar[i].len);
}
g_thread_virtio_hw->is_remapped = true;
__atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
return;
fail:
for (--i; i >= 0; i--) {
if (g_thread_virtio_hw->pci_bar[i].vaddr == NULL) {
continue;
}
munmap(g_thread_virtio_hw->pci_bar[i].vaddr, g_thread_virtio_hw->pci_bar[i].len);
}
__atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
}
static inline int
check_vq_phys_addr_ok(struct virtqueue *vq)
{
@ -155,6 +213,7 @@ modern_read_dev_config(struct virtio_dev *dev, size_t offset,
uint8_t *p;
uint8_t old_gen, new_gen;
g_thread_virtio_hw = hw;
do {
old_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
@ -165,6 +224,7 @@ modern_read_dev_config(struct virtio_dev *dev, size_t offset,
new_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
} while (old_gen != new_gen);
g_thread_virtio_hw = NULL;
return 0;
}
@ -177,9 +237,11 @@ modern_write_dev_config(struct virtio_dev *dev, size_t offset,
int i;
const uint8_t *p = src;
g_thread_virtio_hw = hw;
for (i = 0; i < length; i++) {
spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++);
}
g_thread_virtio_hw = NULL;
return 0;
}
@ -190,11 +252,13 @@ modern_get_features(struct virtio_dev *dev)
struct virtio_hw *hw = dev->ctx;
uint32_t features_lo, features_hi;
g_thread_virtio_hw = hw;
spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 0);
features_lo = spdk_mmio_read_4(&hw->common_cfg->device_feature);
spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 1);
features_hi = spdk_mmio_read_4(&hw->common_cfg->device_feature);
g_thread_virtio_hw = NULL;
return ((uint64_t)features_hi << 32) | features_lo;
}
@ -209,11 +273,13 @@ modern_set_features(struct virtio_dev *dev, uint64_t features)
return -EINVAL;
}
g_thread_virtio_hw = hw;
spdk_mmio_write_4(&hw->common_cfg->guest_feature_select, 0);
spdk_mmio_write_4(&hw->common_cfg->guest_feature, features & ((1ULL << 32) - 1));
spdk_mmio_write_4(&hw->common_cfg->guest_feature_select, 1);
spdk_mmio_write_4(&hw->common_cfg->guest_feature, features >> 32);
g_thread_virtio_hw = NULL;
dev->negotiated_features = features;
@ -239,8 +305,13 @@ static uint8_t
modern_get_status(struct virtio_dev *dev)
{
struct virtio_hw *hw = dev->ctx;
uint8_t ret;
return spdk_mmio_read_1(&hw->common_cfg->device_status);
g_thread_virtio_hw = hw;
ret = spdk_mmio_read_1(&hw->common_cfg->device_status);
g_thread_virtio_hw = NULL;
return ret;
}
static void
@ -248,16 +319,23 @@ modern_set_status(struct virtio_dev *dev, uint8_t status)
{
struct virtio_hw *hw = dev->ctx;
g_thread_virtio_hw = hw;
spdk_mmio_write_1(&hw->common_cfg->device_status, status);
g_thread_virtio_hw = NULL;
}
static uint16_t
modern_get_queue_size(struct virtio_dev *dev, uint16_t queue_id)
{
struct virtio_hw *hw = dev->ctx;
uint16_t ret;
g_thread_virtio_hw = hw;
spdk_mmio_write_2(&hw->common_cfg->queue_select, queue_id);
return spdk_mmio_read_2(&hw->common_cfg->queue_size);
ret = spdk_mmio_read_2(&hw->common_cfg->queue_size);
g_thread_virtio_hw = NULL;
return ret;
}
static int
@ -302,6 +380,7 @@ modern_setup_queue(struct virtio_dev *dev, struct virtqueue *vq)
used_addr = (avail_addr + offsetof(struct vring_avail, ring[vq->vq_nentries])
+ VIRTIO_PCI_VRING_ALIGN - 1) & ~(VIRTIO_PCI_VRING_ALIGN - 1);
g_thread_virtio_hw = hw;
spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
@ -316,6 +395,7 @@ modern_setup_queue(struct virtio_dev *dev, struct virtqueue *vq)
notify_off * hw->notify_off_multiplier);
spdk_mmio_write_2(&hw->common_cfg->queue_enable, 1);
g_thread_virtio_hw = NULL;
SPDK_DEBUGLOG(virtio_pci, "queue %"PRIu16" addresses:\n", vq->vq_queue_index);
SPDK_DEBUGLOG(virtio_pci, "\t desc_addr: %" PRIx64 "\n", desc_addr);
@ -332,6 +412,7 @@ modern_del_queue(struct virtio_dev *dev, struct virtqueue *vq)
{
struct virtio_hw *hw = dev->ctx;
g_thread_virtio_hw = hw;
spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
@ -342,6 +423,7 @@ modern_del_queue(struct virtio_dev *dev, struct virtqueue *vq)
&hw->common_cfg->queue_used_hi);
spdk_mmio_write_2(&hw->common_cfg->queue_enable, 0);
g_thread_virtio_hw = NULL;
spdk_free(vq->vq_ring_virt_mem);
}
@ -349,7 +431,9 @@ modern_del_queue(struct virtio_dev *dev, struct virtqueue *vq)
static void
modern_notify_queue(struct virtio_dev *dev, struct virtqueue *vq)
{
g_thread_virtio_hw = dev->ctx;
spdk_mmio_write_2(vq->notify_addr, vq->vq_queue_index);
g_thread_virtio_hw = NULL;
}
static const struct virtio_dev_ops modern_ops = {
@ -530,6 +614,12 @@ virtio_pci_dev_probe(struct spdk_pci_device *pci_dev, struct virtio_pci_probe_ct
free_virtio_hw(hw);
}
if (g_sigset != true) {
spdk_pci_register_error_handler(virtio_pci_dev_sigbus_handler,
NULL);
g_sigset = true;
}
return rc;
}