mirror of https://github.com/xemu-project/xemu.git
GPU pull request
Includes: - [PATCH] virtio-gpu-rutabaga: Add empty interface to fix arm64 crash - [PATCH v2 0/4] Misc ati-vga patches - [PATCH v2 0/5] virtio-gpu: add blob migration support -----BEGIN PGP SIGNATURE----- iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmVI6rYcHG1hcmNhbmRy ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5VdjEAC6xsnITkX5FgJVjDo2 XQWGz2MgWIFcqMXYVbz21UgY86KjCE7jVbGL6BkWO8N/XzsP6EUEIcUcHm7KcdwU +csMTjgnZUb97Ov/d27Ge9UYr/9rgozyoQRwvvQYXRFfxTur+b+poodcAOn3Ml3Q vXBTYb0z2FYd85VcVx59w5lFlonER1z4wnQuF4GLCBNIW/GX+S87+xyv1FZCgWku luBhWa7ihVrlrYA2UaoQS7sI2ch/wI9NnfP1p+31Iy/w1wLwQOj9ofTslbehTcvS uDU/+WMkhmlB8LOl7mx8bGHeBab9iUvSz5H5MIfTgrk6hRaaMJp3y2lefsc9cWuA 5aPvj0qouTEkIZ+2aPClcZk11mIbH5lT9eeEYc16Ztrt5VJHXmR7RwF74hHQbxY3 LDiRlpvhBfX4muaPw4L1max9kJZdOvo9aQVqKL7hkrTBL/xBmvg40ZRrWDrIvZZg 8TZ8woD2ORiic/hTxmI7waG+f3WozH/drStJrOFpJA7+iFefrHgkv2K7ze9LhWmZ ookM8K96NV6AnPQ39N2nuvQ/Fndqv7Kg4AiOwzj3epfg/rDscaJw9J2JQuCGEiEF KEIt3hyIo/HOXXiwmGqP3BWs90EmMvZTDmAt5e/cT0eQ1jWwJ3Tj8ShVg2S8QW0h TMXdPV7bepd49aaynpGFeADhfw== =k/gN -----END PGP SIGNATURE----- Merge tag 'gpu-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging GPU pull request Includes: - [PATCH] virtio-gpu-rutabaga: Add empty interface to fix arm64 crash - [PATCH v2 0/4] Misc ati-vga patches - [PATCH v2 0/5] virtio-gpu: add blob migration support # -----BEGIN PGP SIGNATURE----- # # iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmVI6rYcHG1hcmNhbmRy # ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5VdjEAC6xsnITkX5FgJVjDo2 # XQWGz2MgWIFcqMXYVbz21UgY86KjCE7jVbGL6BkWO8N/XzsP6EUEIcUcHm7KcdwU # +csMTjgnZUb97Ov/d27Ge9UYr/9rgozyoQRwvvQYXRFfxTur+b+poodcAOn3Ml3Q # vXBTYb0z2FYd85VcVx59w5lFlonER1z4wnQuF4GLCBNIW/GX+S87+xyv1FZCgWku # luBhWa7ihVrlrYA2UaoQS7sI2ch/wI9NnfP1p+31Iy/w1wLwQOj9ofTslbehTcvS # uDU/+WMkhmlB8LOl7mx8bGHeBab9iUvSz5H5MIfTgrk6hRaaMJp3y2lefsc9cWuA # 5aPvj0qouTEkIZ+2aPClcZk11mIbH5lT9eeEYc16Ztrt5VJHXmR7RwF74hHQbxY3 # LDiRlpvhBfX4muaPw4L1max9kJZdOvo9aQVqKL7hkrTBL/xBmvg40ZRrWDrIvZZg # 8TZ8woD2ORiic/hTxmI7waG+f3WozH/drStJrOFpJA7+iFefrHgkv2K7ze9LhWmZ # ookM8K96NV6AnPQ39N2nuvQ/Fndqv7Kg4AiOwzj3epfg/rDscaJw9J2JQuCGEiEF # KEIt3hyIo/HOXXiwmGqP3BWs90EmMvZTDmAt5e/cT0eQ1jWwJ3Tj8ShVg2S8QW0h # TMXdPV7bepd49aaynpGFeADhfw== # =k/gN # -----END PGP SIGNATURE----- # gpg: Signature made Mon 06 Nov 2023 21:31:34 HKT # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * tag 'gpu-pull-request' of https://gitlab.com/marcandre.lureau/qemu: Revert "virtio-gpu: block migration of VMs with blob=true" virtio-gpu: add virtio-gpu/blob vmstate subsection virtio-gpu: move scanout restoration to post_load virtio-gpu: factor out restore mapping virtio-gpu: block migration of VMs with blob=true ati-vga: Implement fallback for pixman routines ati-vga: Add 30 bit palette access register ati-vga: Support unaligned access to GPIO DDC registers ati-vga: Fix aperture sizes virtio-gpu-rutabaga: Add empty interface to fix arm64 crash Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
9f33cf2a89
|
@ -319,11 +319,13 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
|
|||
case DAC_CNTL:
|
||||
val = s->regs.dac_cntl;
|
||||
break;
|
||||
case GPIO_VGA_DDC:
|
||||
val = s->regs.gpio_vga_ddc;
|
||||
case GPIO_VGA_DDC ... GPIO_VGA_DDC + 3:
|
||||
val = ati_reg_read_offs(s->regs.gpio_vga_ddc,
|
||||
addr - GPIO_VGA_DDC, size);
|
||||
break;
|
||||
case GPIO_DVI_DDC:
|
||||
val = s->regs.gpio_dvi_ddc;
|
||||
case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3:
|
||||
val = ati_reg_read_offs(s->regs.gpio_dvi_ddc,
|
||||
addr - GPIO_DVI_DDC, size);
|
||||
break;
|
||||
case GPIO_MONID ... GPIO_MONID + 3:
|
||||
val = ati_reg_read_offs(s->regs.gpio_monid,
|
||||
|
@ -337,6 +339,9 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
|
|||
case PALETTE_DATA:
|
||||
val = vga_ioport_read(&s->vga, VGA_PEL_D);
|
||||
break;
|
||||
case PALETTE_30_DATA:
|
||||
val = s->regs.palette[vga_ioport_read(&s->vga, VGA_PEL_IR)];
|
||||
break;
|
||||
case CNFG_CNTL:
|
||||
val = s->regs.config_cntl;
|
||||
break;
|
||||
|
@ -349,14 +354,17 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
|
|||
PCI_BASE_ADDRESS_0, size) & 0xfffffff0;
|
||||
break;
|
||||
case CONFIG_APER_SIZE:
|
||||
val = s->vga.vram_size;
|
||||
val = s->vga.vram_size / 2;
|
||||
break;
|
||||
case CONFIG_REG_1_BASE:
|
||||
val = pci_default_read_config(&s->dev,
|
||||
PCI_BASE_ADDRESS_2, size) & 0xfffffff0;
|
||||
break;
|
||||
case CONFIG_REG_APER_SIZE:
|
||||
val = memory_region_size(&s->mm);
|
||||
val = memory_region_size(&s->mm) / 2;
|
||||
break;
|
||||
case HOST_PATH_CNTL:
|
||||
val = BIT(23); /* Radeon HDP_APER_CNTL */
|
||||
break;
|
||||
case MC_STATUS:
|
||||
val = 5;
|
||||
|
@ -612,29 +620,34 @@ static void ati_mm_write(void *opaque, hwaddr addr,
|
|||
s->regs.dac_cntl = data & 0xffffe3ff;
|
||||
s->vga.dac_8bit = !!(data & DAC_8BIT_EN);
|
||||
break;
|
||||
case GPIO_VGA_DDC:
|
||||
/*
|
||||
* GPIO regs for DDC access. Because some drivers access these via
|
||||
* multiple byte writes we have to be careful when we send bits to
|
||||
* avoid spurious changes in bitbang_i2c state. Only do it when either
|
||||
* the enable bits are changed or output bits changed while enabled.
|
||||
*/
|
||||
case GPIO_VGA_DDC ... GPIO_VGA_DDC + 3:
|
||||
if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
|
||||
/* FIXME: Maybe add a property to select VGA or DVI port? */
|
||||
}
|
||||
break;
|
||||
case GPIO_DVI_DDC:
|
||||
case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3:
|
||||
if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
|
||||
s->regs.gpio_dvi_ddc = ati_i2c(&s->bbi2c, data, 0);
|
||||
ati_reg_write_offs(&s->regs.gpio_dvi_ddc,
|
||||
addr - GPIO_DVI_DDC, data, size);
|
||||
if ((addr <= GPIO_DVI_DDC + 2 && addr + size > GPIO_DVI_DDC + 2) ||
|
||||
(addr == GPIO_DVI_DDC && (s->regs.gpio_dvi_ddc & 0x30000))) {
|
||||
s->regs.gpio_dvi_ddc = ati_i2c(&s->bbi2c,
|
||||
s->regs.gpio_dvi_ddc, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GPIO_MONID ... GPIO_MONID + 3:
|
||||
/* FIXME What does Radeon have here? */
|
||||
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
|
||||
/* Rage128p accesses DDC via MONID(1-2) with additional mask bit */
|
||||
ati_reg_write_offs(&s->regs.gpio_monid,
|
||||
addr - GPIO_MONID, data, size);
|
||||
/*
|
||||
* Rage128p accesses DDC used to get EDID via these bits.
|
||||
* Because some drivers access this via multiple byte writes
|
||||
* we have to be careful when we send bits to avoid spurious
|
||||
* changes in bitbang_i2c state. So only do it when mask is set
|
||||
* and either the enable bits are changed or output bits changed
|
||||
* while enabled.
|
||||
*/
|
||||
if ((s->regs.gpio_monid & BIT(25)) &&
|
||||
((addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) ||
|
||||
(addr == GPIO_MONID && (s->regs.gpio_monid & 0x60000)))) {
|
||||
|
@ -663,6 +676,12 @@ static void ati_mm_write(void *opaque, hwaddr addr,
|
|||
data >>= 8;
|
||||
vga_ioport_write(&s->vga, VGA_PEL_D, data & 0xff);
|
||||
break;
|
||||
case PALETTE_30_DATA:
|
||||
s->regs.palette[vga_ioport_read(&s->vga, VGA_PEL_IW)] = data;
|
||||
vga_ioport_write(&s->vga, VGA_PEL_D, (data >> 22) & 0xff);
|
||||
vga_ioport_write(&s->vga, VGA_PEL_D, (data >> 12) & 0xff);
|
||||
vga_ioport_write(&s->vga, VGA_PEL_D, (data >> 2) & 0xff);
|
||||
break;
|
||||
case CNFG_CNTL:
|
||||
s->regs.config_cntl = data;
|
||||
break;
|
||||
|
@ -1014,6 +1033,7 @@ static Property ati_vga_properties[] = {
|
|||
DEFINE_PROP_UINT16("x-device-id", ATIVGAState, dev_id,
|
||||
PCI_DEVICE_ID_ATI_RAGE128_PF),
|
||||
DEFINE_PROP_BOOL("guest_hwcursor", ATIVGAState, cursor_guest_mode, false),
|
||||
DEFINE_PROP_UINT8("x-pixman", ATIVGAState, use_pixman, 3),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
|
@ -1035,11 +1055,18 @@ static void ati_vga_class_init(ObjectClass *klass, void *data)
|
|||
k->exit = ati_vga_exit;
|
||||
}
|
||||
|
||||
static void ati_vga_init(Object *o)
|
||||
{
|
||||
object_property_set_description(o, "x-pixman", "Use pixman for: "
|
||||
"1: fill, 2: blit");
|
||||
}
|
||||
|
||||
static const TypeInfo ati_vga_info = {
|
||||
.name = TYPE_ATI_VGA,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(ATIVGAState),
|
||||
.class_init = ati_vga_class_init,
|
||||
.instance_init = ati_vga_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
{ },
|
||||
|
|
|
@ -92,6 +92,7 @@ void ati_2d_blt(ATIVGAState *s)
|
|||
switch (s->regs.dp_mix & GMC_ROP3_MASK) {
|
||||
case ROP3_SRCCOPY:
|
||||
{
|
||||
bool fallback = false;
|
||||
unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
|
||||
s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width);
|
||||
unsigned src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
|
||||
|
@ -122,27 +123,50 @@ void ati_2d_blt(ATIVGAState *s)
|
|||
src_bits, dst_bits, src_stride, dst_stride, bpp, bpp,
|
||||
src_x, src_y, dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height);
|
||||
if (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT &&
|
||||
if ((s->use_pixman & BIT(1)) &&
|
||||
s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT &&
|
||||
s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM) {
|
||||
pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
|
||||
src_stride, dst_stride, bpp, bpp,
|
||||
src_x, src_y, dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height);
|
||||
} else {
|
||||
fallback = !pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
|
||||
src_stride, dst_stride, bpp, bpp,
|
||||
src_x, src_y, dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height);
|
||||
} else if (s->use_pixman & BIT(1)) {
|
||||
/* FIXME: We only really need a temporary if src and dst overlap */
|
||||
int llb = s->regs.dst_width * (bpp / 8);
|
||||
int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
|
||||
uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) *
|
||||
s->regs.dst_height);
|
||||
pixman_blt((uint32_t *)src_bits, tmp,
|
||||
src_stride, tmp_stride, bpp, bpp,
|
||||
src_x, src_y, 0, 0,
|
||||
s->regs.dst_width, s->regs.dst_height);
|
||||
pixman_blt(tmp, (uint32_t *)dst_bits,
|
||||
tmp_stride, dst_stride, bpp, bpp,
|
||||
0, 0, dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height);
|
||||
fallback = !pixman_blt((uint32_t *)src_bits, tmp,
|
||||
src_stride, tmp_stride, bpp, bpp,
|
||||
src_x, src_y, 0, 0,
|
||||
s->regs.dst_width, s->regs.dst_height);
|
||||
if (!fallback) {
|
||||
fallback = !pixman_blt(tmp, (uint32_t *)dst_bits,
|
||||
tmp_stride, dst_stride, bpp, bpp,
|
||||
0, 0, dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height);
|
||||
}
|
||||
g_free(tmp);
|
||||
} else {
|
||||
fallback = true;
|
||||
}
|
||||
if (fallback) {
|
||||
unsigned int y, i, j, bypp = bpp / 8;
|
||||
unsigned int src_pitch = src_stride * sizeof(uint32_t);
|
||||
unsigned int dst_pitch = dst_stride * sizeof(uint32_t);
|
||||
|
||||
for (y = 0; y < s->regs.dst_height; y++) {
|
||||
i = dst_x * bypp;
|
||||
j = src_x * bypp;
|
||||
if (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM) {
|
||||
i += (dst_y + y) * dst_pitch;
|
||||
j += (src_y + y) * src_pitch;
|
||||
} else {
|
||||
i += (dst_y + s->regs.dst_height - 1 - y) * dst_pitch;
|
||||
j += (src_y + s->regs.dst_height - 1 - y) * src_pitch;
|
||||
}
|
||||
memmove(&dst_bits[i], &src_bits[j], s->regs.dst_width * bypp);
|
||||
}
|
||||
}
|
||||
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&
|
||||
dst_bits < s->vga.vram_ptr + s->vga.vbe_start_addr +
|
||||
|
@ -180,14 +204,21 @@ void ati_2d_blt(ATIVGAState *s)
|
|||
|
||||
dst_stride /= sizeof(uint32_t);
|
||||
DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n",
|
||||
dst_bits, dst_stride, bpp,
|
||||
dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height,
|
||||
filler);
|
||||
pixman_fill((uint32_t *)dst_bits, dst_stride, bpp,
|
||||
dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height,
|
||||
filler);
|
||||
dst_bits, dst_stride, bpp, dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height, filler);
|
||||
if (!(s->use_pixman & BIT(0)) ||
|
||||
!pixman_fill((uint32_t *)dst_bits, dst_stride, bpp, dst_x, dst_y,
|
||||
s->regs.dst_width, s->regs.dst_height, filler)) {
|
||||
/* fallback when pixman failed or we don't want to call it */
|
||||
unsigned int x, y, i, bypp = bpp / 8;
|
||||
unsigned int dst_pitch = dst_stride * sizeof(uint32_t);
|
||||
for (y = 0; y < s->regs.dst_height; y++) {
|
||||
i = dst_x * bypp + (dst_y + y) * dst_pitch;
|
||||
for (x = 0; x < s->regs.dst_width; x++, i += bypp) {
|
||||
stn_he_p(&dst_bits[i], bypp, filler);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&
|
||||
dst_bits < s->vga.vram_ptr + s->vga.vbe_start_addr +
|
||||
s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] * s->vga.vbe_line_offset) {
|
||||
|
|
|
@ -30,6 +30,7 @@ static struct ati_regdesc ati_reg_names[] = {
|
|||
{"AMCGPIO_EN_MIR", 0x00a8},
|
||||
{"PALETTE_INDEX", 0x00b0},
|
||||
{"PALETTE_DATA", 0x00b4},
|
||||
{"PALETTE_30_DATA", 0x00b8},
|
||||
{"CNFG_CNTL", 0x00e0},
|
||||
{"GEN_RESET_CNTL", 0x00f0},
|
||||
{"CNFG_MEMSIZE", 0x00f8},
|
||||
|
@ -38,6 +39,7 @@ static struct ati_regdesc ati_reg_names[] = {
|
|||
{"CONFIG_APER_SIZE", 0x0108},
|
||||
{"CONFIG_REG_1_BASE", 0x010c},
|
||||
{"CONFIG_REG_APER_SIZE", 0x0110},
|
||||
{"HOST_PATH_CNTL", 0x0130},
|
||||
{"MEM_CNTL", 0x0140},
|
||||
{"MC_FB_LOCATION", 0x0148},
|
||||
{"MC_AGP_LOCATION", 0x014C},
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef struct ATIVGARegs {
|
|||
uint32_t gpio_dvi_ddc;
|
||||
uint32_t gpio_monid;
|
||||
uint32_t config_cntl;
|
||||
uint32_t palette[256];
|
||||
uint32_t crtc_h_total_disp;
|
||||
uint32_t crtc_h_sync_strt_wid;
|
||||
uint32_t crtc_v_total_disp;
|
||||
|
@ -89,6 +90,7 @@ struct ATIVGAState {
|
|||
char *model;
|
||||
uint16_t dev_id;
|
||||
uint8_t mode;
|
||||
uint8_t use_pixman;
|
||||
bool cursor_guest_mode;
|
||||
uint16_t cursor_size;
|
||||
uint32_t cursor_offset;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define AMCGPIO_EN_MIR 0x00a8
|
||||
#define PALETTE_INDEX 0x00b0
|
||||
#define PALETTE_DATA 0x00b4
|
||||
#define PALETTE_30_DATA 0x00b8
|
||||
#define CNFG_CNTL 0x00e0
|
||||
#define GEN_RESET_CNTL 0x00f0
|
||||
#define CNFG_MEMSIZE 0x00f8
|
||||
|
@ -56,6 +57,7 @@
|
|||
#define CONFIG_APER_SIZE 0x0108
|
||||
#define CONFIG_REG_1_BASE 0x010c
|
||||
#define CONFIG_REG_APER_SIZE 0x0110
|
||||
#define HOST_PATH_CNTL 0x0130
|
||||
#define MEM_CNTL 0x0140
|
||||
#define MC_FB_LOCATION 0x0148
|
||||
#define MC_AGP_LOCATION 0x014C
|
||||
|
|
|
@ -36,6 +36,7 @@ static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
|
|||
.instance_init = virtio_gpu_rutabaga_initfn,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
{ },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1213,6 +1213,9 @@ static int virtio_gpu_save(QEMUFile *f, void *opaque, size_t size,
|
|||
assert(QTAILQ_EMPTY(&g->cmdq));
|
||||
|
||||
QTAILQ_FOREACH(res, &g->reslist, next) {
|
||||
if (res->blob_size) {
|
||||
continue;
|
||||
}
|
||||
qemu_put_be32(f, res->resource_id);
|
||||
qemu_put_be32(f, res->width);
|
||||
qemu_put_be32(f, res->height);
|
||||
|
@ -1230,12 +1233,40 @@ static int virtio_gpu_save(QEMUFile *f, void *opaque, size_t size,
|
|||
return vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL);
|
||||
}
|
||||
|
||||
static bool virtio_gpu_load_restore_mapping(VirtIOGPU *g,
|
||||
struct virtio_gpu_simple_resource *res)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < res->iov_cnt; i++) {
|
||||
hwaddr len = res->iov[i].iov_len;
|
||||
res->iov[i].iov_base =
|
||||
dma_memory_map(VIRTIO_DEVICE(g)->dma_as, res->addrs[i], &len,
|
||||
DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED);
|
||||
|
||||
if (!res->iov[i].iov_base || len != res->iov[i].iov_len) {
|
||||
/* Clean up the half-a-mapping we just created... */
|
||||
if (res->iov[i].iov_base) {
|
||||
dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, res->iov[i].iov_base,
|
||||
len, DMA_DIRECTION_TO_DEVICE, 0);
|
||||
}
|
||||
/* ...and the mappings for previous loop iterations */
|
||||
res->iov_cnt = i;
|
||||
virtio_gpu_cleanup_mapping(g, res);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
|
||||
g->hostmem += res->hostmem;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
|
||||
const VMStateField *field)
|
||||
{
|
||||
VirtIOGPU *g = opaque;
|
||||
struct virtio_gpu_simple_resource *res;
|
||||
struct virtio_gpu_scanout *scanout;
|
||||
uint32_t resource_id, pformat;
|
||||
void *bits = NULL;
|
||||
int i;
|
||||
|
@ -1294,40 +1325,96 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
|
|||
qemu_get_buffer(f, (void *)pixman_image_get_data(res->image),
|
||||
pixman_image_get_stride(res->image) * res->height);
|
||||
|
||||
/* restore mapping */
|
||||
for (i = 0; i < res->iov_cnt; i++) {
|
||||
hwaddr len = res->iov[i].iov_len;
|
||||
res->iov[i].iov_base =
|
||||
dma_memory_map(VIRTIO_DEVICE(g)->dma_as, res->addrs[i], &len,
|
||||
DMA_DIRECTION_TO_DEVICE,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
|
||||
if (!res->iov[i].iov_base || len != res->iov[i].iov_len) {
|
||||
/* Clean up the half-a-mapping we just created... */
|
||||
if (res->iov[i].iov_base) {
|
||||
dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as,
|
||||
res->iov[i].iov_base,
|
||||
len,
|
||||
DMA_DIRECTION_TO_DEVICE,
|
||||
0);
|
||||
}
|
||||
/* ...and the mappings for previous loop iterations */
|
||||
res->iov_cnt = i;
|
||||
virtio_gpu_cleanup_mapping(g, res);
|
||||
pixman_image_unref(res->image);
|
||||
g_free(res);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!virtio_gpu_load_restore_mapping(g, res)) {
|
||||
pixman_image_unref(res->image);
|
||||
g_free(res);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
|
||||
g->hostmem += res->hostmem;
|
||||
|
||||
resource_id = qemu_get_be32(f);
|
||||
}
|
||||
|
||||
/* load & apply scanout state */
|
||||
vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_gpu_blob_save(QEMUFile *f, void *opaque, size_t size,
|
||||
const VMStateField *field, JSONWriter *vmdesc)
|
||||
{
|
||||
VirtIOGPU *g = opaque;
|
||||
struct virtio_gpu_simple_resource *res;
|
||||
int i;
|
||||
|
||||
/* in 2d mode we should never find unprocessed commands here */
|
||||
assert(QTAILQ_EMPTY(&g->cmdq));
|
||||
|
||||
QTAILQ_FOREACH(res, &g->reslist, next) {
|
||||
if (!res->blob_size) {
|
||||
continue;
|
||||
}
|
||||
qemu_put_be32(f, res->resource_id);
|
||||
qemu_put_be32(f, res->blob_size);
|
||||
qemu_put_be32(f, res->iov_cnt);
|
||||
for (i = 0; i < res->iov_cnt; i++) {
|
||||
qemu_put_be64(f, res->addrs[i]);
|
||||
qemu_put_be32(f, res->iov[i].iov_len);
|
||||
}
|
||||
}
|
||||
qemu_put_be32(f, 0); /* end of list */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_gpu_blob_load(QEMUFile *f, void *opaque, size_t size,
|
||||
const VMStateField *field)
|
||||
{
|
||||
VirtIOGPU *g = opaque;
|
||||
struct virtio_gpu_simple_resource *res;
|
||||
uint32_t resource_id;
|
||||
int i;
|
||||
|
||||
resource_id = qemu_get_be32(f);
|
||||
while (resource_id != 0) {
|
||||
res = virtio_gpu_find_resource(g, resource_id);
|
||||
if (res) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = g_new0(struct virtio_gpu_simple_resource, 1);
|
||||
res->resource_id = resource_id;
|
||||
res->blob_size = qemu_get_be32(f);
|
||||
res->iov_cnt = qemu_get_be32(f);
|
||||
res->addrs = g_new(uint64_t, res->iov_cnt);
|
||||
res->iov = g_new(struct iovec, res->iov_cnt);
|
||||
|
||||
/* read data */
|
||||
for (i = 0; i < res->iov_cnt; i++) {
|
||||
res->addrs[i] = qemu_get_be64(f);
|
||||
res->iov[i].iov_len = qemu_get_be32(f);
|
||||
}
|
||||
|
||||
if (!virtio_gpu_load_restore_mapping(g, res)) {
|
||||
g_free(res);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
virtio_gpu_init_udmabuf(res);
|
||||
|
||||
resource_id = qemu_get_be32(f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_gpu_post_load(void *opaque, int version_id)
|
||||
{
|
||||
VirtIOGPU *g = opaque;
|
||||
struct virtio_gpu_scanout *scanout;
|
||||
struct virtio_gpu_simple_resource *res;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||
/* FIXME: should take scanout.r.{x,y} into account */
|
||||
scanout = &g->parent_obj.scanout[i];
|
||||
|
@ -1475,6 +1562,32 @@ virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
|
|||
}
|
||||
}
|
||||
|
||||
static bool virtio_gpu_blob_state_needed(void *opaque)
|
||||
{
|
||||
VirtIOGPU *g = VIRTIO_GPU(opaque);
|
||||
|
||||
return virtio_gpu_blob_enabled(g->parent_obj.conf);
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_virtio_gpu_blob_state = {
|
||||
.name = "virtio-gpu/blob",
|
||||
.minimum_version_id = VIRTIO_GPU_VM_VERSION,
|
||||
.version_id = VIRTIO_GPU_VM_VERSION,
|
||||
.needed = virtio_gpu_blob_state_needed,
|
||||
.fields = (const VMStateField[]){
|
||||
{
|
||||
.name = "virtio-gpu/blob",
|
||||
.info = &(const VMStateInfo) {
|
||||
.name = "blob",
|
||||
.get = virtio_gpu_blob_load,
|
||||
.put = virtio_gpu_blob_save,
|
||||
},
|
||||
.flags = VMS_SINGLE,
|
||||
} /* device */,
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* For historical reasons virtio_gpu does not adhere to virtio migration
|
||||
* scheme as described in doc/virtio-migration.txt, in a sense that no
|
||||
|
@ -1500,6 +1613,11 @@ static const VMStateDescription vmstate_virtio_gpu = {
|
|||
} /* device */,
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription * []) {
|
||||
&vmstate_virtio_gpu_blob_state,
|
||||
NULL
|
||||
},
|
||||
.post_load = virtio_gpu_post_load,
|
||||
};
|
||||
|
||||
static Property virtio_gpu_properties[] = {
|
||||
|
|
Loading…
Reference in New Issue