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:
parent
303d670f8e
commit
5ee049eeec
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user