>From fb818f1060e57dac6793187a70a79801a7c17e50 Mon Sep 17 00:00:00 2001 From: Weidong Han Date: Thu, 27 Aug 2009 16:51:01 +0800 Subject: [PATCH] qemu gfx passthrough support support basic gfx passthrough: - disable emulated VGA adpater if there is passthroughed gfx - register/unregister legacy VGA I/O ports and MMIOs for passthroughed gfx Signed-off-by: Ben Lin Signed-off-by: Weidong Han --- hw/pass-through.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pass-through.h | 6 +++++ hw/pc.c | 51 ++++++++++++++++++++++++------------------ vl.c | 32 +++++++++++++++++++++++--- 4 files changed, 126 insertions(+), 26 deletions(-) diff --git a/hw/pass-through.c b/hw/pass-through.c index 8d80755..4a9e03a 100644 --- a/hw/pass-through.c +++ b/hw/pass-through.c @@ -93,6 +93,8 @@ #include #include +extern int gfx_passthru; + struct php_dev { struct pt_dev *pt_dev; uint8_t valid; @@ -1781,12 +1783,57 @@ static int pt_dev_is_virtfn(struct pci_dev *dev) return rc; } +/* + * register VGA resources for the domain with assigned gfx + */ +static int register_vga_regions(struct pt_dev *real_device) +{ + int ret = 0; + + ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3B0, + 0x3B0, 0xC, DPCI_ADD_MAPPING); + + ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3C0, + 0x3C0, 0x20, DPCI_ADD_MAPPING); + + ret |= xc_domain_memory_mapping(xc_handle, domid, + 0xa0000 >> XC_PAGE_SHIFT, + 0xa0000 >> XC_PAGE_SHIFT, + 0x20, + DPCI_ADD_MAPPING); + + return ret; +} + +/* + * unregister VGA resources for the domain with assigned gfx + */ +static int unregister_vga_regions(struct pt_dev *real_device) +{ + int ret = 0; + + ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3B0, + 0x3B0, 0xC, DPCI_REMOVE_MAPPING); + + ret |= xc_domain_ioport_mapping(xc_handle, domid, 0x3C0, + 0x3C0, 0x20, DPCI_REMOVE_MAPPING); + + ret |= xc_domain_memory_mapping(xc_handle, domid, + 0xa0000 >> XC_PAGE_SHIFT, + 0xa0000 >> XC_PAGE_SHIFT, + 0x20, + DPCI_REMOVE_MAPPING); + + return ret; +} + static int pt_register_regions(struct pt_dev *assigned_device) { int i = 0; uint32_t bar_data = 0; struct pci_dev *pci_dev = assigned_device->pci_dev; PCIDevice *d = &assigned_device->dev; + int ret; /* Register PIO/MMIO BARs */ for ( i = 0; i < PCI_BAR_ENTRIES; i++ ) @@ -1842,6 +1889,16 @@ static int pt_register_regions(struct pt_dev *assigned_device) (uint32_t)(pci_dev->rom_size), (uint32_t)(pci_dev->rom_base_addr)); } + if ( gfx_passthru && (pci_dev->device_class == 0x0300) ) + { + ret = register_vga_regions(assigned_device); + if ( ret != 0 ) + { + PT_LOG("VGA region mapping failed\n"); + return ret; + } + } + return 0; } @@ -1891,6 +1948,12 @@ static void pt_unregister_regions(struct pt_dev *assigned_device) } + if ( gfx_passthru && (assigned_device->pci_dev->device_class == 0x0300) ) + { + ret = unregister_vga_regions(assigned_device); + if ( ret != 0 ) + PT_LOG("VGA region unmapping failed\n"); + } } static uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap) diff --git a/hw/pass-through.h b/hw/pass-through.h index 028a03e..956e228 100644 --- a/hw/pass-through.h +++ b/hw/pass-through.h @@ -142,6 +142,12 @@ enum { GRP_TYPE_EMU, /* emul reg group */ }; +enum { + GFX_NO_PASSTHRU = 0, /* No gfx pass-through */ + GFX_IGD_PASSTHRU, /* IGD pass-through */ + GFX_DISCRETE_PASSTHRU, /* Discrete gfx pass-through */ +}; + #define PT_GET_EMUL_SIZE(flag, r_size) do { \ if (flag == PT_BAR_FLAG_MEM) {\ r_size = (((r_size) + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1)); \ diff --git a/hw/pc.c b/hw/pc.c index 129e9d9..53b59c0 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -41,6 +41,7 @@ #include "virtio-balloon.h" #include "virtio-console.h" #include "hpet_emul.h" +#include "pass-through.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS @@ -65,6 +66,8 @@ void tpm_tis_init(SetIRQFunc *set_irq, void *opaque, int irq); extern uint8_t *acpi_tables; extern size_t acpi_tables_len; +extern int gfx_passthru; + static fdctrl_t *floppy_controller; static RTCState *rtc_state; static PITState *pit; @@ -983,30 +986,34 @@ vga_bios_error: register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); - if (cirrus_vga_enabled) { - if (pci_enabled) { - pci_cirrus_vga_init(pci_bus, - phys_ram_base + vga_ram_addr, - vga_ram_addr, vga_ram_size); - } else { - isa_cirrus_vga_init(phys_ram_base + vga_ram_addr, - vga_ram_addr, vga_ram_size); - } + if (gfx_passthru == GFX_NO_PASSTHRU) { + if (cirrus_vga_enabled) { + fprintf(logfile,"cirrus_vga_enabled\n"); + if (pci_enabled) { + pci_cirrus_vga_init(pci_bus, + phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); + } else { + isa_cirrus_vga_init(phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); + } #ifndef CONFIG_DM - } else if (vmsvga_enabled) { - if (pci_enabled) - pci_vmsvga_init(pci_bus, phys_ram_base + vga_ram_addr, - vga_ram_addr, vga_ram_size); - else - fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); + } else if (vmsvga_enabled) { + if (pci_enabled) + pci_vmsvga_init(pci_bus, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); + else + fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); #endif - } else if (std_vga_enabled) { - if (pci_enabled) { - pci_vga_init(pci_bus, phys_ram_base + vga_ram_addr, - vga_ram_addr, vga_ram_size, 0, 0); - } else { - isa_vga_init(phys_ram_base + vga_ram_addr, - vga_ram_addr, vga_ram_size); + } else if (std_vga_enabled) { + fprintf(logfile,"std_vga_enabled\n"); + if (pci_enabled) { + pci_vga_init(pci_bus, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size, 0, 0); + } else { + isa_vga_init(phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); + } } } diff --git a/vl.c b/vl.c index 62bed05..72f3479 100644 --- a/vl.c +++ b/vl.c @@ -48,6 +48,7 @@ #include #include "qemu-xen.h" +#include "hw/pass-through.h" #include #include @@ -213,6 +214,7 @@ static int rtc_date_offset = -1; /* -1 means no change */ int cirrus_vga_enabled = 1; int std_vga_enabled = 0; int vmsvga_enabled = 0; +int gfx_passthru = 0; #ifdef TARGET_SPARC int graphic_width = 1024; int graphic_height = 768; @@ -4269,6 +4271,7 @@ enum { /* Xen tree: */ QEMU_OPTION_disable_opengl, QEMU_OPTION_direct_pci, + QEMU_OPTION_gfx_passthru, QEMU_OPTION_pci_emulation, QEMU_OPTION_vncunused, QEMU_OPTION_videoram, @@ -4447,6 +4450,7 @@ static const QEMUOption qemu_options[] = { #endif { "acpi", 0, QEMU_OPTION_acpi }, /* deprecated, for xend compatibility */ { "direct_pci", HAS_ARG, QEMU_OPTION_direct_pci }, + { "gfx_passthru", HAS_ARG, QEMU_OPTION_gfx_passthru}, { "pciemulation", HAS_ARG, QEMU_OPTION_pci_emulation }, { "vncunused", 0, QEMU_OPTION_vncunused }, { "vcpus", HAS_ARG, QEMU_OPTION_vcpus }, @@ -5484,6 +5488,22 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_runas: run_as = optarg; break; + case QEMU_OPTION_gfx_passthru: + gfx_passthru = atoi(optarg); + switch (gfx_passthru) { + case GFX_NO_PASSTHRU: + break; + case GFX_IGD_PASSTHRU: + fprintf(logfile, "IGD graphics card assignment\n"); + break; + case GFX_DISCRETE_PASSTHRU: + fprintf(logfile, "Discrete graphics card assignment\n"); + break; + default: + fprintf(stderr, "unsupported gfx_passthru option: %d\n", + gfx_passthru); + } + break; } } } @@ -5897,13 +5917,17 @@ int main(int argc, char **argv, char **envp) exit(1); xenstore_write_vncport(vnc_display_port); } + + if (gfx_passthru == GFX_NO_PASSTHRU) + { #if defined(CONFIG_SDL) - if (sdl || !vnc_display) - sdl_display_init(ds, full_screen, no_frame, opengl_enabled); + if (sdl || !vnc_display) + sdl_display_init(ds, full_screen, no_frame, opengl_enabled); #elif defined(CONFIG_COCOA) - if (sdl || !vnc_display) - cocoa_display_init(ds, full_screen); + if (sdl || !vnc_display) + cocoa_display_init(ds, full_screen); #endif + } } } dpy_resize(ds); -- 1.6.0.4