mirror of https://github.com/xemu-project/xemu.git
vfio/pci: Rework RTL8168 quirk
Another rework of this quirk, this time to update to the new quirk structure. We can handle the address and data registers with separate MemoryRegions and a quirk specific data structure, making the code much more understandable. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
6029a424be
commit
954258a5f1
|
@ -784,56 +784,46 @@ static void vfio_probe_nvidia_bar0_1800_quirk(VFIOPCIDevice *vdev, int nr)
|
||||||
* vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write
|
* vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write
|
||||||
* vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete
|
* vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete
|
||||||
*/
|
*/
|
||||||
static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
|
typedef struct VFIOrtl8168Quirk {
|
||||||
|
VFIOPCIDevice *vdev;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t data;
|
||||||
|
bool enabled;
|
||||||
|
} VFIOrtl8168Quirk;
|
||||||
|
|
||||||
|
static uint64_t vfio_rtl8168_quirk_address_read(void *opaque,
|
||||||
hwaddr addr, unsigned size)
|
hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
VFIOLegacyQuirk *quirk = opaque;
|
VFIOrtl8168Quirk *rtl = opaque;
|
||||||
VFIOPCIDevice *vdev = quirk->vdev;
|
VFIOPCIDevice *vdev = rtl->vdev;
|
||||||
uint64_t val = 0;
|
uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size);
|
||||||
|
|
||||||
if (!quirk->data.flags) { /* Non-MSI-X table access */
|
if (rtl->enabled) {
|
||||||
return vfio_region_read(&vdev->bars[quirk->data.bar].region,
|
data = rtl->addr ^ 0x80000000U; /* latch/complete */
|
||||||
addr + 0x70, size);
|
trace_vfio_quirk_rtl8168_fake_latch(vdev->vbasedev.name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (addr) {
|
return data;
|
||||||
case 4: /* address */
|
|
||||||
val = quirk->data.address_match ^ 0x80000000U; /* latch/complete */
|
|
||||||
break;
|
|
||||||
case 0: /* data */
|
|
||||||
if ((vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
|
|
||||||
memory_region_dispatch_read(&vdev->pdev.msix_table_mmio,
|
|
||||||
(hwaddr)(quirk->data.address_match & 0xfff),
|
|
||||||
&val, size, MEMTXATTRS_UNSPECIFIED);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_vfio_rtl8168_quirk_read(vdev->vbasedev.name,
|
|
||||||
addr ? "address" : "data", val);
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
|
static void vfio_rtl8168_quirk_address_write(void *opaque, hwaddr addr,
|
||||||
uint64_t data, unsigned size)
|
uint64_t data, unsigned size)
|
||||||
{
|
{
|
||||||
VFIOLegacyQuirk *quirk = opaque;
|
VFIOrtl8168Quirk *rtl = opaque;
|
||||||
VFIOPCIDevice *vdev = quirk->vdev;
|
VFIOPCIDevice *vdev = rtl->vdev;
|
||||||
|
|
||||||
|
rtl->enabled = false;
|
||||||
|
|
||||||
switch (addr) {
|
|
||||||
case 4: /* address */
|
|
||||||
if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */
|
if ((data & 0x7fff0000) == 0x10000) { /* MSI-X table */
|
||||||
quirk->data.flags = 1; /* Activate reads */
|
rtl->enabled = true;
|
||||||
quirk->data.address_match = data;
|
rtl->addr = (uint32_t)data;
|
||||||
|
|
||||||
trace_vfio_rtl8168_quirk_write(vdev->vbasedev.name, data);
|
|
||||||
|
|
||||||
if (data & 0x80000000U) { /* Do write */
|
if (data & 0x80000000U) { /* Do write */
|
||||||
if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
|
if (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
|
||||||
hwaddr offset = data & 0xfff;
|
hwaddr offset = data & 0xfff;
|
||||||
uint64_t val = quirk->data.address_mask;
|
uint64_t val = rtl->data;
|
||||||
|
|
||||||
trace_vfio_rtl8168_quirk_msix(vdev->vbasedev.name,
|
trace_vfio_quirk_rtl8168_msix_write(vdev->vbasedev.name,
|
||||||
(uint16_t)offset, val);
|
(uint16_t)offset, val);
|
||||||
|
|
||||||
/* Write to the proper guest MSI-X table instead */
|
/* Write to the proper guest MSI-X table instead */
|
||||||
|
@ -843,22 +833,14 @@ static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
|
||||||
}
|
}
|
||||||
return; /* Do not write guest MSI-X data to hardware */
|
return; /* Do not write guest MSI-X data to hardware */
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
quirk->data.flags = 0; /* De-activate reads, non-MSI-X */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0: /* data */
|
|
||||||
quirk->data.address_mask = data;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vfio_region_write(&vdev->bars[quirk->data.bar].region,
|
vfio_region_write(&vdev->bars[2].region, addr + 0x74, data, size);
|
||||||
addr + 0x70, data, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps vfio_rtl8168_window_quirk = {
|
static const MemoryRegionOps vfio_rtl_address_quirk = {
|
||||||
.read = vfio_rtl8168_window_quirk_read,
|
.read = vfio_rtl8168_quirk_address_read,
|
||||||
.write = vfio_rtl8168_window_quirk_write,
|
.write = vfio_rtl8168_quirk_address_write,
|
||||||
.valid = {
|
.valid = {
|
||||||
.min_access_size = 4,
|
.min_access_size = 4,
|
||||||
.max_access_size = 4,
|
.max_access_size = 4,
|
||||||
|
@ -867,32 +849,75 @@ static const MemoryRegionOps vfio_rtl8168_window_quirk = {
|
||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vfio_probe_rtl8168_bar2_window_quirk(VFIOPCIDevice *vdev, int nr)
|
static uint64_t vfio_rtl8168_quirk_data_read(void *opaque,
|
||||||
|
hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
PCIDevice *pdev = &vdev->pdev;
|
VFIOrtl8168Quirk *rtl = opaque;
|
||||||
VFIOQuirk *quirk;
|
VFIOPCIDevice *vdev = rtl->vdev;
|
||||||
VFIOLegacyQuirk *legacy;
|
uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size);
|
||||||
|
|
||||||
if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_REALTEK ||
|
if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
|
||||||
pci_get_word(pdev->config + PCI_DEVICE_ID) != 0x8168 || nr != 2) {
|
hwaddr offset = rtl->addr & 0xfff;
|
||||||
|
memory_region_dispatch_read(&vdev->pdev.msix_table_mmio, offset,
|
||||||
|
&data, size, MEMTXATTRS_UNSPECIFIED);
|
||||||
|
trace_vfio_quirk_rtl8168_msix_read(vdev->vbasedev.name, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vfio_rtl8168_quirk_data_write(void *opaque, hwaddr addr,
|
||||||
|
uint64_t data, unsigned size)
|
||||||
|
{
|
||||||
|
VFIOrtl8168Quirk *rtl = opaque;
|
||||||
|
VFIOPCIDevice *vdev = rtl->vdev;
|
||||||
|
|
||||||
|
rtl->data = (uint32_t)data;
|
||||||
|
|
||||||
|
vfio_region_write(&vdev->bars[2].region, addr + 0x70, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps vfio_rtl_data_quirk = {
|
||||||
|
.read = vfio_rtl8168_quirk_data_read,
|
||||||
|
.write = vfio_rtl8168_quirk_data_write,
|
||||||
|
.valid = {
|
||||||
|
.min_access_size = 4,
|
||||||
|
.max_access_size = 4,
|
||||||
|
.unaligned = false,
|
||||||
|
},
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void vfio_probe_rtl8168_bar2_quirk(VFIOPCIDevice *vdev, int nr)
|
||||||
|
{
|
||||||
|
VFIOQuirk *quirk;
|
||||||
|
VFIOrtl8168Quirk *rtl;
|
||||||
|
|
||||||
|
if (!vfio_pci_is(vdev, PCI_VENDOR_ID_REALTEK, 0x8168) || nr != 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
quirk = g_malloc0(sizeof(*quirk));
|
quirk = g_malloc0(sizeof(*quirk));
|
||||||
quirk->data = legacy = g_malloc0(sizeof(*legacy));
|
quirk->mem = g_malloc0_n(sizeof(MemoryRegion), 2);
|
||||||
quirk->mem = legacy->mem = g_malloc0_n(sizeof(MemoryRegion), 1);
|
quirk->nr_mem = 2;
|
||||||
quirk->nr_mem = 1;
|
quirk->data = rtl = g_malloc0(sizeof(*rtl));
|
||||||
legacy->vdev = vdev;
|
rtl->vdev = vdev;
|
||||||
legacy->data.bar = nr;
|
|
||||||
|
|
||||||
memory_region_init_io(quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk,
|
memory_region_init_io(&quirk->mem[0], OBJECT(vdev),
|
||||||
legacy, "vfio-rtl8168-window-quirk", 8);
|
&vfio_rtl_address_quirk, rtl,
|
||||||
|
"vfio-rtl8168-window-address-quirk", 4);
|
||||||
memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
|
memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
|
||||||
0x70, quirk->mem, 1);
|
0x74, &quirk->mem[0], 1);
|
||||||
|
|
||||||
|
memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
|
||||||
|
&vfio_rtl_data_quirk, rtl,
|
||||||
|
"vfio-rtl8168-window-data-quirk", 4);
|
||||||
|
memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem,
|
||||||
|
0x70, &quirk->mem[1], 1);
|
||||||
|
|
||||||
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
|
QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
|
||||||
|
|
||||||
trace_vfio_rtl8168_quirk_enable(vdev->vbasedev.name);
|
trace_vfio_quirk_rtl8168_probe(vdev->vbasedev.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -944,7 +969,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
|
||||||
vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
|
vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
|
||||||
vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
|
vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
|
||||||
vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
|
vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
|
||||||
vfio_probe_rtl8168_bar2_window_quirk(vdev, nr);
|
vfio_probe_rtl8168_bar2_quirk(vdev, nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr)
|
void vfio_bar_quirk_teardown(VFIOPCIDevice *vdev, int nr)
|
||||||
|
|
|
@ -1552,10 +1552,6 @@ vfio_generic_quirk_read(const char * region_name, const char *name, int index, u
|
||||||
vfio_generic_quirk_write(const char * region_name, const char *name, int index, uint64_t addr, uint64_t data, int size) "%s write(%s:BAR%d+0x%"PRIx64", 0x%"PRIx64", %d"
|
vfio_generic_quirk_write(const char * region_name, const char *name, int index, uint64_t addr, uint64_t data, int size) "%s write(%s:BAR%d+0x%"PRIx64", 0x%"PRIx64", %d"
|
||||||
vfio_probe_ati_bar4_window_quirk(const char *name) "Enabled ATI/AMD BAR4 window quirk for device %s"
|
vfio_probe_ati_bar4_window_quirk(const char *name) "Enabled ATI/AMD BAR4 window quirk for device %s"
|
||||||
#issue with )
|
#issue with )
|
||||||
vfio_rtl8168_quirk_read(const char *name, const char *type, uint64_t val) "%s [%s]: 0x%"PRIx64
|
|
||||||
vfio_rtl8168_quirk_write(const char *name, uint64_t val) "%s [address]: 0x%"PRIx64
|
|
||||||
vfio_rtl8168_quirk_msix(const char *name, uint16_t offset, uint64_t val) "%s MSI-X table write[0x%x]: 0x%"PRIx64
|
|
||||||
vfio_rtl8168_quirk_enable(const char *name) "%s"
|
|
||||||
vfio_probe_ati_bar2_4000_quirk(const char *name) "Enabled ATI/AMD BAR2 0x4000 quirk for device %s"
|
vfio_probe_ati_bar2_4000_quirk(const char *name) "Enabled ATI/AMD BAR2 0x4000 quirk for device %s"
|
||||||
vfio_probe_nvidia_bar5_window_quirk(const char *name) "Enabled NVIDIA BAR5 window quirk for device %s"
|
vfio_probe_nvidia_bar5_window_quirk(const char *name) "Enabled NVIDIA BAR5 window quirk for device %s"
|
||||||
vfio_probe_nvidia_bar0_88000_quirk(const char *name) "Enabled NVIDIA BAR0 0x88000 quirk for device %s"
|
vfio_probe_nvidia_bar0_88000_quirk(const char *name) "Enabled NVIDIA BAR0 0x88000 quirk for device %s"
|
||||||
|
@ -1588,6 +1584,10 @@ vfio_quirk_nvidia_3d0_state(const char *name, const char *state) "%s %s"
|
||||||
vfio_quirk_nvidia_3d0_read(const char *name, uint8_t offset, unsigned size, uint64_t val) " (%s, @0x%x, len=0x%x) %"PRIx64
|
vfio_quirk_nvidia_3d0_read(const char *name, uint8_t offset, unsigned size, uint64_t val) " (%s, @0x%x, len=0x%x) %"PRIx64
|
||||||
vfio_quirk_nvidia_3d0_write(const char *name, uint8_t offset, uint64_t data, unsigned size) "(%s, @0x%x, 0x%"PRIx64", len=0x%x)"
|
vfio_quirk_nvidia_3d0_write(const char *name, uint8_t offset, uint64_t data, unsigned size) "(%s, @0x%x, 0x%"PRIx64", len=0x%x)"
|
||||||
vfio_quirk_nvidia_3d0_probe(const char *name) "%s"
|
vfio_quirk_nvidia_3d0_probe(const char *name) "%s"
|
||||||
|
vfio_quirk_rtl8168_fake_latch(const char *name, uint64_t val) "%s 0x%"PRIx64
|
||||||
|
vfio_quirk_rtl8168_msix_write(const char *name, uint16_t offset, uint64_t val) "%s MSI-X table write[0x%x]: 0x%"PRIx64
|
||||||
|
vfio_quirk_rtl8168_msix_read(const char *name, uint16_t offset, uint64_t val) "%s MSI-X table read[0x%x]: 0x%"PRIx64
|
||||||
|
vfio_quirk_rtl8168_probe(const char *name) "%s"
|
||||||
|
|
||||||
# hw/vfio/vfio-common.c
|
# hw/vfio/vfio-common.c
|
||||||
vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)"
|
vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)"
|
||||||
|
|
Loading…
Reference in New Issue