mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -06:00
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
7 changed files with 250 additions and 67 deletions
|
@ -319,11 +319,13 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
case DAC_CNTL:
|
case DAC_CNTL:
|
||||||
val = s->regs.dac_cntl;
|
val = s->regs.dac_cntl;
|
||||||
break;
|
break;
|
||||||
case GPIO_VGA_DDC:
|
case GPIO_VGA_DDC ... GPIO_VGA_DDC + 3:
|
||||||
val = s->regs.gpio_vga_ddc;
|
val = ati_reg_read_offs(s->regs.gpio_vga_ddc,
|
||||||
|
addr - GPIO_VGA_DDC, size);
|
||||||
break;
|
break;
|
||||||
case GPIO_DVI_DDC:
|
case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3:
|
||||||
val = s->regs.gpio_dvi_ddc;
|
val = ati_reg_read_offs(s->regs.gpio_dvi_ddc,
|
||||||
|
addr - GPIO_DVI_DDC, size);
|
||||||
break;
|
break;
|
||||||
case GPIO_MONID ... GPIO_MONID + 3:
|
case GPIO_MONID ... GPIO_MONID + 3:
|
||||||
val = ati_reg_read_offs(s->regs.gpio_monid,
|
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:
|
case PALETTE_DATA:
|
||||||
val = vga_ioport_read(&s->vga, VGA_PEL_D);
|
val = vga_ioport_read(&s->vga, VGA_PEL_D);
|
||||||
break;
|
break;
|
||||||
|
case PALETTE_30_DATA:
|
||||||
|
val = s->regs.palette[vga_ioport_read(&s->vga, VGA_PEL_IR)];
|
||||||
|
break;
|
||||||
case CNFG_CNTL:
|
case CNFG_CNTL:
|
||||||
val = s->regs.config_cntl;
|
val = s->regs.config_cntl;
|
||||||
break;
|
break;
|
||||||
|
@ -349,14 +354,17 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
PCI_BASE_ADDRESS_0, size) & 0xfffffff0;
|
PCI_BASE_ADDRESS_0, size) & 0xfffffff0;
|
||||||
break;
|
break;
|
||||||
case CONFIG_APER_SIZE:
|
case CONFIG_APER_SIZE:
|
||||||
val = s->vga.vram_size;
|
val = s->vga.vram_size / 2;
|
||||||
break;
|
break;
|
||||||
case CONFIG_REG_1_BASE:
|
case CONFIG_REG_1_BASE:
|
||||||
val = pci_default_read_config(&s->dev,
|
val = pci_default_read_config(&s->dev,
|
||||||
PCI_BASE_ADDRESS_2, size) & 0xfffffff0;
|
PCI_BASE_ADDRESS_2, size) & 0xfffffff0;
|
||||||
break;
|
break;
|
||||||
case CONFIG_REG_APER_SIZE:
|
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;
|
break;
|
||||||
case MC_STATUS:
|
case MC_STATUS:
|
||||||
val = 5;
|
val = 5;
|
||||||
|
@ -612,29 +620,34 @@ static void ati_mm_write(void *opaque, hwaddr addr,
|
||||||
s->regs.dac_cntl = data & 0xffffe3ff;
|
s->regs.dac_cntl = data & 0xffffe3ff;
|
||||||
s->vga.dac_8bit = !!(data & DAC_8BIT_EN);
|
s->vga.dac_8bit = !!(data & DAC_8BIT_EN);
|
||||||
break;
|
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) {
|
if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
|
||||||
/* FIXME: Maybe add a property to select VGA or DVI port? */
|
/* FIXME: Maybe add a property to select VGA or DVI port? */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GPIO_DVI_DDC:
|
case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3:
|
||||||
if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
|
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;
|
break;
|
||||||
case GPIO_MONID ... GPIO_MONID + 3:
|
case GPIO_MONID ... GPIO_MONID + 3:
|
||||||
/* FIXME What does Radeon have here? */
|
/* FIXME What does Radeon have here? */
|
||||||
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
|
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,
|
ati_reg_write_offs(&s->regs.gpio_monid,
|
||||||
addr - GPIO_MONID, data, size);
|
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)) &&
|
if ((s->regs.gpio_monid & BIT(25)) &&
|
||||||
((addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) ||
|
((addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) ||
|
||||||
(addr == GPIO_MONID && (s->regs.gpio_monid & 0x60000)))) {
|
(addr == GPIO_MONID && (s->regs.gpio_monid & 0x60000)))) {
|
||||||
|
@ -663,6 +676,12 @@ static void ati_mm_write(void *opaque, hwaddr addr,
|
||||||
data >>= 8;
|
data >>= 8;
|
||||||
vga_ioport_write(&s->vga, VGA_PEL_D, data & 0xff);
|
vga_ioport_write(&s->vga, VGA_PEL_D, data & 0xff);
|
||||||
break;
|
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:
|
case CNFG_CNTL:
|
||||||
s->regs.config_cntl = data;
|
s->regs.config_cntl = data;
|
||||||
break;
|
break;
|
||||||
|
@ -1014,6 +1033,7 @@ static Property ati_vga_properties[] = {
|
||||||
DEFINE_PROP_UINT16("x-device-id", ATIVGAState, dev_id,
|
DEFINE_PROP_UINT16("x-device-id", ATIVGAState, dev_id,
|
||||||
PCI_DEVICE_ID_ATI_RAGE128_PF),
|
PCI_DEVICE_ID_ATI_RAGE128_PF),
|
||||||
DEFINE_PROP_BOOL("guest_hwcursor", ATIVGAState, cursor_guest_mode, false),
|
DEFINE_PROP_BOOL("guest_hwcursor", ATIVGAState, cursor_guest_mode, false),
|
||||||
|
DEFINE_PROP_UINT8("x-pixman", ATIVGAState, use_pixman, 3),
|
||||||
DEFINE_PROP_END_OF_LIST()
|
DEFINE_PROP_END_OF_LIST()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1035,11 +1055,18 @@ static void ati_vga_class_init(ObjectClass *klass, void *data)
|
||||||
k->exit = ati_vga_exit;
|
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 = {
|
static const TypeInfo ati_vga_info = {
|
||||||
.name = TYPE_ATI_VGA,
|
.name = TYPE_ATI_VGA,
|
||||||
.parent = TYPE_PCI_DEVICE,
|
.parent = TYPE_PCI_DEVICE,
|
||||||
.instance_size = sizeof(ATIVGAState),
|
.instance_size = sizeof(ATIVGAState),
|
||||||
.class_init = ati_vga_class_init,
|
.class_init = ati_vga_class_init,
|
||||||
|
.instance_init = ati_vga_init,
|
||||||
.interfaces = (InterfaceInfo[]) {
|
.interfaces = (InterfaceInfo[]) {
|
||||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||||
{ },
|
{ },
|
||||||
|
|
|
@ -92,6 +92,7 @@ void ati_2d_blt(ATIVGAState *s)
|
||||||
switch (s->regs.dp_mix & GMC_ROP3_MASK) {
|
switch (s->regs.dp_mix & GMC_ROP3_MASK) {
|
||||||
case ROP3_SRCCOPY:
|
case ROP3_SRCCOPY:
|
||||||
{
|
{
|
||||||
|
bool fallback = false;
|
||||||
unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
|
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);
|
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 ?
|
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_bits, dst_bits, src_stride, dst_stride, bpp, bpp,
|
||||||
src_x, src_y, dst_x, dst_y,
|
src_x, src_y, dst_x, dst_y,
|
||||||
s->regs.dst_width, s->regs.dst_height);
|
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) {
|
s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM) {
|
||||||
pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
|
fallback = !pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits,
|
||||||
src_stride, dst_stride, bpp, bpp,
|
src_stride, dst_stride, bpp, bpp,
|
||||||
src_x, src_y, dst_x, dst_y,
|
src_x, src_y, dst_x, dst_y,
|
||||||
s->regs.dst_width, s->regs.dst_height);
|
s->regs.dst_width, s->regs.dst_height);
|
||||||
} else {
|
} else if (s->use_pixman & BIT(1)) {
|
||||||
/* FIXME: We only really need a temporary if src and dst overlap */
|
/* FIXME: We only really need a temporary if src and dst overlap */
|
||||||
int llb = s->regs.dst_width * (bpp / 8);
|
int llb = s->regs.dst_width * (bpp / 8);
|
||||||
int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
|
int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
|
||||||
uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) *
|
uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) *
|
||||||
s->regs.dst_height);
|
s->regs.dst_height);
|
||||||
pixman_blt((uint32_t *)src_bits, tmp,
|
fallback = !pixman_blt((uint32_t *)src_bits, tmp,
|
||||||
src_stride, tmp_stride, bpp, bpp,
|
src_stride, tmp_stride, bpp, bpp,
|
||||||
src_x, src_y, 0, 0,
|
src_x, src_y, 0, 0,
|
||||||
s->regs.dst_width, s->regs.dst_height);
|
s->regs.dst_width, s->regs.dst_height);
|
||||||
pixman_blt(tmp, (uint32_t *)dst_bits,
|
if (!fallback) {
|
||||||
|
fallback = !pixman_blt(tmp, (uint32_t *)dst_bits,
|
||||||
tmp_stride, dst_stride, bpp, bpp,
|
tmp_stride, dst_stride, bpp, bpp,
|
||||||
0, 0, dst_x, dst_y,
|
0, 0, dst_x, dst_y,
|
||||||
s->regs.dst_width, s->regs.dst_height);
|
s->regs.dst_width, s->regs.dst_height);
|
||||||
|
}
|
||||||
g_free(tmp);
|
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 &&
|
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&
|
||||||
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);
|
dst_stride /= sizeof(uint32_t);
|
||||||
DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n",
|
DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n",
|
||||||
dst_bits, dst_stride, bpp,
|
dst_bits, dst_stride, bpp, dst_x, dst_y,
|
||||||
dst_x, dst_y,
|
s->regs.dst_width, s->regs.dst_height, filler);
|
||||||
s->regs.dst_width, s->regs.dst_height,
|
if (!(s->use_pixman & BIT(0)) ||
|
||||||
filler);
|
!pixman_fill((uint32_t *)dst_bits, dst_stride, bpp, dst_x, dst_y,
|
||||||
pixman_fill((uint32_t *)dst_bits, dst_stride, bpp,
|
s->regs.dst_width, s->regs.dst_height, filler)) {
|
||||||
dst_x, dst_y,
|
/* fallback when pixman failed or we don't want to call it */
|
||||||
s->regs.dst_width, s->regs.dst_height,
|
unsigned int x, y, i, bypp = bpp / 8;
|
||||||
filler);
|
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 &&
|
if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr &&
|
||||||
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) {
|
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},
|
{"AMCGPIO_EN_MIR", 0x00a8},
|
||||||
{"PALETTE_INDEX", 0x00b0},
|
{"PALETTE_INDEX", 0x00b0},
|
||||||
{"PALETTE_DATA", 0x00b4},
|
{"PALETTE_DATA", 0x00b4},
|
||||||
|
{"PALETTE_30_DATA", 0x00b8},
|
||||||
{"CNFG_CNTL", 0x00e0},
|
{"CNFG_CNTL", 0x00e0},
|
||||||
{"GEN_RESET_CNTL", 0x00f0},
|
{"GEN_RESET_CNTL", 0x00f0},
|
||||||
{"CNFG_MEMSIZE", 0x00f8},
|
{"CNFG_MEMSIZE", 0x00f8},
|
||||||
|
@ -38,6 +39,7 @@ static struct ati_regdesc ati_reg_names[] = {
|
||||||
{"CONFIG_APER_SIZE", 0x0108},
|
{"CONFIG_APER_SIZE", 0x0108},
|
||||||
{"CONFIG_REG_1_BASE", 0x010c},
|
{"CONFIG_REG_1_BASE", 0x010c},
|
||||||
{"CONFIG_REG_APER_SIZE", 0x0110},
|
{"CONFIG_REG_APER_SIZE", 0x0110},
|
||||||
|
{"HOST_PATH_CNTL", 0x0130},
|
||||||
{"MEM_CNTL", 0x0140},
|
{"MEM_CNTL", 0x0140},
|
||||||
{"MC_FB_LOCATION", 0x0148},
|
{"MC_FB_LOCATION", 0x0148},
|
||||||
{"MC_AGP_LOCATION", 0x014C},
|
{"MC_AGP_LOCATION", 0x014C},
|
||||||
|
|
|
@ -44,6 +44,7 @@ typedef struct ATIVGARegs {
|
||||||
uint32_t gpio_dvi_ddc;
|
uint32_t gpio_dvi_ddc;
|
||||||
uint32_t gpio_monid;
|
uint32_t gpio_monid;
|
||||||
uint32_t config_cntl;
|
uint32_t config_cntl;
|
||||||
|
uint32_t palette[256];
|
||||||
uint32_t crtc_h_total_disp;
|
uint32_t crtc_h_total_disp;
|
||||||
uint32_t crtc_h_sync_strt_wid;
|
uint32_t crtc_h_sync_strt_wid;
|
||||||
uint32_t crtc_v_total_disp;
|
uint32_t crtc_v_total_disp;
|
||||||
|
@ -89,6 +90,7 @@ struct ATIVGAState {
|
||||||
char *model;
|
char *model;
|
||||||
uint16_t dev_id;
|
uint16_t dev_id;
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
uint8_t use_pixman;
|
||||||
bool cursor_guest_mode;
|
bool cursor_guest_mode;
|
||||||
uint16_t cursor_size;
|
uint16_t cursor_size;
|
||||||
uint32_t cursor_offset;
|
uint32_t cursor_offset;
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#define AMCGPIO_EN_MIR 0x00a8
|
#define AMCGPIO_EN_MIR 0x00a8
|
||||||
#define PALETTE_INDEX 0x00b0
|
#define PALETTE_INDEX 0x00b0
|
||||||
#define PALETTE_DATA 0x00b4
|
#define PALETTE_DATA 0x00b4
|
||||||
|
#define PALETTE_30_DATA 0x00b8
|
||||||
#define CNFG_CNTL 0x00e0
|
#define CNFG_CNTL 0x00e0
|
||||||
#define GEN_RESET_CNTL 0x00f0
|
#define GEN_RESET_CNTL 0x00f0
|
||||||
#define CNFG_MEMSIZE 0x00f8
|
#define CNFG_MEMSIZE 0x00f8
|
||||||
|
@ -56,6 +57,7 @@
|
||||||
#define CONFIG_APER_SIZE 0x0108
|
#define CONFIG_APER_SIZE 0x0108
|
||||||
#define CONFIG_REG_1_BASE 0x010c
|
#define CONFIG_REG_1_BASE 0x010c
|
||||||
#define CONFIG_REG_APER_SIZE 0x0110
|
#define CONFIG_REG_APER_SIZE 0x0110
|
||||||
|
#define HOST_PATH_CNTL 0x0130
|
||||||
#define MEM_CNTL 0x0140
|
#define MEM_CNTL 0x0140
|
||||||
#define MC_FB_LOCATION 0x0148
|
#define MC_FB_LOCATION 0x0148
|
||||||
#define MC_AGP_LOCATION 0x014C
|
#define MC_AGP_LOCATION 0x014C
|
||||||
|
|
|
@ -36,6 +36,7 @@ static const TypeInfo virtio_gpu_rutabaga_pci_info[] = {
|
||||||
.instance_init = virtio_gpu_rutabaga_initfn,
|
.instance_init = virtio_gpu_rutabaga_initfn,
|
||||||
.interfaces = (InterfaceInfo[]) {
|
.interfaces = (InterfaceInfo[]) {
|
||||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
{ 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));
|
assert(QTAILQ_EMPTY(&g->cmdq));
|
||||||
|
|
||||||
QTAILQ_FOREACH(res, &g->reslist, next) {
|
QTAILQ_FOREACH(res, &g->reslist, next) {
|
||||||
|
if (res->blob_size) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
qemu_put_be32(f, res->resource_id);
|
qemu_put_be32(f, res->resource_id);
|
||||||
qemu_put_be32(f, res->width);
|
qemu_put_be32(f, res->width);
|
||||||
qemu_put_be32(f, res->height);
|
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);
|
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,
|
static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
|
||||||
const VMStateField *field)
|
const VMStateField *field)
|
||||||
{
|
{
|
||||||
VirtIOGPU *g = opaque;
|
VirtIOGPU *g = opaque;
|
||||||
struct virtio_gpu_simple_resource *res;
|
struct virtio_gpu_simple_resource *res;
|
||||||
struct virtio_gpu_scanout *scanout;
|
|
||||||
uint32_t resource_id, pformat;
|
uint32_t resource_id, pformat;
|
||||||
void *bits = NULL;
|
void *bits = NULL;
|
||||||
int i;
|
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),
|
qemu_get_buffer(f, (void *)pixman_image_get_data(res->image),
|
||||||
pixman_image_get_stride(res->image) * res->height);
|
pixman_image_get_stride(res->image) * res->height);
|
||||||
|
|
||||||
/* restore mapping */
|
if (!virtio_gpu_load_restore_mapping(g, res)) {
|
||||||
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);
|
pixman_image_unref(res->image);
|
||||||
g_free(res);
|
g_free(res);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
|
|
||||||
g->hostmem += res->hostmem;
|
|
||||||
|
|
||||||
resource_id = qemu_get_be32(f);
|
resource_id = qemu_get_be32(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* load & apply scanout state */
|
/* load & apply scanout state */
|
||||||
vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
|
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++) {
|
for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
|
||||||
/* FIXME: should take scanout.r.{x,y} into account */
|
/* FIXME: should take scanout.r.{x,y} into account */
|
||||||
scanout = &g->parent_obj.scanout[i];
|
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
|
* For historical reasons virtio_gpu does not adhere to virtio migration
|
||||||
* scheme as described in doc/virtio-migration.txt, in a sense that no
|
* scheme as described in doc/virtio-migration.txt, in a sense that no
|
||||||
|
@ -1500,6 +1613,11 @@ static const VMStateDescription vmstate_virtio_gpu = {
|
||||||
} /* device */,
|
} /* device */,
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
|
.subsections = (const VMStateDescription * []) {
|
||||||
|
&vmstate_virtio_gpu_blob_state,
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
.post_load = virtio_gpu_post_load,
|
||||||
};
|
};
|
||||||
|
|
||||||
static Property virtio_gpu_properties[] = {
|
static Property virtio_gpu_properties[] = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue