--- tools/ioemu-remote/hw/pass-through.c.org 2010-05-10 15:24:52.115083489 +0200 +++ tools/ioemu-remote/hw/pass-through.c 2010-05-10 16:02:19.517997970 +0200 @@ -1865,6 +1865,75 @@ return rc; } +#define PCI_HEADER_TYPE_ADDR 0x0e +#define PCI_BRIDGE_FLAG 0x01 + +#define PCI_CLASS_CODE_ADDR_0 0x09 +#define PCI_CLASS_CODE_ADDR_1 0x0a +#define PCI_CLASS_CODE_ADDR_2 0x0b +#define PCI_CLASS_CODE_DATA_0 0x060000 +#define PCI_CLASS_CODE_DATA_1 0x0600 +#define PCI_CLASS_CODE_DATA_2 0x06 + +#define PCI_SECOND_BUS_NUMBER_ADDR 0x19 + +#define PCI_BRIDGE_CONTROL_ADDR 0x3e +#define PCI_BRIDGE_VGA_ENABLE 0x18 + +#define PCI_GRAPHIC_CONTROL_ADDR 0x52 +#define PCI_HOST_BRIDGE_IGD_VGA_DISABLE 0x02 + +/* + * Claim vga cycle for the graphics card pass-through + */ +static uint32_t gfx_claim_vga_cycle(struct pci_access *pci_access, + uint32_t bus, uint32_t devfn, uint32_t func) +{ + struct pci_dev *pci_dev; + + for ( pci_dev = pci_access->devices; pci_dev != NULL; pci_dev = pci_dev->next ) + { + /* Check whether this is a ordinary bridge */ + if ( pci_read_byte(pci_dev, PCI_HEADER_TYPE_ADDR) == PCI_BRIDGE_FLAG ) + { + unsigned sec_bus_num = pci_read_byte(pci_dev, PCI_SECOND_BUS_NUMBER_ADDR); + unsigned ubrg = pci_read_byte(pci_dev, PCI_BRIDGE_CONTROL_ADDR); + + PT_LOG("bridge for bus %d, previous bridge control is %x\n", sec_bus_num, ubrg); + PT_LOG("bus=0x%d, dev=0x%x, func=0x%x\n",pci_dev->bus,pci_dev->dev,pci_dev->func); + + if ( sec_bus_num == bus ) /* VGA device's bridge */ + ubrg |= PCI_BRIDGE_VGA_ENABLE; + else /* Other device's bridge */ + ubrg &= ~PCI_BRIDGE_VGA_ENABLE; + + pci_write_byte(pci_dev, PCI_BRIDGE_CONTROL_ADDR, ubrg); + PT_LOG("bridge for bus %d, updated bridge control is %x\n", sec_bus_num, ubrg); + } + } + + for ( pci_dev = pci_access->devices; pci_dev != NULL; pci_dev = pci_dev->next ) + { + /* Check host bridge */ + if ( pci_read_word(pci_dev, PCI_CLASS_CODE_ADDR_1) == PCI_CLASS_CODE_DATA_1 ) + { + unsigned uigd = pci_read_byte(pci_dev, PCI_GRAPHIC_CONTROL_ADDR); + + PT_LOG("previous igd control is %x\n", uigd); + + if ( bus == 0 ) + uigd &= ~PCI_HOST_BRIDGE_IGD_VGA_DISABLE; + else + uigd |= PCI_HOST_BRIDGE_IGD_VGA_DISABLE; + + pci_write_byte(pci_dev, PCI_GRAPHIC_CONTROL_ADDR, uigd); + PT_LOG("updated igd control is %x\n", uigd); + } + } + + return 0; +} + /* * register VGA resources for the domain with assigned gfx */ @@ -3298,6 +3367,8 @@ } /* read BAR */ +static int gfx_first_read_BAR[7] = {1, 1, 1, 1, 1, 1, 1}; + static int pt_bar_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t valid_mask) @@ -3320,6 +3391,17 @@ /* use fixed-up value from kernel sysfs */ *value = ptdev->pci_dev->base_addr[index]; + if ( ptdev->pci_dev->device_class == 0x300 ) + { + if ( gfx_first_read_BAR[index] == 1 ) + { + gfx_first_read_BAR[index] = 0; + PT_LOG("first read BARs of gfx\n"); + return 0; + } + } + + /* set emulate mask depend on BAR flag */ switch (ptdev->bases[index].bar_flag) { @@ -4397,6 +4479,13 @@ } } + if ( pci_dev->device_class == 0x0300 ) + { + rc = gfx_claim_vga_cycle(pci_access, r_bus, r_dev, r_func); + if ( rc != 0 ) + return NULL; + } + /* reinitialize each config register to be emulated */ rc = pt_config_init(assigned_device); if ( rc < 0 ) {