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 */ /** Device-specific PCI config space */
void *dev_cfg; void *dev_cfg;
bool is_remapped;
}; };
struct virtio_pci_probe_ctx { struct virtio_pci_probe_ctx {
@ -67,6 +69,10 @@ struct virtio_pci_probe_ctx {
uint16_t device_id; 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, * Following macros are derived from linux/pci_regs.h, however,
* we can't simply include that header here, as there is no such * 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_VNDR 0x09
#define PCI_CAP_ID_MSIX 0x11 #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 static inline int
check_vq_phys_addr_ok(struct virtqueue *vq) 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 *p;
uint8_t old_gen, new_gen; uint8_t old_gen, new_gen;
g_thread_virtio_hw = hw;
do { do {
old_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation); 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); new_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
} while (old_gen != new_gen); } while (old_gen != new_gen);
g_thread_virtio_hw = NULL;
return 0; return 0;
} }
@ -177,9 +237,11 @@ modern_write_dev_config(struct virtio_dev *dev, size_t offset,
int i; int i;
const uint8_t *p = src; const uint8_t *p = src;
g_thread_virtio_hw = hw;
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++); spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++);
} }
g_thread_virtio_hw = NULL;
return 0; return 0;
} }
@ -190,11 +252,13 @@ modern_get_features(struct virtio_dev *dev)
struct virtio_hw *hw = dev->ctx; struct virtio_hw *hw = dev->ctx;
uint32_t features_lo, features_hi; uint32_t features_lo, features_hi;
g_thread_virtio_hw = hw;
spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 0); spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 0);
features_lo = spdk_mmio_read_4(&hw->common_cfg->device_feature); features_lo = spdk_mmio_read_4(&hw->common_cfg->device_feature);
spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 1); spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 1);
features_hi = spdk_mmio_read_4(&hw->common_cfg->device_feature); features_hi = spdk_mmio_read_4(&hw->common_cfg->device_feature);
g_thread_virtio_hw = NULL;
return ((uint64_t)features_hi << 32) | features_lo; return ((uint64_t)features_hi << 32) | features_lo;
} }
@ -209,11 +273,13 @@ modern_set_features(struct virtio_dev *dev, uint64_t features)
return -EINVAL; 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_select, 0);
spdk_mmio_write_4(&hw->common_cfg->guest_feature, features & ((1ULL << 32) - 1)); 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_select, 1);
spdk_mmio_write_4(&hw->common_cfg->guest_feature, features >> 32); spdk_mmio_write_4(&hw->common_cfg->guest_feature, features >> 32);
g_thread_virtio_hw = NULL;
dev->negotiated_features = features; dev->negotiated_features = features;
@ -239,8 +305,13 @@ static uint8_t
modern_get_status(struct virtio_dev *dev) modern_get_status(struct virtio_dev *dev)
{ {
struct virtio_hw *hw = dev->ctx; 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 static void
@ -248,16 +319,23 @@ modern_set_status(struct virtio_dev *dev, uint8_t status)
{ {
struct virtio_hw *hw = dev->ctx; struct virtio_hw *hw = dev->ctx;
g_thread_virtio_hw = hw;
spdk_mmio_write_1(&hw->common_cfg->device_status, status); spdk_mmio_write_1(&hw->common_cfg->device_status, status);
g_thread_virtio_hw = NULL;
} }
static uint16_t static uint16_t
modern_get_queue_size(struct virtio_dev *dev, uint16_t queue_id) modern_get_queue_size(struct virtio_dev *dev, uint16_t queue_id)
{ {
struct virtio_hw *hw = dev->ctx; 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); 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 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]) used_addr = (avail_addr + offsetof(struct vring_avail, ring[vq->vq_nentries])
+ VIRTIO_PCI_VRING_ALIGN - 1) & ~(VIRTIO_PCI_VRING_ALIGN - 1); + 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); spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, 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); notify_off * hw->notify_off_multiplier);
spdk_mmio_write_2(&hw->common_cfg->queue_enable, 1); 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, "queue %"PRIu16" addresses:\n", vq->vq_queue_index);
SPDK_DEBUGLOG(virtio_pci, "\t desc_addr: %" PRIx64 "\n", desc_addr); 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; struct virtio_hw *hw = dev->ctx;
g_thread_virtio_hw = hw;
spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index); spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, 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); &hw->common_cfg->queue_used_hi);
spdk_mmio_write_2(&hw->common_cfg->queue_enable, 0); spdk_mmio_write_2(&hw->common_cfg->queue_enable, 0);
g_thread_virtio_hw = NULL;
spdk_free(vq->vq_ring_virt_mem); spdk_free(vq->vq_ring_virt_mem);
} }
@ -349,7 +431,9 @@ modern_del_queue(struct virtio_dev *dev, struct virtqueue *vq)
static void static void
modern_notify_queue(struct virtio_dev *dev, struct virtqueue *vq) 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); spdk_mmio_write_2(vq->notify_addr, vq->vq_queue_index);
g_thread_virtio_hw = NULL;
} }
static const struct virtio_dev_ops modern_ops = { 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); free_virtio_hw(hw);
} }
if (g_sigset != true) {
spdk_pci_register_error_handler(virtio_pci_dev_sigbus_handler,
NULL);
g_sigset = true;
}
return rc; return rc;
} }