mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-21 13:08:42 +00:00
dm/VBS-U: implement generic PCI barread/barwrite
This patch implements the generic PCI barread/barwrite callbacks. Specific barread/barwrite interfaces are called based on the baridx. Virtio legacy devices, transitional devices and modern devices can be handled in an unified way. Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com> Reviewed-by: Hao Li <hao.l.li@intel.com> Reviewed-by: Yin Fengwei <fengwei.yin@intel.com> Reviewed-by: Zhao Yakui <yakui.zhao@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
2acbebf6dc
commit
884f83f54f
@ -541,9 +541,9 @@ virtio_find_cr(int offset) {
|
|||||||
* If it's part of the virtio standard stuff, do that.
|
* If it's part of the virtio standard stuff, do that.
|
||||||
* Otherwise dispatch to the actual driver.
|
* Otherwise dispatch to the actual driver.
|
||||||
*/
|
*/
|
||||||
uint64_t
|
static uint64_t
|
||||||
virtio_pci_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
virtio_pci_legacy_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
int baridx, uint64_t offset, int size)
|
int baridx, uint64_t offset, int size)
|
||||||
{
|
{
|
||||||
struct virtio_base *base = dev->arg;
|
struct virtio_base *base = dev->arg;
|
||||||
struct virtio_ops *vops;
|
struct virtio_ops *vops;
|
||||||
@ -554,13 +554,6 @@ virtio_pci_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
|||||||
uint32_t value;
|
uint32_t value;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (base->flags & VIRTIO_USE_MSIX) {
|
|
||||||
if (baridx == pci_msix_table_bar(dev) ||
|
|
||||||
baridx == pci_msix_pba_bar(dev)) {
|
|
||||||
return pci_emul_msix_tread(dev, offset, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX probably should do something better than just assert() */
|
/* XXX probably should do something better than just assert() */
|
||||||
assert(baridx == base->legacy_pio_bar_idx);
|
assert(baridx == base->legacy_pio_bar_idx);
|
||||||
|
|
||||||
@ -662,9 +655,9 @@ done:
|
|||||||
* If it's part of the virtio standard stuff, do that.
|
* If it's part of the virtio standard stuff, do that.
|
||||||
* Otherwise dispatch to the actual driver.
|
* Otherwise dispatch to the actual driver.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
virtio_pci_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
virtio_pci_legacy_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
int baridx, uint64_t offset, int size, uint64_t value)
|
int baridx, uint64_t offset, int size, uint64_t value)
|
||||||
{
|
{
|
||||||
struct virtio_base *base = dev->arg;
|
struct virtio_base *base = dev->arg;
|
||||||
struct virtio_vq_info *vq;
|
struct virtio_vq_info *vq;
|
||||||
@ -675,14 +668,6 @@ virtio_pci_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
|||||||
uint32_t newoff;
|
uint32_t newoff;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (base->flags & VIRTIO_USE_MSIX) {
|
|
||||||
if (baridx == pci_msix_table_bar(dev) ||
|
|
||||||
baridx == pci_msix_pba_bar(dev)) {
|
|
||||||
pci_emul_msix_twrite(dev, offset, size, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX probably should do something better than just assert() */
|
/* XXX probably should do something better than just assert() */
|
||||||
assert(baridx == base->legacy_pio_bar_idx);
|
assert(baridx == base->legacy_pio_bar_idx);
|
||||||
|
|
||||||
@ -930,3 +915,318 @@ virtio_set_modern_bar(struct virtio_base *base, bool use_notify_pio)
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct cap_region {
|
||||||
|
uint64_t cap_offset; /* offset of capability region */
|
||||||
|
int cap_size; /* size of capability region */
|
||||||
|
int cap_id; /* capability id */
|
||||||
|
} cap_regions[] = {
|
||||||
|
{VIRTIO_CAP_COMMON_OFFSET, VIRTIO_CAP_COMMON_SIZE,
|
||||||
|
VIRTIO_PCI_CAP_COMMON_CFG},
|
||||||
|
{VIRTIO_CAP_ISR_OFFSET, VIRTIO_CAP_ISR_SIZE,
|
||||||
|
VIRTIO_PCI_CAP_ISR_CFG},
|
||||||
|
{VIRTIO_CAP_DEVICE_OFFSET, VIRTIO_CAP_DEVICE_SIZE,
|
||||||
|
VIRTIO_PCI_CAP_DEVICE_CFG},
|
||||||
|
{VIRTIO_CAP_NOTIFY_OFFSET, VIRTIO_CAP_NOTIFY_SIZE,
|
||||||
|
VIRTIO_PCI_CAP_NOTIFY_CFG},
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
virtio_get_cap_id(uint64_t offset, int size)
|
||||||
|
{
|
||||||
|
int i, rc = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cap_regions); i++) {
|
||||||
|
if (offset >= cap_regions[i].cap_offset &&
|
||||||
|
offset + size <= cap_regions[i].cap_offset +
|
||||||
|
cap_regions[i].cap_size)
|
||||||
|
return cap_regions[i].cap_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
virtio_common_cfg_read(struct pci_vdev *dev, uint64_t offset, int size)
|
||||||
|
{
|
||||||
|
/* TODO: to be implemented */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_common_cfg_write(struct pci_vdev *dev, uint64_t offset, int size,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
/* TODO: to be implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ignore driver writes to ISR region, and only support ISR region read */
|
||||||
|
static uint32_t
|
||||||
|
virtio_isr_cfg_read(struct pci_vdev *dev, uint64_t offset, int size)
|
||||||
|
{
|
||||||
|
/* TODO: to be implemented */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
virtio_device_cfg_read(struct pci_vdev *dev, uint64_t offset, int size)
|
||||||
|
{
|
||||||
|
/* TODO: to be implemented */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_device_cfg_write(struct pci_vdev *dev, uint64_t offset, int size,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
/* TODO: to be implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ignore driver reads from notify region, and only support notify region
|
||||||
|
* write
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
virtio_notify_cfg_write(struct pci_vdev *dev, uint64_t offset, int size,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
/* TODO: to be implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
virtio_pci_modern_mmio_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
|
int baridx, uint64_t offset, int size)
|
||||||
|
{
|
||||||
|
struct virtio_base *base = dev->arg;
|
||||||
|
struct virtio_ops *vops;
|
||||||
|
const char *name;
|
||||||
|
uint32_t value;
|
||||||
|
int capid;
|
||||||
|
|
||||||
|
assert(base->modern_mmio_bar_idx == baridx);
|
||||||
|
|
||||||
|
vops = base->vops;
|
||||||
|
name = vops->name;
|
||||||
|
value = size == 1 ? 0xff : size == 2 ? 0xffff : 0xffffffff;
|
||||||
|
|
||||||
|
if (size != 1 && size != 2 && size != 4) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: read from [%d:0x%lx] bad size %d\r\n",
|
||||||
|
name, baridx, offset, size);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
capid = virtio_get_cap_id(offset, size);
|
||||||
|
if (capid < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: read from [%d:0x%lx] bad range %d\r\n",
|
||||||
|
name, baridx, offset, size);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base->mtx)
|
||||||
|
pthread_mutex_lock(base->mtx);
|
||||||
|
|
||||||
|
switch (capid) {
|
||||||
|
case VIRTIO_PCI_CAP_COMMON_CFG:
|
||||||
|
offset -= VIRTIO_CAP_COMMON_OFFSET;
|
||||||
|
value = virtio_common_cfg_read(dev, offset, size);
|
||||||
|
break;
|
||||||
|
case VIRTIO_PCI_CAP_ISR_CFG:
|
||||||
|
offset -= VIRTIO_CAP_ISR_OFFSET;
|
||||||
|
value = virtio_isr_cfg_read(dev, offset, size);
|
||||||
|
break;
|
||||||
|
case VIRTIO_PCI_CAP_DEVICE_CFG:
|
||||||
|
offset -= VIRTIO_CAP_DEVICE_OFFSET;
|
||||||
|
value = virtio_device_cfg_read(dev, offset, size);
|
||||||
|
break;
|
||||||
|
default: /* guest driver should not read from notify region */
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: read from [%d:0x%lx] size %d not supported\r\n",
|
||||||
|
name, baridx, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base->mtx)
|
||||||
|
pthread_mutex_unlock(base->mtx);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_pci_modern_mmio_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
|
int baridx, uint64_t offset, int size,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
struct virtio_base *base = dev->arg;
|
||||||
|
struct virtio_ops *vops;
|
||||||
|
const char *name;
|
||||||
|
int capid;
|
||||||
|
|
||||||
|
assert(base->modern_mmio_bar_idx == baridx);
|
||||||
|
|
||||||
|
vops = base->vops;
|
||||||
|
name = vops->name;
|
||||||
|
|
||||||
|
if (size != 1 && size != 2 && size != 4) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: write to [%d:0x%lx] bad size %d\r\n",
|
||||||
|
name, baridx, offset, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
capid = virtio_get_cap_id(offset, size);
|
||||||
|
if (capid < 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: write to [%d:0x%lx] bad range %d\r\n",
|
||||||
|
name, baridx, offset, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base->mtx)
|
||||||
|
pthread_mutex_lock(base->mtx);
|
||||||
|
|
||||||
|
switch (capid) {
|
||||||
|
case VIRTIO_PCI_CAP_COMMON_CFG:
|
||||||
|
offset -= VIRTIO_CAP_COMMON_OFFSET;
|
||||||
|
virtio_common_cfg_write(dev, offset, size, value);
|
||||||
|
break;
|
||||||
|
case VIRTIO_PCI_CAP_DEVICE_CFG:
|
||||||
|
offset -= VIRTIO_CAP_DEVICE_OFFSET;
|
||||||
|
virtio_device_cfg_write(dev, offset, size, value);
|
||||||
|
break;
|
||||||
|
case VIRTIO_PCI_CAP_NOTIFY_CFG:
|
||||||
|
offset -= VIRTIO_CAP_NOTIFY_OFFSET;
|
||||||
|
virtio_notify_cfg_write(dev, offset, size, value);
|
||||||
|
break;
|
||||||
|
default: /* guest driver should not write to ISR region */
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: write to [%d:0x%lx] size %d not supported\r\n",
|
||||||
|
name, baridx, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base->mtx)
|
||||||
|
pthread_mutex_unlock(base->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
virtio_pci_modern_pio_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
|
int baridx, uint64_t offset, int size)
|
||||||
|
{
|
||||||
|
struct virtio_base *base = dev->arg;
|
||||||
|
|
||||||
|
assert(base->modern_pio_bar_idx == baridx);
|
||||||
|
/* guest driver should not read notify pio */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_pci_modern_pio_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
|
int baridx, uint64_t offset, int size,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
struct virtio_base *base = dev->arg;
|
||||||
|
struct virtio_vq_info *vq;
|
||||||
|
struct virtio_ops *vops;
|
||||||
|
const char *name;
|
||||||
|
uint64_t idx;
|
||||||
|
|
||||||
|
assert(base->modern_pio_bar_idx == baridx);
|
||||||
|
|
||||||
|
vops = base->vops;
|
||||||
|
name = vops->name;
|
||||||
|
idx = value;
|
||||||
|
|
||||||
|
if (size != 1 && size != 2 && size != 4) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: write to [%d:0x%lx] bad size %d\r\n",
|
||||||
|
name, baridx, offset, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx >= vops->nvq) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: queue %lu notify out of range\r\n", name, idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base->mtx)
|
||||||
|
pthread_mutex_lock(base->mtx);
|
||||||
|
|
||||||
|
vq = &base->queues[idx];
|
||||||
|
if (vq->notify)
|
||||||
|
(*vq->notify)(DEV_STRUCT(base), vq);
|
||||||
|
else if (vops->qnotify)
|
||||||
|
(*vops->qnotify)(DEV_STRUCT(base), vq);
|
||||||
|
else
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: qnotify queue %lu: missing vq/vops notify\r\n",
|
||||||
|
name, idx);
|
||||||
|
|
||||||
|
if (base->mtx)
|
||||||
|
pthread_mutex_unlock(base->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
virtio_pci_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
|
int baridx, uint64_t offset, int size)
|
||||||
|
{
|
||||||
|
struct virtio_base *base = dev->arg;
|
||||||
|
|
||||||
|
if (base->flags & VIRTIO_USE_MSIX) {
|
||||||
|
if (baridx == pci_msix_table_bar(dev) ||
|
||||||
|
baridx == pci_msix_pba_bar(dev)) {
|
||||||
|
return pci_emul_msix_tread(dev, offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baridx == base->legacy_pio_bar_idx)
|
||||||
|
return virtio_pci_legacy_read(ctx, vcpu, dev, baridx,
|
||||||
|
offset, size);
|
||||||
|
|
||||||
|
if (baridx == base->modern_mmio_bar_idx)
|
||||||
|
return virtio_pci_modern_mmio_read(ctx, vcpu, dev, baridx,
|
||||||
|
offset, size);
|
||||||
|
|
||||||
|
if (baridx == base->modern_pio_bar_idx)
|
||||||
|
return virtio_pci_modern_pio_read(ctx, vcpu, dev, baridx,
|
||||||
|
offset, size);
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: read unexpected baridx %d\r\n",
|
||||||
|
base->vops->name, baridx);
|
||||||
|
return size == 1 ? 0xff : size == 2 ? 0xffff : 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
virtio_pci_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||||
|
int baridx, uint64_t offset, int size, uint64_t value)
|
||||||
|
{
|
||||||
|
struct virtio_base *base = dev->arg;
|
||||||
|
|
||||||
|
if (base->flags & VIRTIO_USE_MSIX) {
|
||||||
|
if (baridx == pci_msix_table_bar(dev) ||
|
||||||
|
baridx == pci_msix_pba_bar(dev)) {
|
||||||
|
pci_emul_msix_twrite(dev, offset, size, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baridx == base->legacy_pio_bar_idx) {
|
||||||
|
virtio_pci_legacy_write(ctx, vcpu, dev, baridx,
|
||||||
|
offset, size, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baridx == base->modern_mmio_bar_idx) {
|
||||||
|
virtio_pci_modern_mmio_write(ctx, vcpu, dev, baridx,
|
||||||
|
offset, size, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baridx == base->modern_pio_bar_idx) {
|
||||||
|
virtio_pci_modern_pio_write(ctx, vcpu, dev, baridx,
|
||||||
|
offset, size, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: write unexpected baridx %d\r\n",
|
||||||
|
base->vops->name, baridx);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user