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 */
|
/** 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user