2
0
Эх сурвалжийг харах

Merge remote-tracking branch 'mst/for_anthony' into staging

Conflicts:
	hw/usb-uhci.c
Anthony Liguori 14 жил өмнө
parent
commit
fdba9594df

+ 33 - 6
exec.c

@@ -1753,14 +1753,21 @@ static int cpu_notify_migration_log(int enable)
     return 0;
     return 0;
 }
 }
 
 
+struct last_map {
+    target_phys_addr_t start_addr;
+    ram_addr_t size;
+    ram_addr_t phys_offset;
+};
+
 /* The l1_phys_map provides the upper P_L1_BITs of the guest physical
 /* The l1_phys_map provides the upper P_L1_BITs of the guest physical
  * address.  Each intermediate table provides the next L2_BITs of guest
  * address.  Each intermediate table provides the next L2_BITs of guest
  * physical address space.  The number of levels vary based on host and
  * physical address space.  The number of levels vary based on host and
  * guest configuration, making it efficient to build the final guest
  * guest configuration, making it efficient to build the final guest
  * physical address by seeding the L1 offset and shifting and adding in
  * physical address by seeding the L1 offset and shifting and adding in
  * each L2 offset as we recurse through them. */
  * each L2 offset as we recurse through them. */
-static void phys_page_for_each_1(CPUPhysMemoryClient *client,
-                                 int level, void **lp, target_phys_addr_t addr)
+static void phys_page_for_each_1(CPUPhysMemoryClient *client, int level,
+                                 void **lp, target_phys_addr_t addr,
+                                 struct last_map *map)
 {
 {
     int i;
     int i;
 
 
@@ -1772,15 +1779,29 @@ static void phys_page_for_each_1(CPUPhysMemoryClient *client,
         addr <<= L2_BITS + TARGET_PAGE_BITS;
         addr <<= L2_BITS + TARGET_PAGE_BITS;
         for (i = 0; i < L2_SIZE; ++i) {
         for (i = 0; i < L2_SIZE; ++i) {
             if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
             if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
-                client->set_memory(client, addr | i << TARGET_PAGE_BITS,
-                                   TARGET_PAGE_SIZE, pd[i].phys_offset, false);
+                target_phys_addr_t start_addr = addr | i << TARGET_PAGE_BITS;
+
+                if (map->size &&
+                    start_addr == map->start_addr + map->size &&
+                    pd[i].phys_offset == map->phys_offset + map->size) {
+
+                    map->size += TARGET_PAGE_SIZE;
+                    continue;
+                } else if (map->size) {
+                    client->set_memory(client, map->start_addr,
+                                       map->size, map->phys_offset, false);
+                }
+
+                map->start_addr = start_addr;
+                map->size = TARGET_PAGE_SIZE;
+                map->phys_offset = pd[i].phys_offset;
             }
             }
         }
         }
     } else {
     } else {
         void **pp = *lp;
         void **pp = *lp;
         for (i = 0; i < L2_SIZE; ++i) {
         for (i = 0; i < L2_SIZE; ++i) {
             phys_page_for_each_1(client, level - 1, pp + i,
             phys_page_for_each_1(client, level - 1, pp + i,
-                                 (addr << L2_BITS) | i);
+                                 (addr << L2_BITS) | i, map);
         }
         }
     }
     }
 }
 }
@@ -1788,9 +1809,15 @@ static void phys_page_for_each_1(CPUPhysMemoryClient *client,
 static void phys_page_for_each(CPUPhysMemoryClient *client)
 static void phys_page_for_each(CPUPhysMemoryClient *client)
 {
 {
     int i;
     int i;
+    struct last_map map = { };
+
     for (i = 0; i < P_L1_SIZE; ++i) {
     for (i = 0; i < P_L1_SIZE; ++i) {
         phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
         phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
-                             l1_phys_map + i, i);
+                             l1_phys_map + i, i, &map);
+    }
+    if (map.size) {
+        client->set_memory(client, map.start_addr, map.size, map.phys_offset,
+                           false);
     }
     }
 }
 }
 
 

+ 5 - 5
hw/9pfs/virtio-9p-device.c

@@ -142,11 +142,7 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev)
 
 
     vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
     vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
     vdev->nvectors = proxy->nvectors;
     vdev->nvectors = proxy->nvectors;
-    virtio_init_pci(proxy, vdev,
-                    PCI_VENDOR_ID_REDHAT_QUMRANET,
-                    0x1009,
-                    0x2,
-                    0x00);
+    virtio_init_pci(proxy, vdev);
     /* make the actual value visible */
     /* make the actual value visible */
     proxy->nvectors = vdev->nvectors;
     proxy->nvectors = vdev->nvectors;
     return 0;
     return 0;
@@ -156,6 +152,10 @@ static PCIDeviceInfo virtio_9p_info = {
     .qdev.name = "virtio-9p-pci",
     .qdev.name = "virtio-9p-pci",
     .qdev.size = sizeof(VirtIOPCIProxy),
     .qdev.size = sizeof(VirtIOPCIProxy),
     .init      = virtio_9p_init_pci,
     .init      = virtio_9p_init_pci,
+    .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+    .device_id = 0x1009,
+    .revision  = VIRTIO_PCI_ABI_VERSION,
+    .class_id  = 0x2,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
         DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
         DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
         DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),

+ 4 - 5
hw/ac97.c

@@ -1277,9 +1277,6 @@ static int ac97_initfn (PCIDevice *dev)
     AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
     AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
     uint8_t *c = s->dev.config;
     uint8_t *c = s->dev.config;
 
 
-    pci_config_set_vendor_id (c, PCI_VENDOR_ID_INTEL); /* ro */
-    pci_config_set_device_id (c, PCI_DEVICE_ID_INTEL_82801AA_5); /* ro */
-
     /* TODO: no need to override */
     /* TODO: no need to override */
     c[PCI_COMMAND] = 0x00;      /* pcicmd pci command rw, ro */
     c[PCI_COMMAND] = 0x00;      /* pcicmd pci command rw, ro */
     c[PCI_COMMAND + 1] = 0x00;
     c[PCI_COMMAND + 1] = 0x00;
@@ -1288,9 +1285,7 @@ static int ac97_initfn (PCIDevice *dev)
     c[PCI_STATUS] = PCI_STATUS_FAST_BACK;      /* pcists pci status rwc, ro */
     c[PCI_STATUS] = PCI_STATUS_FAST_BACK;      /* pcists pci status rwc, ro */
     c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
     c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
 
 
-    c[PCI_REVISION_ID] = 0x01;      /* rid revision ro */
     c[PCI_CLASS_PROG] = 0x00;      /* pi programming interface ro */
     c[PCI_CLASS_PROG] = 0x00;      /* pi programming interface ro */
-    pci_config_set_class (c, PCI_CLASS_MULTIMEDIA_AUDIO); /* ro */
 
 
     /* TODO set when bar is registered. no need to override. */
     /* TODO set when bar is registered. no need to override. */
     /* nabmar native audio mixer base address rw */
     /* nabmar native audio mixer base address rw */
@@ -1337,6 +1332,10 @@ static PCIDeviceInfo ac97_info = {
     .qdev.size    = sizeof (AC97LinkState),
     .qdev.size    = sizeof (AC97LinkState),
     .qdev.vmsd    = &vmstate_ac97,
     .qdev.vmsd    = &vmstate_ac97,
     .init         = ac97_initfn,
     .init         = ac97_initfn,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = PCI_DEVICE_ID_INTEL_82801AA_5,
+    .revision     = 0x01,
+    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
 };
 };
 
 
 static void ac97_register (void)
 static void ac97_register (void)

+ 4 - 4
hw/acpi_piix4.c

@@ -317,13 +317,9 @@ static int piix4_pm_initfn(PCIDevice *dev)
     uint8_t *pci_conf;
     uint8_t *pci_conf;
 
 
     pci_conf = s->dev.config;
     pci_conf = s->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3);
     pci_conf[0x06] = 0x80;
     pci_conf[0x06] = 0x80;
     pci_conf[0x07] = 0x02;
     pci_conf[0x07] = 0x02;
-    pci_conf[0x08] = 0x03; // revision number
     pci_conf[0x09] = 0x00;
     pci_conf[0x09] = 0x00;
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
     pci_conf[0x3d] = 0x01; // interrupt pin 1
     pci_conf[0x3d] = 0x01; // interrupt pin 1
 
 
     pci_conf[0x40] = 0x01; /* PM io base read only bit */
     pci_conf[0x40] = 0x01; /* PM io base read only bit */
@@ -394,6 +390,10 @@ static PCIDeviceInfo piix4_pm_info = {
     .no_hotplug         = 1,
     .no_hotplug         = 1,
     .init               = piix4_pm_initfn,
     .init               = piix4_pm_initfn,
     .config_write       = pm_write_config,
     .config_write       = pm_write_config,
+    .vendor_id          = PCI_VENDOR_ID_INTEL,
+    .device_id          = PCI_DEVICE_ID_INTEL_82371AB_3,
+    .revision           = 0x03,
+    .class_id           = PCI_CLASS_BRIDGE_OTHER,
     .qdev.props         = (Property[]) {
     .qdev.props         = (Property[]) {
         DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
         DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
         DEFINE_PROP_END_OF_LIST(),
         DEFINE_PROP_END_OF_LIST(),

+ 6 - 7
hw/apb_pci.c

@@ -304,9 +304,6 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
         return rc;
         return rc;
     }
     }
 
 
-    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN);
-    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA);
-
     /*
     /*
      * command register:
      * command register:
      * According to PCI bridge spec, after reset
      * According to PCI bridge spec, after reset
@@ -321,7 +318,6 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
     pci_set_word(dev->config + PCI_STATUS,
     pci_set_word(dev->config + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
                  PCI_STATUS_DEVSEL_MEDIUM);
                  PCI_STATUS_DEVSEL_MEDIUM);
-    pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
     return 0;
     return 0;
 }
 }
 
 
@@ -436,14 +432,11 @@ static int pci_pbm_init_device(SysBusDevice *dev)
 
 
 static int pbm_pci_host_init(PCIDevice *d)
 static int pbm_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
     pci_set_word(d->config + PCI_COMMAND,
     pci_set_word(d->config + PCI_COMMAND,
                  PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
                  PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
     pci_set_word(d->config + PCI_STATUS,
     pci_set_word(d->config + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
                  PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
                  PCI_STATUS_DEVSEL_MEDIUM);
                  PCI_STATUS_DEVSEL_MEDIUM);
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     return 0;
     return 0;
 }
 }
 
 
@@ -451,6 +444,9 @@ static PCIDeviceInfo pbm_pci_host_info = {
     .qdev.name = "pbm",
     .qdev.name = "pbm",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = pbm_pci_host_init,
     .init      = pbm_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_SABRE,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
     .is_bridge = 1,
     .is_bridge = 1,
 };
 };
 
 
@@ -468,6 +464,9 @@ static PCIDeviceInfo pbm_pci_bridge_info = {
     .qdev.reset = pci_bridge_reset,
     .qdev.reset = pci_bridge_reset,
     .init = apb_pci_bridge_initfn,
     .init = apb_pci_bridge_initfn,
     .exit = pci_bridge_exitfn,
     .exit = pci_bridge_exitfn,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_SIMBA,
+    .revision = 0x11,
     .config_write = pci_bridge_write_config,
     .config_write = pci_bridge_write_config,
     .is_bridge = 1,
     .is_bridge = 1,
 };
 };

+ 5 - 4
hw/bonito.c

@@ -691,11 +691,7 @@ static int bonito_initfn(PCIDevice *dev)
     PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
     PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
 
 
     /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
     /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
-    pci_config_set_vendor_id(dev->config, 0xdf53);
-    pci_config_set_device_id(dev->config, 0x00d5);
-    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
     pci_config_set_prog_interface(dev->config, 0x00);
     pci_config_set_prog_interface(dev->config, 0x00);
-    pci_config_set_revision(dev->config, 0x01);
 
 
     /* set the north bridge register mapping */
     /* set the north bridge register mapping */
     s->bonito_reg_handle = cpu_register_io_memory(bonito_read, bonito_write, s,
     s->bonito_reg_handle = cpu_register_io_memory(bonito_read, bonito_write, s,
@@ -796,6 +792,11 @@ static PCIDeviceInfo bonito_info = {
     .qdev.vmsd    = &vmstate_bonito,
     .qdev.vmsd    = &vmstate_bonito,
     .qdev.no_user = 1,
     .qdev.no_user = 1,
     .init         = bonito_initfn,
     .init         = bonito_initfn,
+    /*Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined"*/
+    .vendor_id    = 0xdf53,
+    .device_id    = 0x00d5,
+    .revision     = 0x01,
+    .class_id     = PCI_CLASS_BRIDGE_HOST,
 };
 };
 
 
 static SysBusDeviceInfo bonito_pcihost_info = {
 static SysBusDeviceInfo bonito_pcihost_info = {

+ 5 - 5
hw/cirrus_vga.c

@@ -3100,8 +3100,8 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
 {
 {
      PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
      PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
      CirrusVGAState *s = &d->cirrus_vga;
      CirrusVGAState *s = &d->cirrus_vga;
-     uint8_t *pci_conf = d->dev.config;
-     int device_id = CIRRUS_ID_CLGD5446;
+     PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
+     int16_t device_id = info->device_id;
 
 
      /* setup VGA */
      /* setup VGA */
      vga_common_init(&s->vga, VGA_RAM_SIZE);
      vga_common_init(&s->vga, VGA_RAM_SIZE);
@@ -3111,9 +3111,6 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
                                       &s->vga);
                                       &s->vga);
 
 
      /* setup PCI */
      /* setup PCI */
-     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CIRRUS);
-     pci_config_set_device_id(pci_conf, device_id);
-     pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
 
 
      /* setup memory space */
      /* setup memory space */
      /* memory #0 LFB */
      /* memory #0 LFB */
@@ -3142,6 +3139,9 @@ static PCIDeviceInfo cirrus_vga_info = {
     .init         = pci_cirrus_vga_initfn,
     .init         = pci_cirrus_vga_initfn,
     .romfile      = VGABIOS_CIRRUS_FILENAME,
     .romfile      = VGABIOS_CIRRUS_FILENAME,
     .config_write = pci_cirrus_write_config,
     .config_write = pci_cirrus_write_config,
+    .vendor_id    = PCI_VENDOR_ID_CIRRUS,
+    .device_id    = CIRRUS_ID_CLGD5446,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
 };
 };
 
 
 static void cirrus_vga_register(void)
 static void cirrus_vga_register(void)

+ 7 - 19
hw/dec_pci.c

@@ -50,28 +50,16 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
     return irq_num;
     return irq_num;
 }
 }
 
 
-static int dec_21154_initfn(PCIDevice *dev)
-{
-    int rc;
-
-    rc = pci_bridge_initfn(dev);
-    if (rc < 0) {
-        return rc;
-    }
-
-    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_DEC);
-    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_DEC_21154);
-    return 0;
-}
-
 static PCIDeviceInfo dec_21154_pci_bridge_info = {
 static PCIDeviceInfo dec_21154_pci_bridge_info = {
     .qdev.name = "dec-21154-p2p-bridge",
     .qdev.name = "dec-21154-p2p-bridge",
     .qdev.desc = "DEC 21154 PCI-PCI bridge",
     .qdev.desc = "DEC 21154 PCI-PCI bridge",
     .qdev.size = sizeof(PCIBridge),
     .qdev.size = sizeof(PCIBridge),
     .qdev.vmsd = &vmstate_pci_device,
     .qdev.vmsd = &vmstate_pci_device,
     .qdev.reset = pci_bridge_reset,
     .qdev.reset = pci_bridge_reset,
-    .init = dec_21154_initfn,
+    .init = pci_bridge_initfn,
     .exit = pci_bridge_exitfn,
     .exit = pci_bridge_exitfn,
+    .vendor_id = PCI_VENDOR_ID_DEC,
+    .device_id = PCI_DEVICE_ID_DEC_21154,
     .config_write = pci_bridge_write_config,
     .config_write = pci_bridge_write_config,
     .is_bridge = 1,
     .is_bridge = 1,
 };
 };
@@ -108,10 +96,6 @@ static int pci_dec_21154_init_device(SysBusDevice *dev)
 static int dec_21154_pci_host_init(PCIDevice *d)
 static int dec_21154_pci_host_init(PCIDevice *d)
 {
 {
     /* PCI2PCI bridge same values as PearPC - check this */
     /* PCI2PCI bridge same values as PearPC - check this */
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_DEC);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154);
-    pci_set_byte(d->config + PCI_REVISION_ID, 0x02);
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
     return 0;
     return 0;
 }
 }
 
 
@@ -119,6 +103,10 @@ static PCIDeviceInfo dec_21154_pci_host_info = {
     .qdev.name = "dec-21154",
     .qdev.name = "dec-21154",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = dec_21154_pci_host_init,
     .init      = dec_21154_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_DEC,
+    .device_id = PCI_DEVICE_ID_DEC_21154,
+    .revision = 0x02,
+    .class_id = PCI_CLASS_BRIDGE_PCI,
     .is_bridge  = 1,
     .is_bridge  = 1,
 };
 };
 
 

+ 4 - 4
hw/e1000.c

@@ -1164,12 +1164,8 @@ static int pci_e1000_init(PCIDevice *pci_dev)
 
 
     pci_conf = d->dev.config;
     pci_conf = d->dev.config;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, E1000_DEVID);
     /* TODO: we have no capabilities, so why is this bit set? */
     /* TODO: we have no capabilities, so why is this bit set? */
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
-    pci_conf[PCI_REVISION_ID] = 0x03;
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
 
 
@@ -1221,6 +1217,10 @@ static PCIDeviceInfo e1000_info = {
     .init       = pci_e1000_init,
     .init       = pci_e1000_init,
     .exit       = pci_e1000_uninit,
     .exit       = pci_e1000_uninit,
     .romfile    = "pxe-e1000.rom",
     .romfile    = "pxe-e1000.rom",
+    .vendor_id  = PCI_VENDOR_ID_INTEL,
+    .device_id  = E1000_DEVID,
+    .revision   = 0x03,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(E1000State, conf),
         DEFINE_NIC_PROPERTIES(E1000State, conf),
         DEFINE_PROP_END_OF_LIST(),
         DEFINE_PROP_END_OF_LIST(),

+ 33 - 41
hw/eepro100.c

@@ -129,8 +129,6 @@
 typedef struct {
 typedef struct {
     PCIDeviceInfo pci;
     PCIDeviceInfo pci;
     uint32_t device;
     uint32_t device;
-    uint16_t device_id;
-    uint8_t revision;
     uint8_t stats_size;
     uint8_t stats_size;
     bool has_extended_tcb_support;
     bool has_extended_tcb_support;
     bool power_management;
     bool power_management;
@@ -526,16 +524,9 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
 
 
     TRACE(OTHER, logout("%p\n", s));
     TRACE(OTHER, logout("%p\n", s));
 
 
-    /* PCI Vendor ID */
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    /* PCI Device ID */
-    pci_config_set_device_id(pci_conf, e100_device->device_id);
     /* PCI Status */
     /* PCI Status */
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
                                         PCI_STATUS_FAST_BACK);
                                         PCI_STATUS_FAST_BACK);
-    /* PCI Revision ID */
-    pci_config_set_revision(pci_conf, e100_device->revision);
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
     /* PCI Latency Timer */
     /* PCI Latency Timer */
     pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20);   /* latency timer = 32 clocks */
     pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20);   /* latency timer = 32 clocks */
     /* Capability Pointer is set by PCI framework. */
     /* Capability Pointer is set by PCI framework. */
@@ -563,12 +554,7 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
     case i82559ER:
     case i82559ER:
     case i82562:
     case i82562:
     case i82801:
     case i82801:
-        break;
     case i82559C:
     case i82559C:
-#if EEPROM_SIZE > 0
-        pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_INTEL);
-        pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0040);
-#endif
         break;
         break;
     default:
     default:
         logout("Device %X is undefined!\n", device);
         logout("Device %X is undefined!\n", device);
@@ -2040,9 +2026,9 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.desc = "Intel i82550 Ethernet",
         .pci.qdev.desc = "Intel i82550 Ethernet",
         .device = i82550,
         .device = i82550,
         /* TODO: check device id. */
         /* TODO: check device id. */
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* Revision ID: 0x0c, 0x0d, 0x0e. */
         /* Revision ID: 0x0c, 0x0d, 0x0e. */
-        .revision = 0x0e,
+        .pci.revision = 0x0e,
         /* TODO: check size of statistical counters. */
         /* TODO: check size of statistical counters. */
         .stats_size = 80,
         .stats_size = 80,
         /* TODO: check extended tcb support. */
         /* TODO: check extended tcb support. */
@@ -2052,9 +2038,9 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82551",
         .pci.qdev.name = "i82551",
         .pci.qdev.desc = "Intel i82551 Ethernet",
         .pci.qdev.desc = "Intel i82551 Ethernet",
         .device = i82551,
         .device = i82551,
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* Revision ID: 0x0f, 0x10. */
         /* Revision ID: 0x0f, 0x10. */
-        .revision = 0x0f,
+        .pci.revision = 0x0f,
         /* TODO: check size of statistical counters. */
         /* TODO: check size of statistical counters. */
         .stats_size = 80,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
@@ -2063,29 +2049,29 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82557a",
         .pci.qdev.name = "i82557a",
         .pci.qdev.desc = "Intel i82557A Ethernet",
         .pci.qdev.desc = "Intel i82557A Ethernet",
         .device = i82557A,
         .device = i82557A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x01,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x01,
         .power_management = false,
         .power_management = false,
     },{
     },{
         .pci.qdev.name = "i82557b",
         .pci.qdev.name = "i82557b",
         .pci.qdev.desc = "Intel i82557B Ethernet",
         .pci.qdev.desc = "Intel i82557B Ethernet",
         .device = i82557B,
         .device = i82557B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x02,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x02,
         .power_management = false,
         .power_management = false,
     },{
     },{
         .pci.qdev.name = "i82557c",
         .pci.qdev.name = "i82557c",
         .pci.qdev.desc = "Intel i82557C Ethernet",
         .pci.qdev.desc = "Intel i82557C Ethernet",
         .device = i82557C,
         .device = i82557C,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x03,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x03,
         .power_management = false,
         .power_management = false,
     },{
     },{
         .pci.qdev.name = "i82558a",
         .pci.qdev.name = "i82558a",
         .pci.qdev.desc = "Intel i82558A Ethernet",
         .pci.qdev.desc = "Intel i82558A Ethernet",
         .device = i82558A,
         .device = i82558A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x04,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x04,
         .stats_size = 76,
         .stats_size = 76,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2093,8 +2079,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82558b",
         .pci.qdev.name = "i82558b",
         .pci.qdev.desc = "Intel i82558B Ethernet",
         .pci.qdev.desc = "Intel i82558B Ethernet",
         .device = i82558B,
         .device = i82558B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x05,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x05,
         .stats_size = 76,
         .stats_size = 76,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2102,8 +2088,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559a",
         .pci.qdev.name = "i82559a",
         .pci.qdev.desc = "Intel i82559A Ethernet",
         .pci.qdev.desc = "Intel i82559A Ethernet",
         .device = i82559A,
         .device = i82559A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x06,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x06,
         .stats_size = 80,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2111,8 +2097,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559b",
         .pci.qdev.name = "i82559b",
         .pci.qdev.desc = "Intel i82559B Ethernet",
         .pci.qdev.desc = "Intel i82559B Ethernet",
         .device = i82559B,
         .device = i82559B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x07,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.revision = 0x07,
         .stats_size = 80,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2120,12 +2106,16 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559c",
         .pci.qdev.name = "i82559c",
         .pci.qdev.desc = "Intel i82559C Ethernet",
         .pci.qdev.desc = "Intel i82559C Ethernet",
         .device = i82559C,
         .device = i82559C,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
 #if 0
 #if 0
-        .revision = 0x08,
+        .pci.revision = 0x08,
 #endif
 #endif
         /* TODO: Windows wants revision id 0x0c. */
         /* TODO: Windows wants revision id 0x0c. */
-        .revision = 0x0c,
+        .pci.revision = 0x0c,
+#if EEPROM_SIZE > 0
+        .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
+        .pci.subsystem_id = 0x0040,
+#endif
         .stats_size = 80,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2133,8 +2123,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82559er",
         .pci.qdev.name = "i82559er",
         .pci.qdev.desc = "Intel i82559ER Ethernet",
         .pci.qdev.desc = "Intel i82559ER Ethernet",
         .device = i82559ER,
         .device = i82559ER,
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
-        .revision = 0x09,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.revision = 0x09,
         .stats_size = 80,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2143,9 +2133,9 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.desc = "Intel i82562 Ethernet",
         .pci.qdev.desc = "Intel i82562 Ethernet",
         .device = i82562,
         .device = i82562,
         /* TODO: check device id. */
         /* TODO: check device id. */
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* TODO: wrong revision id. */
         /* TODO: wrong revision id. */
-        .revision = 0x0e,
+        .pci.revision = 0x0e,
         .stats_size = 80,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2154,8 +2144,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .pci.qdev.name = "i82801",
         .pci.qdev.name = "i82801",
         .pci.qdev.desc = "Intel i82801 Ethernet",
         .pci.qdev.desc = "Intel i82801 Ethernet",
         .device = i82801,
         .device = i82801,
-        .device_id = 0x2449,
-        .revision = 0x03,
+        .pci.device_id = 0x2449,
+        .pci.revision = 0x03,
         .stats_size = 80,
         .stats_size = 80,
         .has_extended_tcb_support = true,
         .has_extended_tcb_support = true,
         .power_management = true,
         .power_management = true,
@@ -2174,6 +2164,8 @@ static void eepro100_register_devices(void)
         PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
         PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
         /* We use the same rom file for all device ids.
         /* We use the same rom file for all device ids.
            QEMU fixes the device id during rom load. */
            QEMU fixes the device id during rom load. */
+        pci_dev->vendor_id = PCI_VENDOR_ID_INTEL;
+        pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET;
         pci_dev->romfile = "pxe-eepro100.rom";
         pci_dev->romfile = "pxe-eepro100.rom";
         pci_dev->init = e100_nic_init;
         pci_dev->init = e100_nic_init;
         pci_dev->exit = pci_nic_uninit;
         pci_dev->exit = pci_nic_uninit;

+ 11 - 13
hw/es1370.c

@@ -998,21 +998,9 @@ static int es1370_initfn (PCIDevice *dev)
     ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
     ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
     uint8_t *c = s->dev.config;
     uint8_t *c = s->dev.config;
 
 
-    pci_config_set_vendor_id (c, PCI_VENDOR_ID_ENSONIQ);
-    pci_config_set_device_id (c, PCI_DEVICE_ID_ENSONIQ_ES1370);
     c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
     c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
-    pci_config_set_class (c, PCI_CLASS_MULTIMEDIA_AUDIO);
 
 
-#if 1
-    c[PCI_SUBSYSTEM_VENDOR_ID] = 0x42;
-    c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x49;
-    c[PCI_SUBSYSTEM_ID] = 0x4c;
-    c[PCI_SUBSYSTEM_ID + 1] = 0x4c;
-#else
-    c[PCI_SUBSYSTEM_VENDOR_ID] = 0x74;
-    c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x12;
-    c[PCI_SUBSYSTEM_ID] = 0x71;
-    c[PCI_SUBSYSTEM_ID + 1] = 0x13;
+#if 0
     c[PCI_CAPABILITY_LIST] = 0xdc;
     c[PCI_CAPABILITY_LIST] = 0xdc;
     c[PCI_INTERRUPT_LINE] = 10;
     c[PCI_INTERRUPT_LINE] = 10;
     c[0xdc] = 0x00;
     c[0xdc] = 0x00;
@@ -1043,6 +1031,16 @@ static PCIDeviceInfo es1370_info = {
     .qdev.size    = sizeof (ES1370State),
     .qdev.size    = sizeof (ES1370State),
     .qdev.vmsd    = &vmstate_es1370,
     .qdev.vmsd    = &vmstate_es1370,
     .init         = es1370_initfn,
     .init         = es1370_initfn,
+    .vendor_id    = PCI_VENDOR_ID_ENSONIQ,
+    .device_id    = PCI_DEVICE_ID_ENSONIQ_ES1370,
+    .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
+#if 1
+    .subsystem_vendor_id = 0x4942,
+    .subsystem_id = 0x4c4c,
+#else
+    .subsystem_vendor_id = 0x1274,
+    .subsystem_id = 0x1371,
+#endif
 };
 };
 
 
 static void es1370_register (void)
 static void es1370_register (void)

+ 4 - 4
hw/grackle_pci.c

@@ -104,11 +104,7 @@ static int pci_grackle_init_device(SysBusDevice *dev)
 
 
 static int grackle_pci_host_init(PCIDevice *d)
 static int grackle_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_MPC106);
-    d->config[0x08] = 0x00; // revision
     d->config[0x09] = 0x01;
     d->config[0x09] = 0x01;
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     return 0;
     return 0;
 }
 }
 
 
@@ -116,6 +112,10 @@ static PCIDeviceInfo grackle_pci_host_info = {
     .qdev.name = "grackle",
     .qdev.name = "grackle",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = grackle_pci_host_init,
     .init      = grackle_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_MOTOROLA,
+    .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 };
 
 
 static void grackle_register_devices(void)
 static void grackle_register_devices(void)

+ 4 - 4
hw/gt64xxx.c

@@ -1118,14 +1118,10 @@ static int gt64120_init(SysBusDevice *dev)
 static int gt64120_pci_init(PCIDevice *d)
 static int gt64120_pci_init(PCIDevice *d)
 {
 {
     /* FIXME: Malta specific hw assumptions ahead */
     /* FIXME: Malta specific hw assumptions ahead */
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MARVELL);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MARVELL_GT6412X);
     pci_set_word(d->config + PCI_COMMAND, 0);
     pci_set_word(d->config + PCI_COMMAND, 0);
     pci_set_word(d->config + PCI_STATUS,
     pci_set_word(d->config + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_set_byte(d->config + PCI_CLASS_REVISION, 0x10);
     pci_config_set_prog_interface(d->config, 0);
     pci_config_set_prog_interface(d->config, 0);
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
     pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
     pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
     pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
     pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
     pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
@@ -1141,6 +1137,10 @@ static PCIDeviceInfo gt64120_pci_info = {
     .qdev.name = "gt64120_pci",
     .qdev.name = "gt64120_pci",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = gt64120_pci_init,
     .init      = gt64120_pci_init,
+    .vendor_id = PCI_VENDOR_ID_MARVELL,
+    .device_id = PCI_DEVICE_ID_MARVELL_GT6412X,
+    .revision  = 0x10,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 };
 
 
 static void gt64120_pci_register_devices(void)
 static void gt64120_pci_register_devices(void)

+ 4 - 6
hw/ide/cmd646.c

@@ -226,14 +226,8 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     qemu_irq *irq;
     qemu_irq *irq;
     int i;
     int i;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
-
-    pci_conf[PCI_REVISION_ID] = 0x07; // IDE controller revision
     pci_conf[PCI_CLASS_PROG] = 0x8f;
     pci_conf[PCI_CLASS_PROG] = 0x8f;
 
 
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
-
     pci_conf[0x51] = 0x04; // enable IDE0
     pci_conf[0x51] = 0x04; // enable IDE0
     if (d->secondary) {
     if (d->secondary) {
         /* XXX: if not enabled, really disable the seconday IDE controller */
         /* XXX: if not enabled, really disable the seconday IDE controller */
@@ -282,6 +276,10 @@ static PCIDeviceInfo cmd646_ide_info[] = {
         .qdev.name    = "cmd646-ide",
         .qdev.name    = "cmd646-ide",
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.size    = sizeof(PCIIDEState),
         .init         = pci_cmd646_ide_initfn,
         .init         = pci_cmd646_ide_initfn,
+        .vendor_id    = PCI_VENDOR_ID_CMD,
+        .device_id    = PCI_DEVICE_ID_CMD_646,
+        .revision     = 0x07, // IDE controller revision
+        .class_id     = PCI_CLASS_STORAGE_IDE,
         .qdev.props   = (Property[]) {
         .qdev.props   = (Property[]) {
             DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
             DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
             DEFINE_PROP_END_OF_LIST(),
             DEFINE_PROP_END_OF_LIST(),

+ 5 - 6
hw/ide/ich.c

@@ -77,11 +77,8 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     struct AHCIPCIState *d;
     struct AHCIPCIState *d;
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
 
-    pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR);
+    ahci_init(&d->ahci, &dev->qdev, 6);
 
 
-    pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA);
-    pci_config_set_revision(d->card.config, 0x02);
     pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
     pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
 
 
     d->card.config[PCI_CACHE_LINE_SIZE] = 0x08;  /* Cache line size */
     d->card.config[PCI_CACHE_LINE_SIZE] = 0x08;  /* Cache line size */
@@ -94,8 +91,6 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     qemu_register_reset(ahci_reset, d);
     qemu_register_reset(ahci_reset, d);
 
 
     msi_init(dev, 0x50, 1, true, false);
     msi_init(dev, 0x50, 1, true, false);
-
-    ahci_init(&d->ahci, &dev->qdev, 6);
     d->ahci.irq = d->card.irq[0];
     d->ahci.irq = d->card.irq[0];
 
 
     /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
     /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
@@ -131,6 +126,10 @@ static PCIDeviceInfo ich_ahci_info[] = {
         .init         = pci_ich9_ahci_init,
         .init         = pci_ich9_ahci_init,
         .exit         = pci_ich9_uninit,
         .exit         = pci_ich9_uninit,
         .config_write = pci_ich9_write_config,
         .config_write = pci_ich9_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82801IR,
+        .revision     = 0x02,
+        .class_id     = PCI_CLASS_STORAGE_SATA,
     },{
     },{
         /* end of list */
         /* end of list */
     }
     }

+ 10 - 22
hw/ide/piix.c

@@ -131,12 +131,12 @@ static void pci_piix_init_ports(PCIIDEState *d) {
     }
     }
 }
 }
 
 
-static int pci_piix_ide_initfn(PCIIDEState *d)
+static int pci_piix_ide_initfn(PCIDevice *dev)
 {
 {
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
     uint8_t *pci_conf = d->dev.config;
     uint8_t *pci_conf = d->dev.config;
 
 
     pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
     pci_conf[PCI_CLASS_PROG] = 0x80; // legacy ATA mode
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
 
 
     qemu_register_reset(piix3_reset, d);
     qemu_register_reset(piix3_reset, d);
 
 
@@ -149,24 +149,6 @@ static int pci_piix_ide_initfn(PCIIDEState *d)
     return 0;
     return 0;
 }
 }
 
 
-static int pci_piix3_ide_initfn(PCIDevice *dev)
-{
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
-
-    pci_config_set_vendor_id(d->dev.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->dev.config, PCI_DEVICE_ID_INTEL_82371SB_1);
-    return pci_piix_ide_initfn(d);
-}
-
-static int pci_piix4_ide_initfn(PCIDevice *dev)
-{
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
-
-    pci_config_set_vendor_id(d->dev.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->dev.config, PCI_DEVICE_ID_INTEL_82371AB);
-    return pci_piix_ide_initfn(d);
-}
-
 /* hd_table must contain 4 block drivers */
 /* hd_table must contain 4 block drivers */
 /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
 /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
 PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
 PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
@@ -195,13 +177,19 @@ static PCIDeviceInfo piix_ide_info[] = {
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.no_user = 1,
         .qdev.no_user = 1,
         .no_hotplug   = 1,
         .no_hotplug   = 1,
-        .init         = pci_piix3_ide_initfn,
+        .init         = pci_piix_ide_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
+        .class_id     = PCI_CLASS_STORAGE_IDE,
     },{
     },{
         .qdev.name    = "piix4-ide",
         .qdev.name    = "piix4-ide",
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.no_user = 1,
         .qdev.no_user = 1,
         .no_hotplug   = 1,
         .no_hotplug   = 1,
-        .init         = pci_piix4_ide_initfn,
+        .init         = pci_piix_ide_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB,
+        .class_id     = PCI_CLASS_STORAGE_IDE,
     },{
     },{
         /* end of list */
         /* end of list */
     }
     }

+ 4 - 4
hw/ide/via.c

@@ -160,11 +160,7 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);;
     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);;
     uint8_t *pci_conf = d->dev.config;
     uint8_t *pci_conf = d->dev.config;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_IDE);
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
     pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */
     pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */
-    pci_config_set_revision(pci_conf,0x06); /* Revision 0.6 */
     pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
     pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
 
 
     qemu_register_reset(via_reset, d);
     qemu_register_reset(via_reset, d);
@@ -191,6 +187,10 @@ static PCIDeviceInfo via_ide_info = {
     .qdev.size    = sizeof(PCIIDEState),
     .qdev.size    = sizeof(PCIIDEState),
     .qdev.no_user = 1,
     .qdev.no_user = 1,
     .init         = vt82c686b_ide_initfn,
     .init         = vt82c686b_ide_initfn,
+    .vendor_id    = PCI_VENDOR_ID_VIA,
+    .device_id    = PCI_DEVICE_ID_VIA_IDE,
+    .revision     = 0x06,
+    .class_id     = PCI_CLASS_STORAGE_IDE,
 };
 };
 
 
 static void via_ide_register(void)
 static void via_ide_register(void)

+ 4 - 4
hw/intel-hda.c

@@ -1138,10 +1138,6 @@ static int intel_hda_init(PCIDevice *pci)
 
 
     d->name = d->pci.qdev.info->name;
     d->name = d->pci.qdev.info->name;
 
 
-    pci_config_set_vendor_id(conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(conf, 0x2668);
-    pci_config_set_revision(conf, 1);
-    pci_config_set_class(conf, PCI_CLASS_MULTIMEDIA_HD_AUDIO);
     pci_config_set_interrupt_pin(conf, 1);
     pci_config_set_interrupt_pin(conf, 1);
 
 
     /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
     /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
@@ -1265,6 +1261,10 @@ static PCIDeviceInfo intel_hda_info = {
     .init         = intel_hda_init,
     .init         = intel_hda_init,
     .exit         = intel_hda_exit,
     .exit         = intel_hda_exit,
     .config_write = intel_hda_write_config,
     .config_write = intel_hda_write_config,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = 0x2668,
+    .revision     = 1,
+    .class_id     = PCI_CLASS_MULTIMEDIA_HD_AUDIO,
     .qdev.props   = (Property[]) {
     .qdev.props   = (Property[]) {
         DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
         DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
         DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
         DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),

+ 3 - 4
hw/ioh3420.c

@@ -104,12 +104,8 @@ static int ioh3420_initfn(PCIDevice *d)
         return rc;
         return rc;
     }
     }
 
 
-    d->config[PCI_REVISION_ID] = PCI_DEVICE_ID_IOH_REV;
     pcie_port_init_reg(d);
     pcie_port_init_reg(d);
 
 
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_IOH_EPORT);
-
     rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
     rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
                                IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
                                IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
     if (rc < 0) {
     if (rc < 0) {
@@ -217,6 +213,9 @@ static PCIDeviceInfo ioh3420_info = {
     .config_write = ioh3420_write_config,
     .config_write = ioh3420_write_config,
     .init = ioh3420_initfn,
     .init = ioh3420_initfn,
     .exit = ioh3420_exitfn,
     .exit = ioh3420_exitfn,
+    .vendor_id = PCI_VENDOR_ID_INTEL,
+    .device_id = PCI_DEVICE_ID_IOH_EPORT,
+    .revision = PCI_DEVICE_ID_IOH_REV,
 
 
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
         DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),

+ 3 - 5
hw/ivshmem.c

@@ -706,12 +706,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
     }
     }
 
 
     pci_conf = s->dev.config;
     pci_conf = s->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REDHAT_QUMRANET);
-    pci_conf[0x02] = 0x10;
-    pci_conf[0x03] = 0x11;
     pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
     pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-    pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_RAM);
-    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
 
 
     pci_config_set_interrupt_pin(pci_conf, 1);
     pci_config_set_interrupt_pin(pci_conf, 1);
 
 
@@ -809,6 +804,9 @@ static PCIDeviceInfo ivshmem_info = {
     .qdev.reset = ivshmem_reset,
     .qdev.reset = ivshmem_reset,
     .init       = pci_ivshmem_init,
     .init       = pci_ivshmem_init,
     .exit       = pci_ivshmem_uninit,
     .exit       = pci_ivshmem_uninit,
+    .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
+    .device_id  = 0x1110,
+    .class_id   = PCI_CLASS_MEMORY_RAM,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
         DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
         DEFINE_PROP_STRING("size", IVShmemState, sizearg),
         DEFINE_PROP_STRING("size", IVShmemState, sizearg),

+ 4 - 9
hw/lsi53c895a.c

@@ -2256,15 +2256,6 @@ static int lsi_scsi_init(PCIDevice *dev)
 
 
     pci_conf = s->dev.config;
     pci_conf = s->dev.config;
 
 
-    /* PCI Vendor ID (word) */
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_LSI_LOGIC);
-    /* PCI device ID (word) */
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_LSI_53C895A);
-    /* PCI base class code */
-    pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_SCSI);
-    /* PCI subsystem ID */
-    pci_conf[PCI_SUBSYSTEM_ID] = 0x00;
-    pci_conf[PCI_SUBSYSTEM_ID + 1] = 0x10;
     /* PCI latency timer = 255 */
     /* PCI latency timer = 255 */
     pci_conf[PCI_LATENCY_TIMER] = 0xff;
     pci_conf[PCI_LATENCY_TIMER] = 0xff;
     /* TODO: RST# value should be 0 */
     /* TODO: RST# value should be 0 */
@@ -2300,6 +2291,10 @@ static PCIDeviceInfo lsi_info = {
     .qdev.vmsd  = &vmstate_lsi_scsi,
     .qdev.vmsd  = &vmstate_lsi_scsi,
     .init       = lsi_scsi_init,
     .init       = lsi_scsi_init,
     .exit       = lsi_scsi_uninit,
     .exit       = lsi_scsi_uninit,
+    .vendor_id  = PCI_VENDOR_ID_LSI_LOGIC,
+    .device_id  = PCI_DEVICE_ID_LSI_53C895A,
+    .class_id   = PCI_CLASS_STORAGE_SCSI,
+    .subsystem_id = 0x1000,
 };
 };
 
 
 static void lsi53c895a_register_devices(void)
 static void lsi53c895a_register_devices(void)

+ 1 - 1
hw/msi.c

@@ -172,7 +172,7 @@ void msi_uninit(struct PCIDevice *dev)
     }
     }
     flags = pci_get_word(dev->config + msi_flags_off(dev));
     flags = pci_get_word(dev->config + msi_flags_off(dev));
     cap_size = msi_cap_sizeof(flags);
     cap_size = msi_cap_sizeof(flags);
-    pci_del_capability(dev, PCI_CAP_ID_MSIX, cap_size);
+    pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
     dev->cap_present &= ~QEMU_PCI_CAP_MSI;
     dev->cap_present &= ~QEMU_PCI_CAP_MSI;
 
 
     MSI_DEV_PRINTF(dev, "uninit\n");
     MSI_DEV_PRINTF(dev, "uninit\n");

+ 15 - 25
hw/msix.c

@@ -16,9 +16,6 @@
 #include "pci.h"
 #include "pci.h"
 #include "range.h"
 #include "range.h"
 
 
-/* MSI-X capability structure */
-#define MSIX_TABLE_OFFSET 4
-#define MSIX_PBA_OFFSET 8
 #define MSIX_CAP_LENGTH 12
 #define MSIX_CAP_LENGTH 12
 
 
 /* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
 /* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
@@ -26,14 +23,6 @@
 #define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
 #define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
 #define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
 #define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
 
 
-/* MSI-X table format */
-#define MSIX_MSG_ADDR 0
-#define MSIX_MSG_UPPER_ADDR 4
-#define MSIX_MSG_DATA 8
-#define MSIX_VECTOR_CTRL 12
-#define MSIX_ENTRY_SIZE 16
-#define MSIX_VECTOR_MASK 0x1
-
 /* How much space does an MSIX table need. */
 /* How much space does an MSIX table need. */
 /* The spec requires giving the table structure
 /* The spec requires giving the table structure
  * a 4K aligned region all by itself. */
  * a 4K aligned region all by itself. */
@@ -82,9 +71,9 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
 
 
     pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
     pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
     /* Table on top of BAR */
     /* Table on top of BAR */
-    pci_set_long(config + MSIX_TABLE_OFFSET, bar_size | bar_nr);
+    pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
     /* Pending bits on top of that */
     /* Pending bits on top of that */
-    pci_set_long(config + MSIX_PBA_OFFSET, (bar_size + MSIX_PAGE_PENDING) |
+    pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
                  bar_nr);
                  bar_nr);
     pdev->msix_cap = config_offset;
     pdev->msix_cap = config_offset;
     /* Make flags bit writable. */
     /* Make flags bit writable. */
@@ -140,9 +129,10 @@ static int msix_function_masked(PCIDevice *dev)
 
 
 static int msix_is_masked(PCIDevice *dev, int vector)
 static int msix_is_masked(PCIDevice *dev, int vector)
 {
 {
-    unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
+    unsigned offset =
+        vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
     return msix_function_masked(dev) ||
     return msix_function_masked(dev) ||
-	   dev->msix_table_page[offset] & MSIX_VECTOR_MASK;
+	   dev->msix_table_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
 }
 }
 
 
 static void msix_handle_mask_update(PCIDevice *dev, int vector)
 static void msix_handle_mask_update(PCIDevice *dev, int vector)
@@ -184,7 +174,7 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
 {
 {
     PCIDevice *dev = opaque;
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
-    int vector = offset / MSIX_ENTRY_SIZE;
+    int vector = offset / PCI_MSIX_ENTRY_SIZE;
     pci_set_long(dev->msix_table_page + offset, val);
     pci_set_long(dev->msix_table_page + offset, val);
     msix_handle_mask_update(dev, vector);
     msix_handle_mask_update(dev, vector);
 }
 }
@@ -208,7 +198,7 @@ void msix_mmio_map(PCIDevice *d, int region_num,
                    pcibus_t addr, pcibus_t size, int type)
                    pcibus_t addr, pcibus_t size, int type)
 {
 {
     uint8_t *config = d->config + d->msix_cap;
     uint8_t *config = d->config + d->msix_cap;
-    uint32_t table = pci_get_long(config + MSIX_TABLE_OFFSET);
+    uint32_t table = pci_get_long(config + PCI_MSIX_TABLE);
     uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1);
     uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1);
     /* TODO: for assigned devices, we'll want to make it possible to map
     /* TODO: for assigned devices, we'll want to make it possible to map
      * pending bits separately in case they are in a separate bar. */
      * pending bits separately in case they are in a separate bar. */
@@ -226,8 +216,9 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
 {
 {
     int vector;
     int vector;
     for (vector = 0; vector < nentries; ++vector) {
     for (vector = 0; vector < nentries; ++vector) {
-        unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
-        dev->msix_table_page[offset] |= MSIX_VECTOR_MASK;
+        unsigned offset =
+            vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
+        dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
     }
     }
 }
 }
 
 
@@ -313,7 +304,7 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
         return;
         return;
     }
     }
 
 
-    qemu_put_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE);
+    qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
     qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
     qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
 }
 }
 
 
@@ -327,7 +318,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
     }
     }
 
 
     msix_free_irq_entries(dev);
     msix_free_irq_entries(dev);
-    qemu_get_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE);
+    qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
     qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
     qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
 }
 }
 
 
@@ -355,7 +346,7 @@ uint32_t msix_bar_size(PCIDevice *dev)
 /* Send an MSI-X message */
 /* Send an MSI-X message */
 void msix_notify(PCIDevice *dev, unsigned vector)
 void msix_notify(PCIDevice *dev, unsigned vector)
 {
 {
-    uint8_t *table_entry = dev->msix_table_page + vector * MSIX_ENTRY_SIZE;
+    uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
     uint64_t address;
     uint64_t address;
     uint32_t data;
     uint32_t data;
 
 
@@ -366,9 +357,8 @@ void msix_notify(PCIDevice *dev, unsigned vector)
         return;
         return;
     }
     }
 
 
-    address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
-    address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR);
-    data = pci_get_long(table_entry + MSIX_MSG_DATA);
+    address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
+    data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
     stl_phys(address, data);
     stl_phys(address, data);
 }
 }
 
 

+ 3 - 3
hw/ne2000.c

@@ -721,9 +721,6 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
     uint8_t *pci_conf;
     uint8_t *pci_conf;
 
 
     pci_conf = d->dev.config;
     pci_conf = d->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8029);
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
     /* TODO: RST# value should be 0. PCI spec 6.2.4 */
     /* TODO: RST# value should be 0. PCI spec 6.2.4 */
     pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
     pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
 
 
@@ -767,6 +764,9 @@ static PCIDeviceInfo ne2000_info = {
     .qdev.vmsd  = &vmstate_pci_ne2000,
     .qdev.vmsd  = &vmstate_pci_ne2000,
     .init       = pci_ne2000_init,
     .init       = pci_ne2000_init,
     .exit       = pci_ne2000_exit,
     .exit       = pci_ne2000_exit,
+    .vendor_id  = PCI_VENDOR_ID_REALTEK,
+    .device_id  = PCI_DEVICE_ID_REALTEK_8029,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
         DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
         DEFINE_PROP_END_OF_LIST(),
         DEFINE_PROP_END_OF_LIST(),

+ 48 - 0
hw/pc_piix.c

@@ -288,6 +288,18 @@ static QEMUMachine pc_machine_v0_13 = {
             .driver   = "PCI",
             .driver   = "PCI",
             .property = "command_serr_enable",
             .property = "command_serr_enable",
             .value    = "off",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
         },
         },
         { /* end of list */ }
         { /* end of list */ }
     },
     },
@@ -319,6 +331,18 @@ static QEMUMachine pc_machine_v0_12 = {
             .driver   = "PCI",
             .driver   = "PCI",
             .property = "command_serr_enable",
             .property = "command_serr_enable",
             .value    = "off",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
         },
         },
         { /* end of list */ }
         { /* end of list */ }
     }
     }
@@ -358,6 +382,18 @@ static QEMUMachine pc_machine_v0_11 = {
             .driver   = "PCI",
             .driver   = "PCI",
             .property = "command_serr_enable",
             .property = "command_serr_enable",
             .value    = "off",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
         },
         },
         { /* end of list */ }
         { /* end of list */ }
     }
     }
@@ -409,6 +445,18 @@ static QEMUMachine pc_machine_v0_10 = {
             .driver   = "PCI",
             .driver   = "PCI",
             .property = "command_serr_enable",
             .property = "command_serr_enable",
             .value    = "off",
             .value    = "off",
+        },{
+            .driver   = "virtio-blk-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-serial-pci",
+            .property = "event_idx",
+            .value    = "off",
+        },{
+            .driver   = "virtio-net-pci",
+            .property = "event_idx",
+            .value    = "off",
         },
         },
         { /* end of list */ }
         { /* end of list */ }
     },
     },

+ 38 - 18
hw/pci.c

@@ -726,10 +726,11 @@ static void pci_config_free(PCIDevice *pci_dev)
 /* -1 for devfn means auto assign */
 /* -1 for devfn means auto assign */
 static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
 static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
                                          const char *name, int devfn,
                                          const char *name, int devfn,
-                                         PCIConfigReadFunc *config_read,
-                                         PCIConfigWriteFunc *config_write,
-                                         bool is_bridge)
+                                         const PCIDeviceInfo *info)
 {
 {
+    PCIConfigReadFunc *config_read = info->config_read;
+    PCIConfigWriteFunc *config_write = info->config_write;
+
     if (devfn < 0) {
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
             devfn += PCI_FUNC_MAX) {
             devfn += PCI_FUNC_MAX) {
@@ -750,13 +751,29 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     pci_dev->irq_state = 0;
     pci_dev->irq_state = 0;
     pci_config_alloc(pci_dev);
     pci_config_alloc(pci_dev);
 
 
-    if (!is_bridge) {
-        pci_set_default_subsystem_id(pci_dev);
+    pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
+    pci_config_set_device_id(pci_dev->config, info->device_id);
+    pci_config_set_revision(pci_dev->config, info->revision);
+    pci_config_set_class(pci_dev->config, info->class_id);
+
+    if (!info->is_bridge) {
+        if (info->subsystem_vendor_id || info->subsystem_id) {
+            pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+                         info->subsystem_vendor_id);
+            pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+                         info->subsystem_id);
+        } else {
+            pci_set_default_subsystem_id(pci_dev);
+        }
+    } else {
+        /* subsystem_vendor_id/subsystem_id are only for header type 0 */
+        assert(!info->subsystem_vendor_id);
+        assert(!info->subsystem_id);
     }
     }
     pci_init_cmask(pci_dev);
     pci_init_cmask(pci_dev);
     pci_init_wmask(pci_dev);
     pci_init_wmask(pci_dev);
     pci_init_w1cmask(pci_dev);
     pci_init_w1cmask(pci_dev);
-    if (is_bridge) {
+    if (info->is_bridge) {
         pci_init_wmask_bridge(pci_dev);
         pci_init_wmask_bridge(pci_dev);
     }
     }
     if (pci_init_multifunction(bus, pci_dev)) {
     if (pci_init_multifunction(bus, pci_dev)) {
@@ -783,17 +800,20 @@ static void do_pci_unregister_device(PCIDevice *pci_dev)
     pci_config_free(pci_dev);
     pci_config_free(pci_dev);
 }
 }
 
 
+/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
                                PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write)
                                PCIConfigWriteFunc *config_write)
 {
 {
     PCIDevice *pci_dev;
     PCIDevice *pci_dev;
+    PCIDeviceInfo info = {
+        .config_read = config_read,
+        .config_write = config_write,
+    };
 
 
     pci_dev = qemu_mallocz(instance_size);
     pci_dev = qemu_mallocz(instance_size);
-    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn,
-                                     config_read, config_write,
-                                     PCI_HEADER_TYPE_NORMAL);
+    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
     if (pci_dev == NULL) {
     if (pci_dev == NULL) {
         hw_error("PCI: can't register device\n");
         hw_error("PCI: can't register device\n");
     }
     }
@@ -1643,7 +1663,7 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     PCIDevice *pci_dev = (PCIDevice *)qdev;
     PCIDevice *pci_dev = (PCIDevice *)qdev;
     PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
     PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
     PCIBus *bus;
     PCIBus *bus;
-    int devfn, rc;
+    int rc;
     bool is_default_rom;
     bool is_default_rom;
 
 
     /* initialize cap_present for pci_is_express() and pci_config_size() */
     /* initialize cap_present for pci_is_express() and pci_config_size() */
@@ -1652,10 +1672,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     }
     }
 
 
     bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
     bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
-    devfn = pci_dev->devfn;
-    pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
-                                     info->config_read, info->config_write,
-                                     info->is_bridge);
+    pci_dev = do_pci_register_device(pci_dev, bus, base->name,
+                                     pci_dev->devfn, info);
     if (pci_dev == NULL)
     if (pci_dev == NULL)
         return -1;
         return -1;
     if (qdev->hotplugged && info->no_hotplug) {
     if (qdev->hotplugged && info->no_hotplug) {
@@ -1663,10 +1681,12 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
         do_pci_unregister_device(pci_dev);
         do_pci_unregister_device(pci_dev);
         return -1;
         return -1;
     }
     }
-    rc = info->init(pci_dev);
-    if (rc != 0) {
-        do_pci_unregister_device(pci_dev);
-        return rc;
+    if (info->init) {
+        rc = info->init(pci_dev);
+        if (rc != 0) {
+            do_pci_unregister_device(pci_dev);
+            return rc;
+        }
     }
     }
 
 
     /* rom loading */
     /* rom loading */

+ 7 - 0
hw/pci.h

@@ -433,6 +433,13 @@ typedef struct {
     PCIConfigReadFunc *config_read;
     PCIConfigReadFunc *config_read;
     PCIConfigWriteFunc *config_write;
     PCIConfigWriteFunc *config_write;
 
 
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint8_t revision;
+    uint16_t class_id;
+    uint16_t subsystem_vendor_id;       /* only for header type = 0 */
+    uint16_t subsystem_id;              /* only for header type = 0 */
+
     /*
     /*
      * pci-to-pci bridge or normal device.
      * pci-to-pci bridge or normal device.
      * This doesn't mean pci host switch.
      * This doesn't mean pci host switch.

+ 55 - 5
hw/pci_regs.h

@@ -300,12 +300,22 @@
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 #define PCI_MSI_MASK_64		16	/* Mask bits register for 64-bit devices */
 #define PCI_MSI_MASK_64		16	/* Mask bits register for 64-bit devices */
 
 
-/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
+/* MSI-X registers */
 #define PCI_MSIX_FLAGS		2
 #define PCI_MSIX_FLAGS		2
 #define  PCI_MSIX_FLAGS_QSIZE	0x7FF
 #define  PCI_MSIX_FLAGS_QSIZE	0x7FF
 #define  PCI_MSIX_FLAGS_ENABLE	(1 << 15)
 #define  PCI_MSIX_FLAGS_ENABLE	(1 << 15)
 #define  PCI_MSIX_FLAGS_MASKALL	(1 << 14)
 #define  PCI_MSIX_FLAGS_MASKALL	(1 << 14)
-#define PCI_MSIX_FLAGS_BIRMASK	(7 << 0)
+#define PCI_MSIX_TABLE		4
+#define PCI_MSIX_PBA		8
+#define  PCI_MSIX_FLAGS_BIRMASK	(7 << 0)
+
+/* MSI-X entry's format */
+#define PCI_MSIX_ENTRY_SIZE		16
+#define  PCI_MSIX_ENTRY_LOWER_ADDR	0
+#define  PCI_MSIX_ENTRY_UPPER_ADDR	4
+#define  PCI_MSIX_ENTRY_DATA		8
+#define  PCI_MSIX_ENTRY_VECTOR_CTRL	12
+#define   PCI_MSIX_ENTRY_CTRL_MASKBIT	1
 
 
 /* CompactPCI Hotswap Register */
 /* CompactPCI Hotswap Register */
 
 
@@ -365,6 +375,11 @@
 #define  PCI_X_STATUS_266MHZ	0x40000000	/* 266 MHz capable */
 #define  PCI_X_STATUS_266MHZ	0x40000000	/* 266 MHz capable */
 #define  PCI_X_STATUS_533MHZ	0x80000000	/* 533 MHz capable */
 #define  PCI_X_STATUS_533MHZ	0x80000000	/* 533 MHz capable */
 
 
+/* PCI Bridge Subsystem ID registers */
+
+#define PCI_SSVID_VENDOR_ID     4	/* PCI-Bridge subsystem vendor id register */
+#define PCI_SSVID_DEVICE_ID     6	/* PCI-Bridge subsystem device id register */
+
 /* PCI Express capability registers */
 /* PCI Express capability registers */
 
 
 #define PCI_EXP_FLAGS		2	/* Capabilities register */
 #define PCI_EXP_FLAGS		2	/* Capabilities register */
@@ -420,7 +435,7 @@
 #define  PCI_EXP_LNKCAP_L0SEL	0x00007000 /* L0s Exit Latency */
 #define  PCI_EXP_LNKCAP_L0SEL	0x00007000 /* L0s Exit Latency */
 #define  PCI_EXP_LNKCAP_L1EL	0x00038000 /* L1 Exit Latency */
 #define  PCI_EXP_LNKCAP_L1EL	0x00038000 /* L1 Exit Latency */
 #define  PCI_EXP_LNKCAP_CLKPM	0x00040000 /* L1 Clock Power Management */
 #define  PCI_EXP_LNKCAP_CLKPM	0x00040000 /* L1 Clock Power Management */
-#define  PCI_EXP_LNKCAP_SDERC	0x00080000 /* Suprise Down Error Reporting Capable */
+#define  PCI_EXP_LNKCAP_SDERC	0x00080000 /* Surprise Down Error Reporting Capable */
 #define  PCI_EXP_LNKCAP_DLLLARC	0x00100000 /* Data Link Layer Link Active Reporting Capable */
 #define  PCI_EXP_LNKCAP_DLLLARC	0x00100000 /* Data Link Layer Link Active Reporting Capable */
 #define  PCI_EXP_LNKCAP_LBNC	0x00200000 /* Link Bandwidth Notification Capability */
 #define  PCI_EXP_LNKCAP_LBNC	0x00200000 /* Link Bandwidth Notification Capability */
 #define  PCI_EXP_LNKCAP_PN	0xff000000 /* Port Number */
 #define  PCI_EXP_LNKCAP_PN	0xff000000 /* Port Number */
@@ -437,7 +452,10 @@
 #define  PCI_EXP_LNKCTL_LABIE	0x0800	/* Lnk Autonomous Bandwidth Interrupt Enable */
 #define  PCI_EXP_LNKCTL_LABIE	0x0800	/* Lnk Autonomous Bandwidth Interrupt Enable */
 #define PCI_EXP_LNKSTA		18	/* Link Status */
 #define PCI_EXP_LNKSTA		18	/* Link Status */
 #define  PCI_EXP_LNKSTA_CLS	0x000f	/* Current Link Speed */
 #define  PCI_EXP_LNKSTA_CLS	0x000f	/* Current Link Speed */
+#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x01	/* Current Link Speed 2.5GT/s */
+#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x02	/* Current Link Speed 5.0GT/s */
 #define  PCI_EXP_LNKSTA_NLW	0x03f0	/* Nogotiated Link Width */
 #define  PCI_EXP_LNKSTA_NLW	0x03f0	/* Nogotiated Link Width */
+#define  PCI_EXP_LNKSTA_NLW_SHIFT 4	/* start of NLW mask in link status */
 #define  PCI_EXP_LNKSTA_LT	0x0800	/* Link Training */
 #define  PCI_EXP_LNKSTA_LT	0x0800	/* Link Training */
 #define  PCI_EXP_LNKSTA_SLC	0x1000	/* Slot Clock Configuration */
 #define  PCI_EXP_LNKSTA_SLC	0x1000	/* Slot Clock Configuration */
 #define  PCI_EXP_LNKSTA_DLLLA	0x2000	/* Data Link Layer Link Active */
 #define  PCI_EXP_LNKSTA_DLLLA	0x2000	/* Data Link Layer Link Active */
@@ -486,10 +504,22 @@
 #define  PCI_EXP_RTCTL_CRSSVE	0x10	/* CRS Software Visibility Enable */
 #define  PCI_EXP_RTCTL_CRSSVE	0x10	/* CRS Software Visibility Enable */
 #define PCI_EXP_RTCAP		30	/* Root Capabilities */
 #define PCI_EXP_RTCAP		30	/* Root Capabilities */
 #define PCI_EXP_RTSTA		32	/* Root Status */
 #define PCI_EXP_RTSTA		32	/* Root Status */
+#define PCI_EXP_RTSTA_PME	0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING	0x20000 /* PME pending */
 #define PCI_EXP_DEVCAP2		36	/* Device Capabilities 2 */
 #define PCI_EXP_DEVCAP2		36	/* Device Capabilities 2 */
 #define  PCI_EXP_DEVCAP2_ARI	0x20	/* Alternative Routing-ID */
 #define  PCI_EXP_DEVCAP2_ARI	0x20	/* Alternative Routing-ID */
+#define  PCI_EXP_DEVCAP2_LTR	0x800	/* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MASK	0xc0000 /* OBFF support mechanism */
+#define  PCI_EXP_OBFF_MSG	0x40000 /* New message signaling */
+#define  PCI_EXP_OBFF_WAKE	0x80000 /* Re-use WAKE# for OBFF */
 #define PCI_EXP_DEVCTL2		40	/* Device Control 2 */
 #define PCI_EXP_DEVCTL2		40	/* Device Control 2 */
 #define  PCI_EXP_DEVCTL2_ARI	0x20	/* Alternative Routing-ID */
 #define  PCI_EXP_DEVCTL2_ARI	0x20	/* Alternative Routing-ID */
+#define  PCI_EXP_IDO_REQ_EN	0x100	/* ID-based ordering request enable */
+#define  PCI_EXP_IDO_CMP_EN	0x200	/* ID-based ordering completion enable */
+#define  PCI_EXP_LTR_EN		0x400	/* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MSGA_EN	0x2000	/* OBFF enable with Message type A */
+#define  PCI_EXP_OBFF_MSGB_EN	0x4000	/* OBFF enable with Message type B */
+#define  PCI_EXP_OBFF_WAKE_EN	0x6000	/* OBFF using WAKE# signaling */
 #define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
 #define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
 #define PCI_EXP_SLTCTL2		56	/* Slot Control 2 */
 #define PCI_EXP_SLTCTL2		56	/* Slot Control 2 */
 
 
@@ -502,9 +532,12 @@
 #define PCI_EXT_CAP_ID_VC	2
 #define PCI_EXT_CAP_ID_VC	2
 #define PCI_EXT_CAP_ID_DSN	3
 #define PCI_EXT_CAP_ID_DSN	3
 #define PCI_EXT_CAP_ID_PWR	4
 #define PCI_EXT_CAP_ID_PWR	4
+#define PCI_EXT_CAP_ID_VNDR	11
+#define PCI_EXT_CAP_ID_ACS	13
 #define PCI_EXT_CAP_ID_ARI	14
 #define PCI_EXT_CAP_ID_ARI	14
 #define PCI_EXT_CAP_ID_ATS	15
 #define PCI_EXT_CAP_ID_ATS	15
 #define PCI_EXT_CAP_ID_SRIOV	16
 #define PCI_EXT_CAP_ID_SRIOV	16
+#define PCI_EXT_CAP_ID_LTR	24
 
 
 /* Advanced Error Reporting */
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
 #define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
@@ -556,8 +589,7 @@
 #define PCI_ERR_ROOT_FIRST_FATAL	0x00000010	/* First Fatal */
 #define PCI_ERR_ROOT_FIRST_FATAL	0x00000010	/* First Fatal */
 #define PCI_ERR_ROOT_NONFATAL_RCV	0x00000020	/* Non-Fatal Received */
 #define PCI_ERR_ROOT_NONFATAL_RCV	0x00000020	/* Non-Fatal Received */
 #define PCI_ERR_ROOT_FATAL_RCV		0x00000040	/* Fatal Received */
 #define PCI_ERR_ROOT_FATAL_RCV		0x00000040	/* Fatal Received */
-#define PCI_ERR_ROOT_COR_SRC	52
-#define PCI_ERR_ROOT_SRC	54
+#define PCI_ERR_ROOT_ERR_SRC	52	/* Error Source Identification */
 
 
 /* Virtual Channel */
 /* Virtual Channel */
 #define PCI_VC_PORT_REG1	4
 #define PCI_VC_PORT_REG1	4
@@ -662,4 +694,22 @@
 #define  PCI_SRIOV_VFM_MO	0x2	/* Active.MigrateOut */
 #define  PCI_SRIOV_VFM_MO	0x2	/* Active.MigrateOut */
 #define  PCI_SRIOV_VFM_AV	0x3	/* Active.Available */
 #define  PCI_SRIOV_VFM_AV	0x3	/* Active.Available */
 
 
+#define PCI_LTR_MAX_SNOOP_LAT	0x4
+#define PCI_LTR_MAX_NOSNOOP_LAT	0x6
+#define  PCI_LTR_VALUE_MASK	0x000003ff
+#define  PCI_LTR_SCALE_MASK	0x00001c00
+#define  PCI_LTR_SCALE_SHIFT	10
+
+/* Access Control Service */
+#define PCI_ACS_CAP		0x04	/* ACS Capability Register */
+#define  PCI_ACS_SV		0x01	/* Source Validation */
+#define  PCI_ACS_TB		0x02	/* Translation Blocking */
+#define  PCI_ACS_RR		0x04	/* P2P Request Redirect */
+#define  PCI_ACS_CR		0x08	/* P2P Completion Redirect */
+#define  PCI_ACS_UF		0x10	/* Upstream Forwarding */
+#define  PCI_ACS_EC		0x20	/* P2P Egress Control */
+#define  PCI_ACS_DT		0x40	/* Direct Translated P2P */
+#define PCI_ACS_CTRL		0x06	/* ACS Control Register */
+#define PCI_ACS_EGRESS_CTL_V	0x08	/* ACS Egress Control Vector */
+
 #endif /* LINUX_PCI_REGS_H */
 #endif /* LINUX_PCI_REGS_H */

+ 7 - 2
hw/pcie_aer.c

@@ -38,6 +38,9 @@
 #define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
 #define PCIE_DEV_PRINTF(dev, fmt, ...)                                  \
     PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
     PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
 
 
+#define PCI_ERR_SRC_COR_OFFS    0
+#define PCI_ERR_SRC_UNCOR_OFFS  2
+
 /* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
 /* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
 static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
 static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
 {
 {
@@ -320,7 +323,8 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
         if (root_status & PCI_ERR_ROOT_COR_RCV) {
         if (root_status & PCI_ERR_ROOT_COR_RCV) {
             root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
             root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
         } else {
         } else {
-            pci_set_word(aer_cap + PCI_ERR_ROOT_COR_SRC, msg->source_id);
+            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC + PCI_ERR_SRC_COR_OFFS,
+                         msg->source_id);
         }
         }
         root_status |= PCI_ERR_ROOT_COR_RCV;
         root_status |= PCI_ERR_ROOT_COR_RCV;
         break;
         break;
@@ -341,7 +345,8 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
         if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
         if (root_status & PCI_ERR_ROOT_UNCOR_RCV) {
             root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
             root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV;
         } else {
         } else {
-            pci_set_word(aer_cap + PCI_ERR_ROOT_SRC, msg->source_id);
+            pci_set_word(aer_cap + PCI_ERR_ROOT_ERR_SRC +
+                         PCI_ERR_SRC_UNCOR_OFFS, msg->source_id);
         }
         }
         root_status |= PCI_ERR_ROOT_UNCOR_RCV;
         root_status |= PCI_ERR_ROOT_UNCOR_RCV;
     }
     }

+ 4 - 4
hw/pcnet-pci.c

@@ -265,12 +265,8 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
 
 
     pci_conf = pci_dev->config;
     pci_conf = pci_dev->config;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
     pci_set_word(pci_conf + PCI_STATUS,
     pci_set_word(pci_conf + PCI_STATUS,
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_conf[PCI_REVISION_ID] = 0x10;
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
 
 
     pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
     pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
     pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
     pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
@@ -318,6 +314,10 @@ static PCIDeviceInfo pcnet_info = {
     .qdev.vmsd  = &vmstate_pci_pcnet,
     .qdev.vmsd  = &vmstate_pci_pcnet,
     .init       = pci_pcnet_init,
     .init       = pci_pcnet_init,
     .exit       = pci_pcnet_uninit,
     .exit       = pci_pcnet_uninit,
+    .vendor_id  = PCI_VENDOR_ID_AMD,
+    .device_id  = PCI_DEVICE_ID_AMD_LANCE,
+    .revision   = 0x10,
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
         DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
         DEFINE_PROP_END_OF_LIST(),
         DEFINE_PROP_END_OF_LIST(),

+ 3 - 7
hw/piix4.c

@@ -86,15 +86,8 @@ static const VMStateDescription vmstate_piix4 = {
 static int piix4_initfn(PCIDevice *dev)
 static int piix4_initfn(PCIDevice *dev)
 {
 {
     PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
     PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
-    uint8_t *pci_conf;
 
 
     isa_bus_new(&d->dev.qdev);
     isa_bus_new(&d->dev.qdev);
-
-    pci_conf = d->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
-
     piix4_dev = &d->dev;
     piix4_dev = &d->dev;
     qemu_register_reset(piix4_reset, d);
     qemu_register_reset(piix4_reset, d);
     return 0;
     return 0;
@@ -117,6 +110,9 @@ static PCIDeviceInfo piix4_info[] = {
         .qdev.no_user = 1,
         .qdev.no_user = 1,
         .no_hotplug   = 1,
         .no_hotplug   = 1,
         .init         = piix4_initfn,
         .init         = piix4_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_0, // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
     },{
     },{
         /* end of list */
         /* end of list */
     }
     }

+ 7 - 12
hw/piix_pci.c

@@ -232,11 +232,6 @@ static int i440fx_initfn(PCIDevice *dev)
 {
 {
     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
 
-    pci_config_set_vendor_id(d->dev.config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->dev.config, PCI_DEVICE_ID_INTEL_82441);
-    d->dev.config[0x08] = 0x02; // revision
-    pci_config_set_class(d->dev.config, PCI_CLASS_BRIDGE_HOST);
-
     d->dev.config[I440FX_SMRAM] = 0x02;
     d->dev.config[I440FX_SMRAM] = 0x02;
 
 
     cpu_smm_register(&i440fx_set_smm, d);
     cpu_smm_register(&i440fx_set_smm, d);
@@ -442,15 +437,8 @@ static const VMStateDescription vmstate_piix3 = {
 static int piix3_initfn(PCIDevice *dev)
 static int piix3_initfn(PCIDevice *dev)
 {
 {
     PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
     PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
-    uint8_t *pci_conf;
 
 
     isa_bus_new(&d->dev.qdev);
     isa_bus_new(&d->dev.qdev);
-
-    pci_conf = d->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_0); // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
-
     qemu_register_reset(piix3_reset, d);
     qemu_register_reset(piix3_reset, d);
     return 0;
     return 0;
 }
 }
@@ -465,6 +453,10 @@ static PCIDeviceInfo i440fx_info[] = {
         .no_hotplug   = 1,
         .no_hotplug   = 1,
         .init         = i440fx_initfn,
         .init         = i440fx_initfn,
         .config_write = i440fx_write_config,
         .config_write = i440fx_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82441,
+        .revision     = 0x02,
+        .class_id     = PCI_CLASS_BRIDGE_HOST,
     },{
     },{
         .qdev.name    = "PIIX3",
         .qdev.name    = "PIIX3",
         .qdev.desc    = "ISA bridge",
         .qdev.desc    = "ISA bridge",
@@ -474,6 +466,9 @@ static PCIDeviceInfo i440fx_info[] = {
         .no_hotplug   = 1,
         .no_hotplug   = 1,
         .init         = piix3_initfn,
         .init         = piix3_initfn,
         .config_write = piix3_write_config,
         .config_write = piix3_write_config,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+        .class_id     = PCI_CLASS_BRIDGE_ISA,
     },{
     },{
         .qdev.name    = "PIIX3-xen",
         .qdev.name    = "PIIX3-xen",
         .qdev.desc    = "ISA bridge",
         .qdev.desc    = "ISA bridge",

+ 3 - 10
hw/ppce500_pci.c

@@ -304,20 +304,13 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
     return 0;
     return 0;
 }
 }
 
 
-static int e500_host_bridge_initfn(PCIDevice *dev)
-{
-    pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_FREESCALE);
-    pci_config_set_device_id(dev->config, PCI_DEVICE_ID_MPC8533E);
-    pci_config_set_class(dev->config, PCI_CLASS_PROCESSOR_POWERPC);
-
-    return 0;
-}
-
 static PCIDeviceInfo e500_host_bridge_info = {
 static PCIDeviceInfo e500_host_bridge_info = {
     .qdev.name    = "e500-host-bridge",
     .qdev.name    = "e500-host-bridge",
     .qdev.desc    = "Host bridge",
     .qdev.desc    = "Host bridge",
     .qdev.size    = sizeof(PCIDevice),
     .qdev.size    = sizeof(PCIDevice),
-    .init         = e500_host_bridge_initfn,
+    .vendor_id    = PCI_VENDOR_ID_FREESCALE,
+    .device_id    = PCI_DEVICE_ID_MPC8533E,
+    .class_id     = PCI_CLASS_PROCESSOR_POWERPC,
 };
 };
 
 
 static SysBusDeviceInfo e500_pcihost_info = {
 static SysBusDeviceInfo e500_pcihost_info = {

+ 4 - 3
hw/qxl.c

@@ -1231,7 +1231,6 @@ static int qxl_init_common(PCIQXLDevice *qxl)
         break;
         break;
     }
     }
 
 
-    pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
     pci_config_set_device_id(config, pci_device_id);
     pci_config_set_device_id(config, pci_device_id);
     pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
     pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
     pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
     pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
@@ -1311,7 +1310,6 @@ static int qxl_init_primary(PCIDevice *dev)
     qxl0 = qxl;
     qxl0 = qxl;
     register_displaychangelistener(vga->ds, &display_listener);
     register_displaychangelistener(vga->ds, &display_listener);
 
 
-    pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_VGA);
     return qxl_init_common(qxl);
     return qxl_init_common(qxl);
 }
 }
 
 
@@ -1331,7 +1329,6 @@ static int qxl_init_secondary(PCIDevice *dev)
                                           qxl->vga.vram_size);
                                           qxl->vga.vram_size);
     qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
     qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
 
 
-    pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_OTHER);
     return qxl_init_common(qxl);
     return qxl_init_common(qxl);
 }
 }
 
 
@@ -1494,6 +1491,8 @@ static PCIDeviceInfo qxl_info_primary = {
     .init         = qxl_init_primary,
     .init         = qxl_init_primary,
     .config_write = qxl_write_config,
     .config_write = qxl_write_config,
     .romfile      = "vgabios-qxl.bin",
     .romfile      = "vgabios-qxl.bin",
+    .vendor_id    = REDHAT_PCI_VENDOR_ID,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
         DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
         DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
         DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
@@ -1512,6 +1511,8 @@ static PCIDeviceInfo qxl_info_secondary = {
     .qdev.reset   = qxl_reset_handler,
     .qdev.reset   = qxl_reset_handler,
     .qdev.vmsd    = &qxl_vmstate,
     .qdev.vmsd    = &qxl_vmstate,
     .init         = qxl_init_secondary,
     .init         = qxl_init_secondary,
+    .vendor_id    = REDHAT_PCI_VENDOR_ID,
+    .class_id     = PCI_CLASS_DISPLAY_OTHER,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
         DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
         DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
         DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),

+ 4 - 4
hw/rtl8139.c

@@ -3457,10 +3457,6 @@ static int pci_rtl8139_init(PCIDevice *dev)
     uint8_t *pci_conf;
     uint8_t *pci_conf;
 
 
     pci_conf = s->dev.config;
     pci_conf = s->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8139);
-    pci_conf[PCI_REVISION_ID] = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
     pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin 0 */
     pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin 0 */
     /* TODO: start of capability list, but no capability
     /* TODO: start of capability list, but no capability
      * list bit in status register, and offset 0xdc seems unused. */
      * list bit in status register, and offset 0xdc seems unused. */
@@ -3514,6 +3510,10 @@ static PCIDeviceInfo rtl8139_info = {
     .init       = pci_rtl8139_init,
     .init       = pci_rtl8139_init,
     .exit       = pci_rtl8139_uninit,
     .exit       = pci_rtl8139_uninit,
     .romfile    = "pxe-rtl8139.rom",
     .romfile    = "pxe-rtl8139.rom",
+    .vendor_id  = PCI_VENDOR_ID_REALTEK,
+    .device_id  = PCI_DEVICE_ID_REALTEK_8139,
+    .revision   = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */
+    .class_id   = PCI_CLASS_NETWORK_ETHERNET,
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(RTL8139State, conf),
         DEFINE_NIC_PROPERTIES(RTL8139State, conf),
         DEFINE_PROP_END_OF_LIST(),
         DEFINE_PROP_END_OF_LIST(),

+ 2 - 2
hw/sh_pci.c

@@ -137,8 +137,6 @@ static int sh_pci_init_device(SysBusDevice *dev)
 
 
 static int sh_pci_host_init(PCIDevice *d)
 static int sh_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_HITACHI);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_HITACHI_SH7751R);
     pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
     pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
     pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
     pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
@@ -149,6 +147,8 @@ static PCIDeviceInfo sh_pci_host_info = {
     .qdev.name = "sh_pci_host",
     .qdev.name = "sh_pci_host",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = sh_pci_host_init,
     .init      = sh_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_HITACHI,
+    .device_id = PCI_DEVICE_ID_HITACHI_SH7751R,
 };
 };
 
 
 static void sh_pci_register_devices(void)
 static void sh_pci_register_devices(void)

+ 4 - 4
hw/sun4u.c

@@ -553,15 +553,11 @@ pci_ebus_init1(PCIDevice *s)
 {
 {
     isa_bus_new(&s->qdev);
     isa_bus_new(&s->qdev);
 
 
-    pci_config_set_vendor_id(s->config, PCI_VENDOR_ID_SUN);
-    pci_config_set_device_id(s->config, PCI_DEVICE_ID_SUN_EBUS);
     s->config[0x04] = 0x06; // command = bus master, pci mem
     s->config[0x04] = 0x06; // command = bus master, pci mem
     s->config[0x05] = 0x00;
     s->config[0x05] = 0x00;
     s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
     s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
     s->config[0x07] = 0x03; // status = medium devsel
     s->config[0x07] = 0x03; // status = medium devsel
-    s->config[0x08] = 0x01; // revision
     s->config[0x09] = 0x00; // programming i/f
     s->config[0x09] = 0x00; // programming i/f
-    pci_config_set_class(s->config, PCI_CLASS_BRIDGE_OTHER);
     s->config[0x0D] = 0x0a; // latency_timer
     s->config[0x0D] = 0x0a; // latency_timer
 
 
     pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
     pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
@@ -575,6 +571,10 @@ static PCIDeviceInfo ebus_info = {
     .qdev.name = "ebus",
     .qdev.name = "ebus",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init = pci_ebus_init1,
     .init = pci_ebus_init1,
+    .vendor_id = PCI_VENDOR_ID_SUN,
+    .device_id = PCI_DEVICE_ID_SUN_EBUS,
+    .revision = 0x01,
+    .class_id = PCI_CLASS_BRIDGE_OTHER,
 };
 };
 
 
 static void pci_ebus_register(void)
 static void pci_ebus_register(void)

+ 3 - 1
hw/syborg_virtio.c

@@ -146,7 +146,9 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
             vdev->queue_sel = value;
             vdev->queue_sel = value;
         break;
         break;
     case SYBORG_VIRTIO_QUEUE_NOTIFY:
     case SYBORG_VIRTIO_QUEUE_NOTIFY:
-        virtio_queue_notify(vdev, value);
+        if (value < VIRTIO_PCI_QUEUE_MAX) {
+            virtio_queue_notify(vdev, value);
+        }
         break;
         break;
     case SYBORG_VIRTIO_STATUS:
     case SYBORG_VIRTIO_STATUS:
         virtio_set_status(vdev, value & 0xFF);
         virtio_set_status(vdev, value & 0xFF);

+ 16 - 17
hw/unin_pci.c

@@ -279,10 +279,6 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic)
 
 
 static int unin_main_pci_host_init(PCIDevice *d)
 static int unin_main_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_PCI);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x34] = 0x00; // capabilities_pointer
     d->config[0x34] = 0x00; // capabilities_pointer
@@ -291,10 +287,6 @@ static int unin_main_pci_host_init(PCIDevice *d)
 
 
 static int unin_agp_pci_host_init(PCIDevice *d)
 static int unin_agp_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_AGP);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x0D] = 0x10; // latency_timer
     //    d->config[0x34] = 0x80; // capabilities_pointer
     //    d->config[0x34] = 0x80; // capabilities_pointer
@@ -303,11 +295,6 @@ static int unin_agp_pci_host_init(PCIDevice *d)
 
 
 static int u3_agp_pci_host_init(PCIDevice *d)
 static int u3_agp_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_U3_AGP);
-    /* revision */
-    d->config[0x08] = 0x00;
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     /* cache line size */
     /* cache line size */
     d->config[0x0C] = 0x08;
     d->config[0x0C] = 0x08;
     /* latency timer */
     /* latency timer */
@@ -317,10 +304,6 @@ static int u3_agp_pci_host_init(PCIDevice *d)
 
 
 static int unin_internal_pci_host_init(PCIDevice *d)
 static int unin_internal_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_I_PCI);
-    d->config[0x08] = 0x00; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0C] = 0x08; // cache_line_size
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x0D] = 0x10; // latency_timer
     d->config[0x34] = 0x00; // capabilities_pointer
     d->config[0x34] = 0x00; // capabilities_pointer
@@ -331,24 +314,40 @@ static PCIDeviceInfo unin_main_pci_host_info = {
     .qdev.name = "uni-north",
     .qdev.name = "uni-north",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_main_pci_host_init,
     .init      = unin_main_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 };
 
 
 static PCIDeviceInfo u3_agp_pci_host_info = {
 static PCIDeviceInfo u3_agp_pci_host_info = {
     .qdev.name = "u3-agp",
     .qdev.name = "u3-agp",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = u3_agp_pci_host_init,
     .init      = u3_agp_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 };
 
 
 static PCIDeviceInfo unin_agp_pci_host_info = {
 static PCIDeviceInfo unin_agp_pci_host_info = {
     .qdev.name = "uni-north-agp",
     .qdev.name = "uni-north-agp",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_agp_pci_host_init,
     .init      = unin_agp_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 };
 
 
 static PCIDeviceInfo unin_internal_pci_host_info = {
 static PCIDeviceInfo unin_internal_pci_host_info = {
     .qdev.name = "uni-north-pci",
     .qdev.name = "uni-north-pci",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_internal_pci_host_init,
     .init      = unin_internal_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI,
+    .revision  = 0x00,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 };
 
 
 static void unin_register_devices(void)
 static void unin_register_devices(void)

+ 4 - 5
hw/usb-ehci.c

@@ -2142,6 +2142,10 @@ static PCIDeviceInfo ehci_info = {
     .qdev.name    = "usb-ehci",
     .qdev.name    = "usb-ehci",
     .qdev.size    = sizeof(EHCIState),
     .qdev.size    = sizeof(EHCIState),
     .init         = usb_ehci_initfn,
     .init         = usb_ehci_initfn,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = PCI_DEVICE_ID_INTEL_82801D,
+    .revision     = 0x10,
+    .class_id     = PCI_CLASS_SERIAL_USB,
 };
 };
 
 
 static int usb_ehci_initfn(PCIDevice *dev)
 static int usb_ehci_initfn(PCIDevice *dev)
@@ -2150,12 +2154,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
     uint8_t *pci_conf = s->dev.config;
     uint8_t *pci_conf = s->dev.config;
     int i;
     int i;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82801D);
-    pci_set_byte(&pci_conf[PCI_REVISION_ID], 0x10);
     pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
     pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-    pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
-    pci_set_byte(&pci_conf[PCI_HEADER_TYPE], PCI_HEADER_TYPE_NORMAL);
 
 
     /* capabilities pointer */
     /* capabilities pointer */
     pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
     pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);

+ 3 - 4
hw/usb-ohci.c

@@ -1748,11 +1748,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev)
     OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
     OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
     int num_ports = 3;
     int num_ports = 3;
 
 
-    pci_config_set_vendor_id(ohci->pci_dev.config, PCI_VENDOR_ID_APPLE);
-    pci_config_set_device_id(ohci->pci_dev.config,
-                             PCI_DEVICE_ID_APPLE_IPID_USB);
     ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
     ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
-    pci_config_set_class(ohci->pci_dev.config, PCI_CLASS_SERIAL_USB);
     /* TODO: RST# value should be 0. */
     /* TODO: RST# value should be 0. */
     ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
     ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
 
 
@@ -1792,6 +1788,9 @@ static PCIDeviceInfo ohci_pci_info = {
     .qdev.desc    = "Apple USB Controller",
     .qdev.desc    = "Apple USB Controller",
     .qdev.size    = sizeof(OHCIPCIState),
     .qdev.size    = sizeof(OHCIPCIState),
     .init         = usb_ohci_initfn_pci,
     .init         = usb_ohci_initfn_pci,
+    .vendor_id    = PCI_VENDOR_ID_APPLE,
+    .device_id    = PCI_DEVICE_ID_APPLE_IPID_USB,
+    .class_id     = PCI_CLASS_SERIAL_USB,
 };
 };
 
 
 static SysBusDeviceInfo ohci_sysbus_info = {
 static SysBusDeviceInfo ohci_sysbus_info = {

+ 17 - 29
hw/usb-uhci.c

@@ -1114,14 +1114,13 @@ static USBBusOps uhci_bus_ops = {
     .device_destroy = uhci_device_destroy,
     .device_destroy = uhci_device_destroy,
 };
 };
 
 
-static int usb_uhci_common_initfn(UHCIState *s)
+static int usb_uhci_common_initfn(PCIDevice *dev)
 {
 {
+    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
     uint8_t *pci_conf = s->dev.config;
     uint8_t *pci_conf = s->dev.config;
     int i;
     int i;
 
 
-    pci_conf[PCI_REVISION_ID] = 0x01; // revision number
     pci_conf[PCI_CLASS_PROG] = 0x00;
     pci_conf[PCI_CLASS_PROG] = 0x00;
-    pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
     /* TODO: reset value should be 0. */
     /* TODO: reset value should be 0. */
     pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
     pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
     pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
     pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
@@ -1146,34 +1145,11 @@ static int usb_uhci_common_initfn(UHCIState *s)
     return 0;
     return 0;
 }
 }
 
 
-static int usb_uhci_piix3_initfn(PCIDevice *dev)
-{
-    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
-    uint8_t *pci_conf = s->dev.config;
-
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_2);
-    return usb_uhci_common_initfn(s);
-}
-
-static int usb_uhci_piix4_initfn(PCIDevice *dev)
-{
-    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
-    uint8_t *pci_conf = s->dev.config;
-
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_2);
-    return usb_uhci_common_initfn(s);
-}
-
 static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
 static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
 {
 {
     UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
     UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
     uint8_t *pci_conf = s->dev.config;
     uint8_t *pci_conf = s->dev.config;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_UHCI);
-
     /* USB misc control 1/2 */
     /* USB misc control 1/2 */
     pci_set_long(pci_conf + 0x40,0x00001000);
     pci_set_long(pci_conf + 0x40,0x00001000);
     /* PM capability */
     /* PM capability */
@@ -1181,7 +1157,7 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
     /* USB legacy support  */
     /* USB legacy support  */
     pci_set_long(pci_conf + 0xc0,0x00002000);
     pci_set_long(pci_conf + 0xc0,0x00002000);
 
 
-    return usb_uhci_common_initfn(s);
+    return usb_uhci_common_initfn(dev);
 }
 }
 
 
 static PCIDeviceInfo uhci_info[] = {
 static PCIDeviceInfo uhci_info[] = {
@@ -1189,17 +1165,29 @@ static PCIDeviceInfo uhci_info[] = {
         .qdev.name    = "piix3-usb-uhci",
         .qdev.name    = "piix3-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
         .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_piix3_initfn,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_2,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
     },{
     },{
         .qdev.name    = "piix4-usb-uhci",
         .qdev.name    = "piix4-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
         .qdev.vmsd    = &vmstate_uhci,
-        .init         = usb_uhci_piix4_initfn,
+        .init         = usb_uhci_common_initfn,
+        .vendor_id    = PCI_VENDOR_ID_INTEL,
+        .device_id    = PCI_DEVICE_ID_INTEL_82371AB_2,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
     },{
     },{
         .qdev.name    = "vt82c686b-usb-uhci",
         .qdev.name    = "vt82c686b-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
         .qdev.vmsd    = &vmstate_uhci,
         .init         = usb_uhci_vt82c686b_initfn,
         .init         = usb_uhci_vt82c686b_initfn,
+        .vendor_id    = PCI_VENDOR_ID_VIA,
+        .device_id    = PCI_DEVICE_ID_VIA_UHCI,
+        .revision     = 0x01,
+        .class_id     = PCI_CLASS_SERIAL_USB,
     },{
     },{
         /* end of list */
         /* end of list */
     }
     }

+ 4 - 4
hw/versatile_pci.c

@@ -133,12 +133,8 @@ static int pci_realview_init(SysBusDevice *dev)
 
 
 static int versatile_pci_host_init(PCIDevice *d)
 static int versatile_pci_host_init(PCIDevice *d)
 {
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_XILINX);
-    /* Both boards have the same device ID.  Oh well.  */
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_XILINX_XC2VP30);
     pci_set_word(d->config + PCI_STATUS,
     pci_set_word(d->config + PCI_STATUS,
 		 PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
 		 PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_CO);
     pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
     pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
     return 0;
     return 0;
 }
 }
@@ -147,6 +143,10 @@ static PCIDeviceInfo versatile_pci_host_info = {
     .qdev.name = "versatile_pci_host",
     .qdev.name = "versatile_pci_host",
     .qdev.size = sizeof(PCIDevice),
     .qdev.size = sizeof(PCIDevice),
     .init      = versatile_pci_host_init,
     .init      = versatile_pci_host_init,
+    .vendor_id = PCI_VENDOR_ID_XILINX,
+    /* Both boards have the same device ID.  Oh well.  */
+    .device_id = PCI_DEVICE_ID_XILINX_XC2VP30,
+    .class_id  = PCI_CLASS_PROCESSOR_CO,
 };
 };
 
 
 static void versatile_pci_register_devices(void)
 static void versatile_pci_register_devices(void)

+ 5 - 6
hw/vga-pci.c

@@ -74,7 +74,6 @@ static int pci_vga_initfn(PCIDevice *dev)
 {
 {
      PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
      PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
      VGACommonState *s = &d->vga;
      VGACommonState *s = &d->vga;
-     uint8_t *pci_conf = d->dev.config;
 
 
      // vga + console init
      // vga + console init
      vga_common_init(s, VGA_RAM_SIZE);
      vga_common_init(s, VGA_RAM_SIZE);
@@ -83,11 +82,6 @@ static int pci_vga_initfn(PCIDevice *dev)
      s->ds = graphic_console_init(s->update, s->invalidate,
      s->ds = graphic_console_init(s->update, s->invalidate,
                                   s->screen_dump, s->text_update, s);
                                   s->screen_dump, s->text_update, s);
 
 
-     // dummy VGA (same as Bochs ID)
-     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
-     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
-     pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
-
      /* XXX: VGA_RAM_SIZE must be a power of two */
      /* XXX: VGA_RAM_SIZE must be a power of two */
      pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
      pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
                       PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
                       PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
@@ -114,6 +108,11 @@ static PCIDeviceInfo vga_info = {
     .init         = pci_vga_initfn,
     .init         = pci_vga_initfn,
     .config_write = pci_vga_write_config,
     .config_write = pci_vga_write_config,
     .romfile      = "vgabios-stdvga.bin",
     .romfile      = "vgabios-stdvga.bin",
+
+    /* dummy VGA (same as Bochs ID) */
+    .vendor_id    = PCI_VENDOR_ID_QEMU,
+    .device_id    = PCI_DEVICE_ID_QEMU_VGA,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
 };
 };
 
 
 static void vga_register(void)
 static void vga_register(void)

+ 8 - 0
hw/vhost_net.c

@@ -15,6 +15,7 @@
 
 
 #include "virtio-net.h"
 #include "virtio-net.h"
 #include "vhost_net.h"
 #include "vhost_net.h"
+#include "qemu-error.h"
 
 
 #include "config.h"
 #include "config.h"
 
 
@@ -50,6 +51,9 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
     if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
     if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
         features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
         features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
     }
     }
+    if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
+    }
     if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
     if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
         features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
         features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
     }
     }
@@ -65,6 +69,9 @@ void vhost_net_ack_features(struct vhost_net *net, unsigned features)
     if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
     if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
         net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
         net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
     }
     }
+    if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
+    }
     if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
     if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
         net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
     }
     }
@@ -197,6 +204,7 @@ void vhost_net_cleanup(struct vhost_net *net)
 struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
 struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
                                  bool force)
                                  bool force)
 {
 {
+    error_report("vhost-net support is not compiled in");
     return NULL;
     return NULL;
 }
 }
 
 

+ 29 - 37
hw/virtio-pci.c

@@ -75,9 +75,6 @@
                                          VIRTIO_PCI_CONFIG_MSI : \
                                          VIRTIO_PCI_CONFIG_MSI : \
                                          VIRTIO_PCI_CONFIG_NOMSI)
                                          VIRTIO_PCI_CONFIG_NOMSI)
 
 
-/* Virtio ABI version, if we increment this, we break the guest driver. */
-#define VIRTIO_PCI_ABI_VERSION          0
-
 /* How many bits to shift physical queue address written to QUEUE_PFN.
 /* How many bits to shift physical queue address written to QUEUE_PFN.
  * 12 is historical, and due to x86 page size. */
  * 12 is historical, and due to x86 page size. */
 #define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
 #define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
@@ -328,7 +325,9 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             vdev->queue_sel = val;
             vdev->queue_sel = val;
         break;
         break;
     case VIRTIO_PCI_QUEUE_NOTIFY:
     case VIRTIO_PCI_QUEUE_NOTIFY:
-        virtio_queue_notify(vdev, val);
+        if (val < VIRTIO_PCI_QUEUE_MAX) {
+            virtio_queue_notify(vdev, val);
+        }
         break;
         break;
     case VIRTIO_PCI_STATUS:
     case VIRTIO_PCI_STATUS:
         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
@@ -649,9 +648,7 @@ static const VirtIOBindings virtio_pci_bindings = {
     .vmstate_change = virtio_pci_vmstate_change,
     .vmstate_change = virtio_pci_vmstate_change,
 };
 };
 
 
-void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
-                            uint16_t vendor, uint16_t device,
-                            uint16_t class_code, uint8_t pif)
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
 {
 {
     uint8_t *config;
     uint8_t *config;
     uint32_t size;
     uint32_t size;
@@ -659,19 +656,12 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
     proxy->vdev = vdev;
     proxy->vdev = vdev;
 
 
     config = proxy->pci_dev.config;
     config = proxy->pci_dev.config;
-    pci_config_set_vendor_id(config, vendor);
-    pci_config_set_device_id(config, device);
-
-    config[0x08] = VIRTIO_PCI_ABI_VERSION;
-
-    config[0x09] = pif;
-    pci_config_set_class(config, class_code);
-
-    config[0x2c] = vendor & 0xFF;
-    config[0x2d] = (vendor >> 8) & 0xFF;
-    config[0x2e] = vdev->device_id & 0xFF;
-    config[0x2f] = (vdev->device_id >> 8) & 0xFF;
 
 
+    if (proxy->class_code) {
+        pci_config_set_class(config, proxy->class_code);
+    }
+    pci_set_word(config + 0x2c, pci_get_word(config + PCI_VENDOR_ID));
+    pci_set_word(config + 0x2e, vdev->device_id);
     config[0x3d] = 1;
     config[0x3d] = 1;
 
 
     if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
     if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
@@ -715,10 +705,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
         return -1;
         return -1;
     }
     }
     vdev->nvectors = proxy->nvectors;
     vdev->nvectors = proxy->nvectors;
-    virtio_init_pci(proxy, vdev,
-                    PCI_VENDOR_ID_REDHAT_QUMRANET,
-                    PCI_DEVICE_ID_VIRTIO_BLOCK,
-                    proxy->class_code, 0x00);
+    virtio_init_pci(proxy, vdev);
     /* make the actual value visible */
     /* make the actual value visible */
     proxy->nvectors = vdev->nvectors;
     proxy->nvectors = vdev->nvectors;
     return 0;
     return 0;
@@ -756,10 +743,7 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev)
     vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
     vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
                                         ? proxy->serial.max_virtserial_ports + 1
                                         ? proxy->serial.max_virtserial_ports + 1
                                         : proxy->nvectors;
                                         : proxy->nvectors;
-    virtio_init_pci(proxy, vdev,
-                    PCI_VENDOR_ID_REDHAT_QUMRANET,
-                    PCI_DEVICE_ID_VIRTIO_CONSOLE,
-                    proxy->class_code, 0x00);
+    virtio_init_pci(proxy, vdev);
     proxy->nvectors = vdev->nvectors;
     proxy->nvectors = vdev->nvectors;
     return 0;
     return 0;
 }
 }
@@ -781,11 +765,7 @@ static int virtio_net_init_pci(PCIDevice *pci_dev)
     vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
     vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
 
 
     vdev->nvectors = proxy->nvectors;
     vdev->nvectors = proxy->nvectors;
-    virtio_init_pci(proxy, vdev,
-                    PCI_VENDOR_ID_REDHAT_QUMRANET,
-                    PCI_DEVICE_ID_VIRTIO_NET,
-                    PCI_CLASS_NETWORK_ETHERNET,
-                    0x00);
+    virtio_init_pci(proxy, vdev);
 
 
     /* make the actual value visible */
     /* make the actual value visible */
     proxy->nvectors = vdev->nvectors;
     proxy->nvectors = vdev->nvectors;
@@ -807,11 +787,7 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
     VirtIODevice *vdev;
     VirtIODevice *vdev;
 
 
     vdev = virtio_balloon_init(&pci_dev->qdev);
     vdev = virtio_balloon_init(&pci_dev->qdev);
-    virtio_init_pci(proxy, vdev,
-                    PCI_VENDOR_ID_REDHAT_QUMRANET,
-                    PCI_DEVICE_ID_VIRTIO_BALLOON,
-                    PCI_CLASS_MEMORY_RAM,
-                    0x00);
+    virtio_init_pci(proxy, vdev);
     return 0;
     return 0;
 }
 }
 
 
@@ -822,6 +798,10 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.size = sizeof(VirtIOPCIProxy),
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_blk_init_pci,
         .init      = virtio_blk_init_pci,
         .exit      = virtio_blk_exit_pci,
         .exit      = virtio_blk_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_BLOCK,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_STORAGE_SCSI,
         .qdev.props = (Property[]) {
         .qdev.props = (Property[]) {
             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
             DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
             DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
@@ -839,6 +819,10 @@ static PCIDeviceInfo virtio_info[] = {
         .init       = virtio_net_init_pci,
         .init       = virtio_net_init_pci,
         .exit       = virtio_net_exit_pci,
         .exit       = virtio_net_exit_pci,
         .romfile    = "pxe-virtio.rom",
         .romfile    = "pxe-virtio.rom",
+        .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id  = PCI_DEVICE_ID_VIRTIO_NET,
+        .revision   = VIRTIO_PCI_ABI_VERSION,
+        .class_id   = PCI_CLASS_NETWORK_ETHERNET,
         .qdev.props = (Property[]) {
         .qdev.props = (Property[]) {
             DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
             DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
                             VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
                             VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
@@ -859,6 +843,10 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.size = sizeof(VirtIOPCIProxy),
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_serial_init_pci,
         .init      = virtio_serial_init_pci,
         .exit      = virtio_serial_exit_pci,
         .exit      = virtio_serial_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_COMMUNICATION_OTHER,
         .qdev.props = (Property[]) {
         .qdev.props = (Property[]) {
             DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
             DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
                             VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
                             VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
@@ -877,6 +865,10 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.size = sizeof(VirtIOPCIProxy),
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_balloon_init_pci,
         .init      = virtio_balloon_init_pci,
         .exit      = virtio_exit_pci,
         .exit      = virtio_exit_pci,
+        .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+        .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
+        .revision  = VIRTIO_PCI_ABI_VERSION,
+        .class_id  = PCI_CLASS_MEMORY_RAM,
         .qdev.props = (Property[]) {
         .qdev.props = (Property[]) {
             DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_PROP_END_OF_LIST(),
             DEFINE_PROP_END_OF_LIST(),

+ 5 - 3
hw/virtio-pci.h

@@ -37,7 +37,9 @@ typedef struct {
     bool ioeventfd_started;
     bool ioeventfd_started;
 } VirtIOPCIProxy;
 } VirtIOPCIProxy;
 
 
-extern void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
-                            uint16_t vendor, uint16_t device,
-                            uint16_t class_code, uint8_t pif);
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
+
+/* Virtio ABI version, if we increment this, we break the guest driver. */
+#define VIRTIO_PCI_ABI_VERSION          0
+
 #endif
 #endif

+ 85 - 12
hw/virtio.c

@@ -71,7 +71,17 @@ struct VirtQueue
     VRing vring;
     VRing vring;
     target_phys_addr_t pa;
     target_phys_addr_t pa;
     uint16_t last_avail_idx;
     uint16_t last_avail_idx;
+    /* Last used index value we have signalled on */
+    uint16_t signalled_used;
+
+    /* Last used index value we have signalled on */
+    bool signalled_used_valid;
+
+    /* Notification enabled? */
+    bool notification;
+
     int inuse;
     int inuse;
+
     uint16_t vector;
     uint16_t vector;
     void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
     void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
     VirtIODevice *vdev;
     VirtIODevice *vdev;
@@ -140,6 +150,11 @@ static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
     return lduw_phys(pa);
     return lduw_phys(pa);
 }
 }
 
 
+static inline uint16_t vring_used_event(VirtQueue *vq)
+{
+    return vring_avail_ring(vq, vq->vring.num);
+}
+
 static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
 static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
 {
 {
     target_phys_addr_t pa;
     target_phys_addr_t pa;
@@ -161,11 +176,11 @@ static uint16_t vring_used_idx(VirtQueue *vq)
     return lduw_phys(pa);
     return lduw_phys(pa);
 }
 }
 
 
-static inline void vring_used_idx_increment(VirtQueue *vq, uint16_t val)
+static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
 {
 {
     target_phys_addr_t pa;
     target_phys_addr_t pa;
     pa = vq->vring.used + offsetof(VRingUsed, idx);
     pa = vq->vring.used + offsetof(VRingUsed, idx);
-    stw_phys(pa, vring_used_idx(vq) + val);
+    stw_phys(pa, val);
 }
 }
 
 
 static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
 static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
@@ -182,12 +197,26 @@ static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
     stw_phys(pa, lduw_phys(pa) & ~mask);
     stw_phys(pa, lduw_phys(pa) & ~mask);
 }
 }
 
 
+static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
+{
+    target_phys_addr_t pa;
+    if (!vq->notification) {
+        return;
+    }
+    pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
+    stw_phys(pa, val);
+}
+
 void virtio_queue_set_notification(VirtQueue *vq, int enable)
 void virtio_queue_set_notification(VirtQueue *vq, int enable)
 {
 {
-    if (enable)
+    vq->notification = enable;
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    } else if (enable) {
         vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
         vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
-    else
+    } else {
         vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
         vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
+    }
 }
 }
 
 
 int virtio_queue_ready(VirtQueue *vq)
 int virtio_queue_ready(VirtQueue *vq)
@@ -233,11 +262,16 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
 
 
 void virtqueue_flush(VirtQueue *vq, unsigned int count)
 void virtqueue_flush(VirtQueue *vq, unsigned int count)
 {
 {
+    uint16_t old, new;
     /* Make sure buffer is written before we update index. */
     /* Make sure buffer is written before we update index. */
     wmb();
     wmb();
     trace_virtqueue_flush(vq, count);
     trace_virtqueue_flush(vq, count);
-    vring_used_idx_increment(vq, count);
+    old = vring_used_idx(vq);
+    new = old + count;
+    vring_used_idx_set(vq, new);
     vq->inuse -= count;
     vq->inuse -= count;
+    if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
+        vq->signalled_used_valid = false;
 }
 }
 
 
 void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
 void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
@@ -394,6 +428,9 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
     max = vq->vring.num;
     max = vq->vring.num;
 
 
     i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
     i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    }
 
 
     if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
     if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
         if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
         if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
@@ -477,6 +514,9 @@ void virtio_reset(void *opaque)
         vdev->vq[i].last_avail_idx = 0;
         vdev->vq[i].last_avail_idx = 0;
         vdev->vq[i].pa = 0;
         vdev->vq[i].pa = 0;
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+        vdev->vq[i].signalled_used = 0;
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
     }
     }
 }
 }
 
 
@@ -585,9 +625,7 @@ void virtio_queue_notify_vq(VirtQueue *vq)
 
 
 void virtio_queue_notify(VirtIODevice *vdev, int n)
 void virtio_queue_notify(VirtIODevice *vdev, int n)
 {
 {
-    if (n < VIRTIO_PCI_QUEUE_MAX) {
-        virtio_queue_notify_vq(&vdev->vq[n]);
-    }
+    virtio_queue_notify_vq(&vdev->vq[n]);
 }
 }
 
 
 uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
 uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
@@ -628,13 +666,45 @@ void virtio_irq(VirtQueue *vq)
     virtio_notify_vector(vq->vdev, vq->vector);
     virtio_notify_vector(vq->vdev, vq->vector);
 }
 }
 
 
-void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static inline int vring_need_event(uint16_t event, uint16_t new, uint16_t old)
+{
+	/* Note: Xen has similar logic for notification hold-off
+	 * in include/xen/interface/io/ring.h with req_event and req_prod
+	 * corresponding to event_idx + 1 and new respectively.
+	 * Note also that req_event and req_prod in Xen start at 1,
+	 * event indexes in virtio start at 0. */
+	return (uint16_t)(new - event - 1) < (uint16_t)(new - old);
+}
+
+static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
 {
 {
+    uint16_t old, new;
+    bool v;
     /* Always notify when queue is empty (when feature acknowledge) */
     /* Always notify when queue is empty (when feature acknowledge) */
-    if ((vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT) &&
-        (!(vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) ||
-         (vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
+    if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
+         !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
+        return true;
+    }
+
+    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
+    }
+
+    v = vq->signalled_used_valid;
+    vq->signalled_used_valid = true;
+    old = vq->signalled_used;
+    new = vq->signalled_used = vring_used_idx(vq);
+    return !v || vring_need_event(vring_used_event(vq), new, old);
+}
+
+void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
+{
+    if (!vring_notify(vdev, vq)) {
         return;
         return;
+    }
 
 
     trace_virtio_notify(vdev, vq);
     trace_virtio_notify(vdev, vq);
     vdev->isr |= 0x01;
     vdev->isr |= 0x01;
@@ -717,6 +787,8 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
         vdev->vq[i].vring.num = qemu_get_be32(f);
         vdev->vq[i].vring.num = qemu_get_be32(f);
         vdev->vq[i].pa = qemu_get_be64(f);
         vdev->vq[i].pa = qemu_get_be64(f);
         qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
         qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
 
 
         if (vdev->vq[i].pa) {
         if (vdev->vq[i].pa) {
             uint16_t nheads;
             uint16_t nheads;
@@ -789,6 +861,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
     vdev->queue_sel = 0;
     vdev->queue_sel = 0;
     vdev->config_vector = VIRTIO_NO_VECTOR;
     vdev->config_vector = VIRTIO_NO_VECTOR;
     vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
     vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
+    vdev->vm_running = vm_running;
     for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
     for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
         vdev->vq[i].vdev = vdev;
         vdev->vq[i].vdev = vdev;

+ 8 - 1
hw/virtio.h

@@ -46,6 +46,11 @@
 #define VIRTIO_F_NOTIFY_ON_EMPTY        24
 #define VIRTIO_F_NOTIFY_ON_EMPTY        24
 /* We support indirect buffer descriptors */
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC     28
 #define VIRTIO_RING_F_INDIRECT_DESC     28
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX         29
 /* A guest should never accept this.  It implies negotiation is broken. */
 /* A guest should never accept this.  It implies negotiation is broken. */
 #define VIRTIO_F_BAD_FEATURE		30
 #define VIRTIO_F_BAD_FEATURE		30
 
 
@@ -210,7 +215,9 @@ void virtio_serial_exit(VirtIODevice *vdev);
 
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
-			VIRTIO_RING_F_INDIRECT_DESC, true)
+			VIRTIO_RING_F_INDIRECT_DESC, true), \
+	DEFINE_PROP_BIT("event_idx", _state, _field, \
+			VIRTIO_RING_F_EVENT_IDX, true)
 
 
 target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
 target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
 target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
 target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);

+ 6 - 7
hw/vmware_vga.c

@@ -1280,15 +1280,8 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
     struct pci_vmsvga_state_s *s =
     struct pci_vmsvga_state_s *s =
         DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
         DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
 
 
-    pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
-    pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
-    pci_config_set_class(s->card.config, PCI_CLASS_DISPLAY_VGA);
     s->card.config[PCI_CACHE_LINE_SIZE]	= 0x08;		/* Cache line size */
     s->card.config[PCI_CACHE_LINE_SIZE]	= 0x08;		/* Cache line size */
     s->card.config[PCI_LATENCY_TIMER] = 0x40;		/* Latency timer */
     s->card.config[PCI_LATENCY_TIMER] = 0x40;		/* Latency timer */
-    s->card.config[PCI_SUBSYSTEM_VENDOR_ID] = PCI_VENDOR_ID_VMWARE & 0xff;
-    s->card.config[PCI_SUBSYSTEM_VENDOR_ID + 1]	= PCI_VENDOR_ID_VMWARE >> 8;
-    s->card.config[PCI_SUBSYSTEM_ID] = SVGA_PCI_DEVICE_ID & 0xff;
-    s->card.config[PCI_SUBSYSTEM_ID + 1] = SVGA_PCI_DEVICE_ID >> 8;
     s->card.config[PCI_INTERRUPT_LINE] = 0xff;		/* End */
     s->card.config[PCI_INTERRUPT_LINE] = 0xff;		/* End */
 
 
     pci_register_bar(&s->card, 0, 0x10,
     pci_register_bar(&s->card, 0, 0x10,
@@ -1316,6 +1309,12 @@ static PCIDeviceInfo vmsvga_info = {
     .no_hotplug   = 1,
     .no_hotplug   = 1,
     .init         = pci_vmsvga_initfn,
     .init         = pci_vmsvga_initfn,
     .romfile      = "vgabios-vmware.bin",
     .romfile      = "vgabios-vmware.bin",
+
+    .vendor_id    =  PCI_VENDOR_ID_VMWARE,
+    .device_id    = SVGA_PCI_DEVICE_ID,
+    .class_id     = PCI_CLASS_DISPLAY_VGA,
+    .subsystem_vendor_id = PCI_VENDOR_ID_VMWARE,
+    .subsystem_id = SVGA_PCI_DEVICE_ID,
 };
 };
 
 
 static void vmsvga_register(void)
 static void vmsvga_register(void)

+ 16 - 19
hw/vt82c686.c

@@ -326,11 +326,6 @@ static int vt82c686b_ac97_initfn(PCIDevice *dev)
     VT686AC97State *s = DO_UPCAST(VT686AC97State, dev, dev);
     VT686AC97State *s = DO_UPCAST(VT686AC97State, dev, dev);
     uint8_t *pci_conf = s->dev.config;
     uint8_t *pci_conf = s->dev.config;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_AC97);
-    pci_config_set_class(pci_conf, PCI_CLASS_MULTIMEDIA_AUDIO);
-    pci_config_set_revision(pci_conf, 0x50);
-
     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
                  PCI_COMMAND_PARITY);
                  PCI_COMMAND_PARITY);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST |
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST |
@@ -353,6 +348,10 @@ static PCIDeviceInfo via_ac97_info = {
     .qdev.desc          = "AC97",
     .qdev.desc          = "AC97",
     .qdev.size          = sizeof(VT686AC97State),
     .qdev.size          = sizeof(VT686AC97State),
     .init               = vt82c686b_ac97_initfn,
     .init               = vt82c686b_ac97_initfn,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_AC97,
+    .revision           = 0x50,
+    .class_id           = PCI_CLASS_MULTIMEDIA_AUDIO,
 };
 };
 
 
 static void vt82c686b_ac97_register(void)
 static void vt82c686b_ac97_register(void)
@@ -367,11 +366,6 @@ static int vt82c686b_mc97_initfn(PCIDevice *dev)
     VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
     VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
     uint8_t *pci_conf = s->dev.config;
     uint8_t *pci_conf = s->dev.config;
 
 
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_MC97);
-    pci_config_set_class(pci_conf, PCI_CLASS_COMMUNICATION_OTHER);
-    pci_config_set_revision(pci_conf, 0x30);
-
     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
                  PCI_COMMAND_VGA_PALETTE);
                  PCI_COMMAND_VGA_PALETTE);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
@@ -393,6 +387,10 @@ static PCIDeviceInfo via_mc97_info = {
     .qdev.desc          = "MC97",
     .qdev.desc          = "MC97",
     .qdev.size          = sizeof(VT686MC97State),
     .qdev.size          = sizeof(VT686MC97State),
     .init               = vt82c686b_mc97_initfn,
     .init               = vt82c686b_mc97_initfn,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_MC97,
+    .class_id           = PCI_CLASS_COMMUNICATION_OTHER,
+    .revision           = 0x30,
 };
 };
 
 
 static void vt82c686b_mc97_register(void)
 static void vt82c686b_mc97_register(void)
@@ -409,11 +407,6 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
     uint8_t *pci_conf;
     uint8_t *pci_conf;
 
 
     pci_conf = s->dev.config;
     pci_conf = s->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_ACPI);
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
-    pci_config_set_revision(pci_conf, 0x40);
-
     pci_set_word(pci_conf + PCI_COMMAND, 0);
     pci_set_word(pci_conf + PCI_COMMAND, 0);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
                  PCI_STATUS_DEVSEL_MEDIUM);
                  PCI_STATUS_DEVSEL_MEDIUM);
@@ -462,6 +455,10 @@ static PCIDeviceInfo via_pm_info = {
     .qdev.vmsd          = &vmstate_acpi,
     .qdev.vmsd          = &vmstate_acpi,
     .init               = vt82c686b_pm_initfn,
     .init               = vt82c686b_pm_initfn,
     .config_write       = pm_write_config,
     .config_write       = pm_write_config,
+    .vendor_id          = PCI_VENDOR_ID_VIA,
+    .device_id          = PCI_DEVICE_ID_VIA_ACPI,
+    .class_id           = PCI_CLASS_BRIDGE_OTHER,
+    .revision           = 0x40,
     .qdev.props         = (Property[]) {
     .qdev.props         = (Property[]) {
         DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
         DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
         DEFINE_PROP_END_OF_LIST(),
         DEFINE_PROP_END_OF_LIST(),
@@ -496,11 +493,7 @@ static int vt82c686b_initfn(PCIDevice *d)
     isa_bus_new(&d->qdev);
     isa_bus_new(&d->qdev);
 
 
     pci_conf = d->config;
     pci_conf = d->config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_ISA_BRIDGE);
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
     pci_config_set_prog_interface(pci_conf, 0x0);
     pci_config_set_prog_interface(pci_conf, 0x0);
-    pci_config_set_revision(pci_conf,0x40); /* Revision 4.0 */
 
 
     wmask = d->wmask;
     wmask = d->wmask;
     for (i = 0x00; i < 0xff; i++) {
     for (i = 0x00; i < 0xff; i++) {
@@ -531,6 +524,10 @@ static PCIDeviceInfo via_info = {
     .qdev.no_user = 1,
     .qdev.no_user = 1,
     .init         = vt82c686b_initfn,
     .init         = vt82c686b_initfn,
     .config_write = vt82c686b_write_config,
     .config_write = vt82c686b_write_config,
+    .vendor_id    = PCI_VENDOR_ID_VIA,
+    .device_id    = PCI_DEVICE_ID_VIA_ISA_BRIDGE,
+    .class_id     = PCI_CLASS_BRIDGE_ISA,
+    .revision     = 0x40,
 };
 };
 
 
 static void vt82c686b_register(void)
 static void vt82c686b_register(void)

+ 3 - 6
hw/wdt_i6300esb.c

@@ -381,7 +381,6 @@ static const VMStateDescription vmstate_i6300esb = {
 static int i6300esb_init(PCIDevice *dev)
 static int i6300esb_init(PCIDevice *dev)
 {
 {
     I6300State *d = DO_UPCAST(I6300State, dev, dev);
     I6300State *d = DO_UPCAST(I6300State, dev, dev);
-    uint8_t *pci_conf;
     int io_mem;
     int io_mem;
     static CPUReadMemoryFunc * const mem_read[3] = {
     static CPUReadMemoryFunc * const mem_read[3] = {
         i6300esb_mem_readb,
         i6300esb_mem_readb,
@@ -399,11 +398,6 @@ static int i6300esb_init(PCIDevice *dev)
     d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d);
     d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d);
     d->previous_reboot_flag = 0;
     d->previous_reboot_flag = 0;
 
 
-    pci_conf = d->dev.config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_ESB_9);
-    pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
-
     io_mem = cpu_register_io_memory(mem_read, mem_write, d,
     io_mem = cpu_register_io_memory(mem_read, mem_write, d,
                                     DEVICE_NATIVE_ENDIAN);
                                     DEVICE_NATIVE_ENDIAN);
     pci_register_bar_simple(&d->dev, 0, 0x10, 0, io_mem);
     pci_register_bar_simple(&d->dev, 0, 0x10, 0, io_mem);
@@ -425,6 +419,9 @@ static PCIDeviceInfo i6300esb_info = {
     .config_read  = i6300esb_config_read,
     .config_read  = i6300esb_config_read,
     .config_write = i6300esb_config_write,
     .config_write = i6300esb_config_write,
     .init         = i6300esb_init,
     .init         = i6300esb_init,
+    .vendor_id    = PCI_VENDOR_ID_INTEL,
+    .device_id    = PCI_DEVICE_ID_INTEL_ESB_9,
+    .class_id     = PCI_CLASS_SYSTEM_OTHER,
 };
 };
 
 
 static void i6300esb_register_devices(void)
 static void i6300esb_register_devices(void)

+ 3 - 3
hw/xio3130_downstream.c

@@ -69,9 +69,6 @@ static int xio3130_downstream_initfn(PCIDevice *d)
     }
     }
 
 
     pcie_port_init_reg(d);
     pcie_port_init_reg(d);
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130D);
-    d->config[PCI_REVISION_ID] = XIO3130_REVISION;
 
 
     rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
     rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
                   XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
                   XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
@@ -182,6 +179,9 @@ static PCIDeviceInfo xio3130_downstream_info = {
     .config_write = xio3130_downstream_write_config,
     .config_write = xio3130_downstream_write_config,
     .init = xio3130_downstream_initfn,
     .init = xio3130_downstream_initfn,
     .exit = xio3130_downstream_exitfn,
     .exit = xio3130_downstream_exitfn,
+    .vendor_id = PCI_VENDOR_ID_TI,
+    .device_id = PCI_DEVICE_ID_TI_XIO3130D,
+    .revision = XIO3130_REVISION,
 
 
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
         DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),

+ 3 - 3
hw/xio3130_upstream.c

@@ -65,9 +65,6 @@ static int xio3130_upstream_initfn(PCIDevice *d)
     }
     }
 
 
     pcie_port_init_reg(d);
     pcie_port_init_reg(d);
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_TI);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_TI_XIO3130U);
-    d->config[PCI_REVISION_ID] = XIO3130_REVISION;
 
 
     rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
     rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
                   XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
                   XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
@@ -159,6 +156,9 @@ static PCIDeviceInfo xio3130_upstream_info = {
     .config_write = xio3130_upstream_write_config,
     .config_write = xio3130_upstream_write_config,
     .init = xio3130_upstream_initfn,
     .init = xio3130_upstream_initfn,
     .exit = xio3130_upstream_exitfn,
     .exit = xio3130_upstream_exitfn,
+    .vendor_id = PCI_VENDOR_ID_TI,
+    .device_id = PCI_DEVICE_ID_TI_XIO3130U,
+    .revision = XIO3130_REVISION,
 
 
     .qdev.props = (Property[]) {
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
         DEFINE_PROP_UINT8("port", PCIEPort, port, 0),

+ 2149 - 0
scripts/get_maintainer.pl

@@ -0,0 +1,2149 @@
+#!/usr/bin/perl -w
+# (c) 2007, Joe Perches <joe@perches.com>
+#           created from checkpatch.pl
+#
+# Print selected MAINTAINERS information for
+# the files modified in a patch or for a file
+#
+# usage: perl scripts/get_maintainer.pl [OPTIONS] <patch>
+#        perl scripts/get_maintainer.pl [OPTIONS] -f <file>
+#
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+my $V = '0.26';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $lk_path = "./";
+my $email = 1;
+my $email_usename = 1;
+my $email_maintainer = 1;
+my $email_list = 1;
+my $email_subscriber_list = 0;
+my $email_git_penguin_chiefs = 0;
+my $email_git = 0;
+my $email_git_all_signature_types = 0;
+my $email_git_blame = 0;
+my $email_git_blame_signatures = 1;
+my $email_git_fallback = 1;
+my $email_git_min_signatures = 1;
+my $email_git_max_maintainers = 5;
+my $email_git_min_percent = 5;
+my $email_git_since = "1-year-ago";
+my $email_hg_since = "-365";
+my $interactive = 0;
+my $email_remove_duplicates = 1;
+my $email_use_mailmap = 1;
+my $output_multiline = 1;
+my $output_separator = ", ";
+my $output_roles = 0;
+my $output_rolestats = 1;
+my $scm = 0;
+my $web = 0;
+my $subsystem = 0;
+my $status = 0;
+my $keywords = 1;
+my $sections = 0;
+my $file_emails = 0;
+my $from_filename = 0;
+my $pattern_depth = 0;
+my $version = 0;
+my $help = 0;
+
+my $vcs_used = 0;
+
+my $exit = 0;
+
+my %commit_author_hash;
+my %commit_signer_hash;
+
+my @penguin_chief = ();
+push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
+#Andrew wants in on most everything - 2009/01/14
+#push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
+
+my @penguin_chief_names = ();
+foreach my $chief (@penguin_chief) {
+    if ($chief =~ m/^(.*):(.*)/) {
+	my $chief_name = $1;
+	my $chief_addr = $2;
+	push(@penguin_chief_names, $chief_name);
+    }
+}
+my $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
+
+# Signature types of people who are either
+# 	a) responsible for the code in question, or
+# 	b) familiar enough with it to give relevant feedback
+my @signature_tags = ();
+push(@signature_tags, "Signed-off-by:");
+push(@signature_tags, "Reviewed-by:");
+push(@signature_tags, "Acked-by:");
+
+# rfc822 email address - preloaded methods go here.
+my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
+my $rfc822_char = '[\\000-\\377]';
+
+# VCS command support: class-like functions and strings
+
+my %VCS_cmds;
+
+my %VCS_cmds_git = (
+    "execute_cmd" => \&git_execute_cmd,
+    "available" => '(which("git") ne "") && (-d ".git")',
+    "find_signers_cmd" =>
+	"git log --no-color --since=\$email_git_since " .
+	    '--format="GitCommit: %H%n' .
+		      'GitAuthor: %an <%ae>%n' .
+		      'GitDate: %aD%n' .
+		      'GitSubject: %s%n' .
+		      '%b%n"' .
+	    " -- \$file",
+    "find_commit_signers_cmd" =>
+	"git log --no-color " .
+	    '--format="GitCommit: %H%n' .
+		      'GitAuthor: %an <%ae>%n' .
+		      'GitDate: %aD%n' .
+		      'GitSubject: %s%n' .
+		      '%b%n"' .
+	    " -1 \$commit",
+    "find_commit_author_cmd" =>
+	"git log --no-color " .
+	    '--format="GitCommit: %H%n' .
+		      'GitAuthor: %an <%ae>%n' .
+		      'GitDate: %aD%n' .
+		      'GitSubject: %s%n"' .
+	    " -1 \$commit",
+    "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
+    "blame_file_cmd" => "git blame -l \$file",
+    "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([0-9a-f]+) ",
+    "author_pattern" => "^GitAuthor: (.*)",
+    "subject_pattern" => "^GitSubject: (.*)",
+);
+
+my %VCS_cmds_hg = (
+    "execute_cmd" => \&hg_execute_cmd,
+    "available" => '(which("hg") ne "") && (-d ".hg")',
+    "find_signers_cmd" =>
+	"hg log --date=\$email_hg_since " .
+	    "--template='HgCommit: {node}\\n" .
+	                "HgAuthor: {author}\\n" .
+			"HgSubject: {desc}\\n'" .
+	    " -- \$file",
+    "find_commit_signers_cmd" =>
+	"hg log " .
+	    "--template='HgSubject: {desc}\\n'" .
+	    " -r \$commit",
+    "find_commit_author_cmd" =>
+	"hg log " .
+	    "--template='HgCommit: {node}\\n" .
+		        "HgAuthor: {author}\\n" .
+			"HgSubject: {desc|firstline}\\n'" .
+	    " -r \$commit",
+    "blame_range_cmd" => "",		# not supported
+    "blame_file_cmd" => "hg blame -n \$file",
+    "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern" => "^([ 0-9a-f]+):",
+    "author_pattern" => "^HgAuthor: (.*)",
+    "subject_pattern" => "^HgSubject: (.*)",
+);
+
+my $conf = which_conf(".get_maintainer.conf");
+if (-f $conf) {
+    my @conf_args;
+    open(my $conffile, '<', "$conf")
+	or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
+
+    while (<$conffile>) {
+	my $line = $_;
+
+	$line =~ s/\s*\n?$//g;
+	$line =~ s/^\s*//g;
+	$line =~ s/\s+/ /g;
+
+	next if ($line =~ m/^\s*#/);
+	next if ($line =~ m/^\s*$/);
+
+	my @words = split(" ", $line);
+	foreach my $word (@words) {
+	    last if ($word =~ m/^#/);
+	    push (@conf_args, $word);
+	}
+    }
+    close($conffile);
+    unshift(@ARGV, @conf_args) if @conf_args;
+}
+
+if (!GetOptions(
+		'email!' => \$email,
+		'git!' => \$email_git,
+		'git-all-signature-types!' => \$email_git_all_signature_types,
+		'git-blame!' => \$email_git_blame,
+		'git-blame-signatures!' => \$email_git_blame_signatures,
+		'git-fallback!' => \$email_git_fallback,
+		'git-chief-penguins!' => \$email_git_penguin_chiefs,
+		'git-min-signatures=i' => \$email_git_min_signatures,
+		'git-max-maintainers=i' => \$email_git_max_maintainers,
+		'git-min-percent=i' => \$email_git_min_percent,
+		'git-since=s' => \$email_git_since,
+		'hg-since=s' => \$email_hg_since,
+		'i|interactive!' => \$interactive,
+		'remove-duplicates!' => \$email_remove_duplicates,
+		'mailmap!' => \$email_use_mailmap,
+		'm!' => \$email_maintainer,
+		'n!' => \$email_usename,
+		'l!' => \$email_list,
+		's!' => \$email_subscriber_list,
+		'multiline!' => \$output_multiline,
+		'roles!' => \$output_roles,
+		'rolestats!' => \$output_rolestats,
+		'separator=s' => \$output_separator,
+		'subsystem!' => \$subsystem,
+		'status!' => \$status,
+		'scm!' => \$scm,
+		'web!' => \$web,
+		'pattern-depth=i' => \$pattern_depth,
+		'k|keywords!' => \$keywords,
+		'sections!' => \$sections,
+		'fe|file-emails!' => \$file_emails,
+		'f|file' => \$from_filename,
+		'v|version' => \$version,
+		'h|help|usage' => \$help,
+		)) {
+    die "$P: invalid argument - use --help if necessary\n";
+}
+
+if ($help != 0) {
+    usage();
+    exit 0;
+}
+
+if ($version != 0) {
+    print("${P} ${V}\n");
+    exit 0;
+}
+
+if (-t STDIN && !@ARGV) {
+    # We're talking to a terminal, but have no command line arguments.
+    die "$P: missing patchfile or -f file - use --help if necessary\n";
+}
+
+$output_multiline = 0 if ($output_separator ne ", ");
+$output_rolestats = 1 if ($interactive);
+$output_roles = 1 if ($output_rolestats);
+
+if ($sections) {
+    $email = 0;
+    $email_list = 0;
+    $scm = 0;
+    $status = 0;
+    $subsystem = 0;
+    $web = 0;
+    $keywords = 0;
+    $interactive = 0;
+} else {
+    my $selections = $email + $scm + $status + $subsystem + $web;
+    if ($selections == 0) {
+	die "$P:  Missing required option: email, scm, status, subsystem or web\n";
+    }
+}
+
+if ($email &&
+    ($email_maintainer + $email_list + $email_subscriber_list +
+     $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
+    die "$P: Please select at least 1 email option\n";
+}
+
+if (!top_of_tree($lk_path)) {
+    die "$P: The current directory does not appear to be "
+	. "a QEMU source tree.\n";
+}
+
+## Read MAINTAINERS for type/value pairs
+
+my @typevalue = ();
+my %keyword_hash;
+
+open (my $maint, '<', "${lk_path}MAINTAINERS")
+    or die "$P: Can't open MAINTAINERS: $!\n";
+while (<$maint>) {
+    my $line = $_;
+
+    if ($line =~ m/^(\C):\s*(.*)/) {
+	my $type = $1;
+	my $value = $2;
+
+	##Filename pattern matching
+	if ($type eq "F" || $type eq "X") {
+	    $value =~ s@\.@\\\.@g;       ##Convert . to \.
+	    $value =~ s/\*/\.\*/g;       ##Convert * to .*
+	    $value =~ s/\?/\./g;         ##Convert ? to .
+	    ##if pattern is a directory and it lacks a trailing slash, add one
+	    if ((-d $value)) {
+		$value =~ s@([^/])$@$1/@;
+	    }
+	} elsif ($type eq "K") {
+	    $keyword_hash{@typevalue} = $value;
+	}
+	push(@typevalue, "$type:$value");
+    } elsif (!/^(\s)*$/) {
+	$line =~ s/\n$//g;
+	push(@typevalue, $line);
+    }
+}
+close($maint);
+
+
+#
+# Read mail address map
+#
+
+my $mailmap;
+
+read_mailmap();
+
+sub read_mailmap {
+    $mailmap = {
+	names => {},
+	addresses => {}
+    };
+
+    return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
+
+    open(my $mailmap_file, '<', "${lk_path}.mailmap")
+	or warn "$P: Can't open .mailmap: $!\n";
+
+    while (<$mailmap_file>) {
+	s/#.*$//; #strip comments
+	s/^\s+|\s+$//g; #trim
+
+	next if (/^\s*$/); #skip empty lines
+	#entries have one of the following formats:
+	# name1 <mail1>
+	# <mail1> <mail2>
+	# name1 <mail1> <mail2>
+	# name1 <mail1> name2 <mail2>
+	# (see man git-shortlog)
+	if (/^(.+)<(.+)>$/) {
+	    my $real_name = $1;
+	    my $address = $2;
+
+	    $real_name =~ s/\s+$//;
+	    ($real_name, $address) = parse_email("$real_name <$address>");
+	    $mailmap->{names}->{$address} = $real_name;
+
+	} elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) {
+	    my $real_address = $1;
+	    my $wrong_address = $2;
+
+	    $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+	} elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) {
+	    my $real_name = $1;
+	    my $real_address = $2;
+	    my $wrong_address = $3;
+
+	    $real_name =~ s/\s+$//;
+	    ($real_name, $real_address) =
+		parse_email("$real_name <$real_address>");
+	    $mailmap->{names}->{$wrong_address} = $real_name;
+	    $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+	} elsif (/^(.+)<([^\s]+)>\s*([^\s].*)<([^\s]+)>$/) {
+	    my $real_name = $1;
+	    my $real_address = $2;
+	    my $wrong_name = $3;
+	    my $wrong_address = $4;
+
+	    $real_name =~ s/\s+$//;
+	    ($real_name, $real_address) =
+		parse_email("$real_name <$real_address>");
+
+	    $wrong_name =~ s/\s+$//;
+	    ($wrong_name, $wrong_address) =
+		parse_email("$wrong_name <$wrong_address>");
+
+	    my $wrong_email = format_email($wrong_name, $wrong_address, 1);
+	    $mailmap->{names}->{$wrong_email} = $real_name;
+	    $mailmap->{addresses}->{$wrong_email} = $real_address;
+	}
+    }
+    close($mailmap_file);
+}
+
+## use the filenames on the command line or find the filenames in the patchfiles
+
+my @files = ();
+my @range = ();
+my @keyword_tvi = ();
+my @file_emails = ();
+
+if (!@ARGV) {
+    push(@ARGV, "&STDIN");
+}
+
+foreach my $file (@ARGV) {
+    if ($file ne "&STDIN") {
+	##if $file is a directory and it lacks a trailing slash, add one
+	if ((-d $file)) {
+	    $file =~ s@([^/])$@$1/@;
+	} elsif (!(-f $file)) {
+	    die "$P: file '${file}' not found\n";
+	}
+    }
+    if ($from_filename) {
+	push(@files, $file);
+	if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) {
+	    open(my $f, '<', $file)
+		or die "$P: Can't open $file: $!\n";
+	    my $text = do { local($/) ; <$f> };
+	    close($f);
+	    if ($keywords) {
+		foreach my $line (keys %keyword_hash) {
+		    if ($text =~ m/$keyword_hash{$line}/x) {
+			push(@keyword_tvi, $line);
+		    }
+		}
+	    }
+	    if ($file_emails) {
+		my @poss_addr = $text =~ m$[A-Za-zÀ-ÿ\"\' \,\.\+-]*\s*[\,]*\s*[\(\<\{]{0,1}[A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+\.[A-Za-z0-9]+[\)\>\}]{0,1}$g;
+		push(@file_emails, clean_file_emails(@poss_addr));
+	    }
+	}
+    } else {
+	my $file_cnt = @files;
+	my $lastfile;
+
+	open(my $patch, "< $file")
+	    or die "$P: Can't open $file: $!\n";
+
+	# We can check arbitrary information before the patch
+	# like the commit message, mail headers, etc...
+	# This allows us to match arbitrary keywords against any part
+	# of a git format-patch generated file (subject tags, etc...)
+
+	my $patch_prefix = "";			#Parsing the intro
+
+	while (<$patch>) {
+	    my $patch_line = $_;
+	    if (m/^\+\+\+\s+(\S+)/) {
+		my $filename = $1;
+		$filename =~ s@^[^/]*/@@;
+		$filename =~ s@\n@@;
+		$lastfile = $filename;
+		push(@files, $filename);
+		$patch_prefix = "^[+-].*";	#Now parsing the actual patch
+	    } elsif (m/^\@\@ -(\d+),(\d+)/) {
+		if ($email_git_blame) {
+		    push(@range, "$lastfile:$1:$2");
+		}
+	    } elsif ($keywords) {
+		foreach my $line (keys %keyword_hash) {
+		    if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) {
+			push(@keyword_tvi, $line);
+		    }
+		}
+	    }
+	}
+	close($patch);
+
+	if ($file_cnt == @files) {
+	    warn "$P: file '${file}' doesn't appear to be a patch.  "
+		. "Add -f to options?\n";
+	}
+	@files = sort_and_uniq(@files);
+    }
+}
+
+@file_emails = uniq(@file_emails);
+
+my %email_hash_name;
+my %email_hash_address;
+my @email_to = ();
+my %hash_list_to;
+my @list_to = ();
+my @scm = ();
+my @web = ();
+my @subsystem = ();
+my @status = ();
+my %deduplicate_name_hash = ();
+my %deduplicate_address_hash = ();
+my $signature_pattern;
+
+my @maintainers = get_maintainers();
+
+if (@maintainers) {
+    @maintainers = merge_email(@maintainers);
+    output(@maintainers);
+}
+
+if ($scm) {
+    @scm = uniq(@scm);
+    output(@scm);
+}
+
+if ($status) {
+    @status = uniq(@status);
+    output(@status);
+}
+
+if ($subsystem) {
+    @subsystem = uniq(@subsystem);
+    output(@subsystem);
+}
+
+if ($web) {
+    @web = uniq(@web);
+    output(@web);
+}
+
+exit($exit);
+
+sub range_is_maintained {
+    my ($start, $end) = @_;
+
+    for (my $i = $start; $i < $end; $i++) {
+	my $line = $typevalue[$i];
+	if ($line =~ m/^(\C):\s*(.*)/) {
+	    my $type = $1;
+	    my $value = $2;
+	    if ($type eq 'S') {
+		if ($value =~ /(maintain|support)/i) {
+		    return 1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+sub range_has_maintainer {
+    my ($start, $end) = @_;
+
+    for (my $i = $start; $i < $end; $i++) {
+	my $line = $typevalue[$i];
+	if ($line =~ m/^(\C):\s*(.*)/) {
+	    my $type = $1;
+	    my $value = $2;
+	    if ($type eq 'M') {
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+
+sub get_maintainers {
+    %email_hash_name = ();
+    %email_hash_address = ();
+    %commit_author_hash = ();
+    %commit_signer_hash = ();
+    @email_to = ();
+    %hash_list_to = ();
+    @list_to = ();
+    @scm = ();
+    @web = ();
+    @subsystem = ();
+    @status = ();
+    %deduplicate_name_hash = ();
+    %deduplicate_address_hash = ();
+    if ($email_git_all_signature_types) {
+	$signature_pattern = "(.+?)[Bb][Yy]:";
+    } else {
+	$signature_pattern = "\(" . join("|", @signature_tags) . "\)";
+    }
+
+    # Find responsible parties
+
+    my %exact_pattern_match_hash = ();
+
+    foreach my $file (@files) {
+
+	my %hash;
+	my $tvi = find_first_section();
+	while ($tvi < @typevalue) {
+	    my $start = find_starting_index($tvi);
+	    my $end = find_ending_index($tvi);
+	    my $exclude = 0;
+	    my $i;
+
+	    #Do not match excluded file patterns
+
+	    for ($i = $start; $i < $end; $i++) {
+		my $line = $typevalue[$i];
+		if ($line =~ m/^(\C):\s*(.*)/) {
+		    my $type = $1;
+		    my $value = $2;
+		    if ($type eq 'X') {
+			if (file_match_pattern($file, $value)) {
+			    $exclude = 1;
+			    last;
+			}
+		    }
+		}
+	    }
+
+	    if (!$exclude) {
+		for ($i = $start; $i < $end; $i++) {
+		    my $line = $typevalue[$i];
+		    if ($line =~ m/^(\C):\s*(.*)/) {
+			my $type = $1;
+			my $value = $2;
+			if ($type eq 'F') {
+			    if (file_match_pattern($file, $value)) {
+				my $value_pd = ($value =~ tr@/@@);
+				my $file_pd = ($file  =~ tr@/@@);
+				$value_pd++ if (substr($value,-1,1) ne "/");
+				$value_pd = -1 if ($value =~ /^\.\*/);
+				if ($value_pd >= $file_pd &&
+				    range_is_maintained($start, $end) &&
+				    range_has_maintainer($start, $end)) {
+				    $exact_pattern_match_hash{$file} = 1;
+				}
+				if ($pattern_depth == 0 ||
+				    (($file_pd - $value_pd) < $pattern_depth)) {
+				    $hash{$tvi} = $value_pd;
+				}
+			    }
+			}
+		    }
+		}
+	    }
+	    $tvi = $end + 1;
+	}
+
+	foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+	    add_categories($line);
+	    if ($sections) {
+		my $i;
+		my $start = find_starting_index($line);
+		my $end = find_ending_index($line);
+		for ($i = $start; $i < $end; $i++) {
+		    my $line = $typevalue[$i];
+		    if ($line =~ /^[FX]:/) {		##Restore file patterns
+			$line =~ s/([^\\])\.([^\*])/$1\?$2/g;
+			$line =~ s/([^\\])\.$/$1\?/g;	##Convert . back to ?
+			$line =~ s/\\\./\./g;       	##Convert \. to .
+			$line =~ s/\.\*/\*/g;       	##Convert .* to *
+		    }
+		    $line =~ s/^([A-Z]):/$1:\t/g;
+		    print("$line\n");
+		}
+		print("\n");
+	    }
+	}
+    }
+
+    if ($keywords) {
+	@keyword_tvi = sort_and_uniq(@keyword_tvi);
+	foreach my $line (@keyword_tvi) {
+	    add_categories($line);
+	}
+    }
+
+    foreach my $email (@email_to, @list_to) {
+	$email->[0] = deduplicate_email($email->[0]);
+    }
+
+    foreach my $file (@files) {
+	if ($email &&
+	    ($email_git || ($email_git_fallback &&
+			    !$exact_pattern_match_hash{$file}))) {
+	    vcs_file_signoffs($file);
+	}
+	if ($email && $email_git_blame) {
+	    vcs_file_blame($file);
+	}
+    }
+
+    if ($email) {
+	foreach my $chief (@penguin_chief) {
+	    if ($chief =~ m/^(.*):(.*)/) {
+		my $email_address;
+
+		$email_address = format_email($1, $2, $email_usename);
+		if ($email_git_penguin_chiefs) {
+		    push(@email_to, [$email_address, 'chief penguin']);
+		} else {
+		    @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
+		}
+	    }
+	}
+
+	foreach my $email (@file_emails) {
+	    my ($name, $address) = parse_email($email);
+
+	    my $tmp_email = format_email($name, $address, $email_usename);
+	    push_email_address($tmp_email, '');
+	    add_role($tmp_email, 'in file');
+	}
+    }
+
+    my @to = ();
+    if ($email || $email_list) {
+	if ($email) {
+	    @to = (@to, @email_to);
+	}
+	if ($email_list) {
+	    @to = (@to, @list_to);
+	}
+    }
+
+    if ($interactive) {
+	@to = interactive_get_maintainers(\@to);
+    }
+
+    return @to;
+}
+
+sub file_match_pattern {
+    my ($file, $pattern) = @_;
+    if (substr($pattern, -1) eq "/") {
+	if ($file =~ m@^$pattern@) {
+	    return 1;
+	}
+    } else {
+	if ($file =~ m@^$pattern@) {
+	    my $s1 = ($file =~ tr@/@@);
+	    my $s2 = ($pattern =~ tr@/@@);
+	    if ($s1 == $s2) {
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+
+sub usage {
+    print <<EOT;
+usage: $P [options] patchfile
+       $P [options] -f file|directory
+version: $V
+
+MAINTAINER field selection options:
+  --email => print email address(es) if any
+    --git => include recent git \*-by: signers
+    --git-all-signature-types => include signers regardless of signature type
+        or use only ${signature_pattern} signers (default: $email_git_all_signature_types)
+    --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback)
+    --git-chief-penguins => include ${penguin_chiefs}
+    --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
+    --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
+    --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent)
+    --git-blame => use git blame to find modified commits for patch or file
+    --git-since => git history to use (default: $email_git_since)
+    --hg-since => hg history to use (default: $email_hg_since)
+    --interactive => display a menu (mostly useful if used with the --git option)
+    --m => include maintainer(s) if any
+    --n => include name 'Full Name <addr\@domain.tld>'
+    --l => include list(s) if any
+    --s => include subscriber only list(s) if any
+    --remove-duplicates => minimize duplicate email names/addresses
+    --roles => show roles (status:subsystem, git-signer, list, etc...)
+    --rolestats => show roles and statistics (commits/total_commits, %)
+    --file-emails => add email addresses found in -f file (default: 0 (off))
+  --scm => print SCM tree(s) if any
+  --status => print status if any
+  --subsystem => print subsystem name if any
+  --web => print website(s) if any
+
+Output type options:
+  --separator [, ] => separator for multiple entries on 1 line
+    using --separator also sets --nomultiline if --separator is not [, ]
+  --multiline => print 1 entry per line
+
+Other options:
+  --pattern-depth => Number of pattern directory traversals (default: 0 (all))
+  --keywords => scan patch for keywords (default: $keywords)
+  --sections => print all of the subsystem sections with pattern matches
+  --mailmap => use .mailmap file (default: $email_use_mailmap)
+  --version => show version
+  --help => show this help information
+
+Default options:
+  [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0
+   --remove-duplicates --rolestats]
+
+Notes:
+  Using "-f directory" may give unexpected results:
+      Used with "--git", git signators for _all_ files in and below
+          directory are examined as git recurses directories.
+          Any specified X: (exclude) pattern matches are _not_ ignored.
+      Used with "--nogit", directory is used as a pattern match,
+          no individual file within the directory or subdirectory
+          is matched.
+      Used with "--git-blame", does not iterate all files in directory
+  Using "--git-blame" is slow and may add old committers and authors
+      that are no longer active maintainers to the output.
+  Using "--roles" or "--rolestats" with git send-email --cc-cmd or any
+      other automated tools that expect only ["name"] <email address>
+      may not work because of additional output after <email address>.
+  Using "--rolestats" and "--git-blame" shows the #/total=% commits,
+      not the percentage of the entire file authored.  # of commits is
+      not a good measure of amount of code authored.  1 major commit may
+      contain a thousand lines, 5 trivial commits may modify a single line.
+  If git is not installed, but mercurial (hg) is installed and an .hg
+      repository exists, the following options apply to mercurial:
+          --git,
+          --git-min-signatures, --git-max-maintainers, --git-min-percent, and
+          --git-blame
+      Use --hg-since not --git-since to control date selection
+  File ".get_maintainer.conf", if it exists in the QEMU source root
+      directory, can change whatever get_maintainer defaults are desired.
+      Entries in this file can be any command line argument.
+      This file is prepended to any additional command line arguments.
+      Multiple lines and # comments are allowed.
+EOT
+}
+
+sub top_of_tree {
+    my ($lk_path) = @_;
+
+    if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
+	$lk_path .= "/";
+    }
+    if (    (-f "${lk_path}COPYING")
+        && (-f "${lk_path}MAINTAINERS")
+        && (-f "${lk_path}Makefile")
+        && (-d "${lk_path}docs")
+        && (-f "${lk_path}VERSION")
+        && (-f "${lk_path}vl.c")) {
+	return 1;
+    }
+    return 0;
+}
+
+sub parse_email {
+    my ($formatted_email) = @_;
+
+    my $name = "";
+    my $address = "";
+
+    if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) {
+	$name = $1;
+	$address = $2;
+    } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) {
+	$address = $1;
+    } elsif ($formatted_email =~ /^(.+\@\S*).*$/) {
+	$address = $1;
+    }
+
+    $name =~ s/^\s+|\s+$//g;
+    $name =~ s/^\"|\"$//g;
+    $address =~ s/^\s+|\s+$//g;
+
+    if ($name =~ /[^\w \-]/i) {  	 ##has "must quote" chars
+	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
+	$name = "\"$name\"";
+    }
+
+    return ($name, $address);
+}
+
+sub format_email {
+    my ($name, $address, $usename) = @_;
+
+    my $formatted_email;
+
+    $name =~ s/^\s+|\s+$//g;
+    $name =~ s/^\"|\"$//g;
+    $address =~ s/^\s+|\s+$//g;
+
+    if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
+	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
+	$name = "\"$name\"";
+    }
+
+    if ($usename) {
+	if ("$name" eq "") {
+	    $formatted_email = "$address";
+	} else {
+	    $formatted_email = "$name <$address>";
+	}
+    } else {
+	$formatted_email = $address;
+    }
+
+    return $formatted_email;
+}
+
+sub find_first_section {
+    my $index = 0;
+
+    while ($index < @typevalue) {
+	my $tv = $typevalue[$index];
+	if (($tv =~ m/^(\C):\s*(.*)/)) {
+	    last;
+	}
+	$index++;
+    }
+
+    return $index;
+}
+
+sub find_starting_index {
+    my ($index) = @_;
+
+    while ($index > 0) {
+	my $tv = $typevalue[$index];
+	if (!($tv =~ m/^(\C):\s*(.*)/)) {
+	    last;
+	}
+	$index--;
+    }
+
+    return $index;
+}
+
+sub find_ending_index {
+    my ($index) = @_;
+
+    while ($index < @typevalue) {
+	my $tv = $typevalue[$index];
+	if (!($tv =~ m/^(\C):\s*(.*)/)) {
+	    last;
+	}
+	$index++;
+    }
+
+    return $index;
+}
+
+sub get_maintainer_role {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    my $role;
+    my $subsystem = $typevalue[$start];
+    if (length($subsystem) > 20) {
+	$subsystem = substr($subsystem, 0, 17);
+	$subsystem =~ s/\s*$//;
+	$subsystem = $subsystem . "...";
+    }
+
+    for ($i = $start + 1; $i < $end; $i++) {
+	my $tv = $typevalue[$i];
+	if ($tv =~ m/^(\C):\s*(.*)/) {
+	    my $ptype = $1;
+	    my $pvalue = $2;
+	    if ($ptype eq "S") {
+		$role = $pvalue;
+	    }
+	}
+    }
+
+    $role = lc($role);
+    if      ($role eq "supported") {
+	$role = "supporter";
+    } elsif ($role eq "maintained") {
+	$role = "maintainer";
+    } elsif ($role eq "odd fixes") {
+	$role = "odd fixer";
+    } elsif ($role eq "orphan") {
+	$role = "orphan minder";
+    } elsif ($role eq "obsolete") {
+	$role = "obsolete minder";
+    } elsif ($role eq "buried alive in reporters") {
+	$role = "chief penguin";
+    }
+
+    return $role . ":" . $subsystem;
+}
+
+sub get_list_role {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    my $subsystem = $typevalue[$start];
+    if (length($subsystem) > 20) {
+	$subsystem = substr($subsystem, 0, 17);
+	$subsystem =~ s/\s*$//;
+	$subsystem = $subsystem . "...";
+    }
+
+    if ($subsystem eq "THE REST") {
+	$subsystem = "";
+    }
+
+    return $subsystem;
+}
+
+sub add_categories {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    push(@subsystem, $typevalue[$start]);
+
+    for ($i = $start + 1; $i < $end; $i++) {
+	my $tv = $typevalue[$i];
+	if ($tv =~ m/^(\C):\s*(.*)/) {
+	    my $ptype = $1;
+	    my $pvalue = $2;
+	    if ($ptype eq "L") {
+		my $list_address = $pvalue;
+		my $list_additional = "";
+		my $list_role = get_list_role($i);
+
+		if ($list_role ne "") {
+		    $list_role = ":" . $list_role;
+		}
+		if ($list_address =~ m/([^\s]+)\s+(.*)$/) {
+		    $list_address = $1;
+		    $list_additional = $2;
+		}
+		if ($list_additional =~ m/subscribers-only/) {
+		    if ($email_subscriber_list) {
+			if (!$hash_list_to{lc($list_address)}) {
+			    $hash_list_to{lc($list_address)} = 1;
+			    push(@list_to, [$list_address,
+					    "subscriber list${list_role}"]);
+			}
+		    }
+		} else {
+		    if ($email_list) {
+			if (!$hash_list_to{lc($list_address)}) {
+			    $hash_list_to{lc($list_address)} = 1;
+			    push(@list_to, [$list_address,
+					    "open list${list_role}"]);
+			}
+		    }
+		}
+	    } elsif ($ptype eq "M") {
+		my ($name, $address) = parse_email($pvalue);
+		if ($name eq "") {
+		    if ($i > 0) {
+			my $tv = $typevalue[$i - 1];
+			if ($tv =~ m/^(\C):\s*(.*)/) {
+			    if ($1 eq "P") {
+				$name = $2;
+				$pvalue = format_email($name, $address, $email_usename);
+			    }
+			}
+		    }
+		}
+		if ($email_maintainer) {
+		    my $role = get_maintainer_role($i);
+		    push_email_addresses($pvalue, $role);
+		}
+	    } elsif ($ptype eq "T") {
+		push(@scm, $pvalue);
+	    } elsif ($ptype eq "W") {
+		push(@web, $pvalue);
+	    } elsif ($ptype eq "S") {
+		push(@status, $pvalue);
+	    }
+	}
+    }
+}
+
+sub email_inuse {
+    my ($name, $address) = @_;
+
+    return 1 if (($name eq "") && ($address eq ""));
+    return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
+    return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
+
+    return 0;
+}
+
+sub push_email_address {
+    my ($line, $role) = @_;
+
+    my ($name, $address) = parse_email($line);
+
+    if ($address eq "") {
+	return 0;
+    }
+
+    if (!$email_remove_duplicates) {
+	push(@email_to, [format_email($name, $address, $email_usename), $role]);
+    } elsif (!email_inuse($name, $address)) {
+	push(@email_to, [format_email($name, $address, $email_usename), $role]);
+	$email_hash_name{lc($name)}++ if ($name ne "");
+	$email_hash_address{lc($address)}++;
+    }
+
+    return 1;
+}
+
+sub push_email_addresses {
+    my ($address, $role) = @_;
+
+    my @address_list = ();
+
+    if (rfc822_valid($address)) {
+	push_email_address($address, $role);
+    } elsif (@address_list = rfc822_validlist($address)) {
+	my $array_count = shift(@address_list);
+	while (my $entry = shift(@address_list)) {
+	    push_email_address($entry, $role);
+	}
+    } else {
+	if (!push_email_address($address, $role)) {
+	    warn("Invalid MAINTAINERS address: '" . $address . "'\n");
+	}
+    }
+}
+
+sub add_role {
+    my ($line, $role) = @_;
+
+    my ($name, $address) = parse_email($line);
+    my $email = format_email($name, $address, $email_usename);
+
+    foreach my $entry (@email_to) {
+	if ($email_remove_duplicates) {
+	    my ($entry_name, $entry_address) = parse_email($entry->[0]);
+	    if (($name eq $entry_name || $address eq $entry_address)
+		&& ($role eq "" || !($entry->[1] =~ m/$role/))
+	    ) {
+		if ($entry->[1] eq "") {
+		    $entry->[1] = "$role";
+		} else {
+		    $entry->[1] = "$entry->[1],$role";
+		}
+	    }
+	} else {
+	    if ($email eq $entry->[0]
+		&& ($role eq "" || !($entry->[1] =~ m/$role/))
+	    ) {
+		if ($entry->[1] eq "") {
+		    $entry->[1] = "$role";
+		} else {
+		    $entry->[1] = "$entry->[1],$role";
+		}
+	    }
+	}
+    }
+}
+
+sub which {
+    my ($bin) = @_;
+
+    foreach my $path (split(/:/, $ENV{PATH})) {
+	if (-e "$path/$bin") {
+	    return "$path/$bin";
+	}
+    }
+
+    return "";
+}
+
+sub which_conf {
+    my ($conf) = @_;
+
+    foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+	if (-e "$path/$conf") {
+	    return "$path/$conf";
+	}
+    }
+
+    return "";
+}
+
+sub mailmap_email {
+    my ($line) = @_;
+
+    my ($name, $address) = parse_email($line);
+    my $email = format_email($name, $address, 1);
+    my $real_name = $name;
+    my $real_address = $address;
+
+    if (exists $mailmap->{names}->{$email} ||
+	exists $mailmap->{addresses}->{$email}) {
+	if (exists $mailmap->{names}->{$email}) {
+	    $real_name = $mailmap->{names}->{$email};
+	}
+	if (exists $mailmap->{addresses}->{$email}) {
+	    $real_address = $mailmap->{addresses}->{$email};
+	}
+    } else {
+	if (exists $mailmap->{names}->{$address}) {
+	    $real_name = $mailmap->{names}->{$address};
+	}
+	if (exists $mailmap->{addresses}->{$address}) {
+	    $real_address = $mailmap->{addresses}->{$address};
+	}
+    }
+    return format_email($real_name, $real_address, 1);
+}
+
+sub mailmap {
+    my (@addresses) = @_;
+
+    my @mapped_emails = ();
+    foreach my $line (@addresses) {
+	push(@mapped_emails, mailmap_email($line));
+    }
+    merge_by_realname(@mapped_emails) if ($email_use_mailmap);
+    return @mapped_emails;
+}
+
+sub merge_by_realname {
+    my %address_map;
+    my (@emails) = @_;
+
+    foreach my $email (@emails) {
+	my ($name, $address) = parse_email($email);
+	if (exists $address_map{$name}) {
+	    $address = $address_map{$name};
+	    $email = format_email($name, $address, 1);
+	} else {
+	    $address_map{$name} = $address;
+	}
+    }
+}
+
+sub git_execute_cmd {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    my $output = `$cmd`;
+    $output =~ s/^\s*//gm;
+    @lines = split("\n", $output);
+
+    return @lines;
+}
+
+sub hg_execute_cmd {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    my $output = `$cmd`;
+    @lines = split("\n", $output);
+
+    return @lines;
+}
+
+sub extract_formatted_signatures {
+    my (@signature_lines) = @_;
+
+    my @type = @signature_lines;
+
+    s/\s*(.*):.*/$1/ for (@type);
+
+    # cut -f2- -d":"
+    s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines);
+
+## Reformat email addresses (with names) to avoid badly written signatures
+
+    foreach my $signer (@signature_lines) {
+	$signer = deduplicate_email($signer);
+    }
+
+    return (\@type, \@signature_lines);
+}
+
+sub vcs_find_signers {
+    my ($cmd) = @_;
+    my $commits;
+    my @lines = ();
+    my @signatures = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    my $pattern = $VCS_cmds{"commit_pattern"};
+
+    $commits = grep(/$pattern/, @lines);	# of commits
+
+    @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
+
+    return (0, @signatures) if !@signatures;
+
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    if (!$email_git_penguin_chiefs) {
+	@signatures = grep(!/${penguin_chiefs}/i, @signatures);
+    }
+
+    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+
+    return ($commits, @$signers_ref);
+}
+
+sub vcs_find_author {
+    my ($cmd) = @_;
+    my @lines = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    if (!$email_git_penguin_chiefs) {
+	@lines = grep(!/${penguin_chiefs}/i, @lines);
+    }
+
+    return @lines if !@lines;
+
+    my @authors = ();
+    foreach my $line (@lines) {
+	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+	    my $author = $1;
+	    my ($name, $address) = parse_email($author);
+	    $author = format_email($name, $address, 1);
+	    push(@authors, $author);
+	}
+    }
+
+    save_commits_by_author(@lines) if ($interactive);
+    save_commits_by_signer(@lines) if ($interactive);
+
+    return @authors;
+}
+
+sub vcs_save_commits {
+    my ($cmd) = @_;
+    my @lines = ();
+    my @commits = ();
+
+    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    foreach my $line (@lines) {
+	if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) {
+	    push(@commits, $1);
+	}
+    }
+
+    return @commits;
+}
+
+sub vcs_blame {
+    my ($file) = @_;
+    my $cmd;
+    my @commits = ();
+
+    return @commits if (!(-f $file));
+
+    if (@range && $VCS_cmds{"blame_range_cmd"} eq "") {
+	my @all_commits = ();
+
+	$cmd = $VCS_cmds{"blame_file_cmd"};
+	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
+	@all_commits = vcs_save_commits($cmd);
+
+	foreach my $file_range_diff (@range) {
+	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
+	    my $diff_file = $1;
+	    my $diff_start = $2;
+	    my $diff_length = $3;
+	    next if ("$file" ne "$diff_file");
+	    for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) {
+		push(@commits, $all_commits[$i]);
+	    }
+	}
+    } elsif (@range) {
+	foreach my $file_range_diff (@range) {
+	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
+	    my $diff_file = $1;
+	    my $diff_start = $2;
+	    my $diff_length = $3;
+	    next if ("$file" ne "$diff_file");
+	    $cmd = $VCS_cmds{"blame_range_cmd"};
+	    $cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
+	    push(@commits, vcs_save_commits($cmd));
+	}
+    } else {
+	$cmd = $VCS_cmds{"blame_file_cmd"};
+	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
+	@commits = vcs_save_commits($cmd);
+    }
+
+    foreach my $commit (@commits) {
+	$commit =~ s/^\^//g;
+    }
+
+    return @commits;
+}
+
+my $printed_novcs = 0;
+sub vcs_exists {
+    %VCS_cmds = %VCS_cmds_git;
+    return 1 if eval $VCS_cmds{"available"};
+    %VCS_cmds = %VCS_cmds_hg;
+    return 2 if eval $VCS_cmds{"available"};
+    %VCS_cmds = ();
+    if (!$printed_novcs) {
+	warn("$P: No supported VCS found.  Add --nogit to options?\n");
+	warn("Using a git repository produces better results.\n");
+	warn("Try latest git repository using:\n");
+	warn("git clone git://git.qemu.org/qemu.git\n");
+	$printed_novcs = 1;
+    }
+    return 0;
+}
+
+sub vcs_is_git {
+    vcs_exists();
+    return $vcs_used == 1;
+}
+
+sub vcs_is_hg {
+    return $vcs_used == 2;
+}
+
+sub interactive_get_maintainers {
+    my ($list_ref) = @_;
+    my @list = @$list_ref;
+
+    vcs_exists();
+
+    my %selected;
+    my %authored;
+    my %signed;
+    my $count = 0;
+    my $maintained = 0;
+    foreach my $entry (@list) {
+	$maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
+	$selected{$count} = 1;
+	$authored{$count} = 0;
+	$signed{$count} = 0;
+	$count++;
+    }
+
+    #menu loop
+    my $done = 0;
+    my $print_options = 0;
+    my $redraw = 1;
+    while (!$done) {
+	$count = 0;
+	if ($redraw) {
+	    printf STDERR "\n%1s %2s %-65s",
+			  "*", "#", "email/list and role:stats";
+	    if ($email_git ||
+		($email_git_fallback && !$maintained) ||
+		$email_git_blame) {
+		print STDERR "auth sign";
+	    }
+	    print STDERR "\n";
+	    foreach my $entry (@list) {
+		my $email = $entry->[0];
+		my $role = $entry->[1];
+		my $sel = "";
+		$sel = "*" if ($selected{$count});
+		my $commit_author = $commit_author_hash{$email};
+		my $commit_signer = $commit_signer_hash{$email};
+		my $authored = 0;
+		my $signed = 0;
+		$authored++ for (@{$commit_author});
+		$signed++ for (@{$commit_signer});
+		printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
+		printf STDERR "%4d %4d", $authored, $signed
+		    if ($authored > 0 || $signed > 0);
+		printf STDERR "\n     %s\n", $role;
+		if ($authored{$count}) {
+		    my $commit_author = $commit_author_hash{$email};
+		    foreach my $ref (@{$commit_author}) {
+			print STDERR "     Author: @{$ref}[1]\n";
+		    }
+		}
+		if ($signed{$count}) {
+		    my $commit_signer = $commit_signer_hash{$email};
+		    foreach my $ref (@{$commit_signer}) {
+			print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
+		    }
+		}
+
+		$count++;
+	    }
+	}
+	my $date_ref = \$email_git_since;
+	$date_ref = \$email_hg_since if (vcs_is_hg());
+	if ($print_options) {
+	    $print_options = 0;
+	    if (vcs_exists()) {
+		print STDERR <<EOT
+
+Version Control options:
+g  use git history      [$email_git]
+gf use git-fallback     [$email_git_fallback]
+b  use git blame        [$email_git_blame]
+bs use blame signatures [$email_git_blame_signatures]
+c# minimum commits      [$email_git_min_signatures]
+%# min percent          [$email_git_min_percent]
+d# history to use       [$$date_ref]
+x# max maintainers      [$email_git_max_maintainers]
+t  all signature types  [$email_git_all_signature_types]
+m  use .mailmap         [$email_use_mailmap]
+EOT
+	    }
+	    print STDERR <<EOT
+
+Additional options:
+0  toggle all
+tm toggle maintainers
+tg toggle git entries
+tl toggle open list entries
+ts toggle subscriber list entries
+f  emails in file       [$file_emails]
+k  keywords in file     [$keywords]
+r  remove duplicates    [$email_remove_duplicates]
+p# pattern match depth  [$pattern_depth]
+EOT
+	}
+	print STDERR
+"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
+
+	my $input = <STDIN>;
+	chomp($input);
+
+	$redraw = 1;
+	my $rerun = 0;
+	my @wish = split(/[, ]+/, $input);
+	foreach my $nr (@wish) {
+	    $nr = lc($nr);
+	    my $sel = substr($nr, 0, 1);
+	    my $str = substr($nr, 1);
+	    my $val = 0;
+	    $val = $1 if $str =~ /^(\d+)$/;
+
+	    if ($sel eq "y") {
+		$interactive = 0;
+		$done = 1;
+		$output_rolestats = 0;
+		$output_roles = 0;
+		last;
+	    } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
+		$selected{$nr - 1} = !$selected{$nr - 1};
+	    } elsif ($sel eq "*" || $sel eq '^') {
+		my $toggle = 0;
+		$toggle = 1 if ($sel eq '*');
+		for (my $i = 0; $i < $count; $i++) {
+		    $selected{$i} = $toggle;
+		}
+	    } elsif ($sel eq "0") {
+		for (my $i = 0; $i < $count; $i++) {
+		    $selected{$i} = !$selected{$i};
+		}
+	    } elsif ($sel eq "t") {
+		if (lc($str) eq "m") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
+		    }
+		} elsif (lc($str) eq "g") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
+		    }
+		} elsif (lc($str) eq "l") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(open list)/i);
+		    }
+		} elsif (lc($str) eq "s") {
+		    for (my $i = 0; $i < $count; $i++) {
+			$selected{$i} = !$selected{$i}
+			    if ($list[$i]->[1] =~ /^(subscriber list)/i);
+		    }
+		}
+	    } elsif ($sel eq "a") {
+		if ($val > 0 && $val <= $count) {
+		    $authored{$val - 1} = !$authored{$val - 1};
+		} elsif ($str eq '*' || $str eq '^') {
+		    my $toggle = 0;
+		    $toggle = 1 if ($str eq '*');
+		    for (my $i = 0; $i < $count; $i++) {
+			$authored{$i} = $toggle;
+		    }
+		}
+	    } elsif ($sel eq "s") {
+		if ($val > 0 && $val <= $count) {
+		    $signed{$val - 1} = !$signed{$val - 1};
+		} elsif ($str eq '*' || $str eq '^') {
+		    my $toggle = 0;
+		    $toggle = 1 if ($str eq '*');
+		    for (my $i = 0; $i < $count; $i++) {
+			$signed{$i} = $toggle;
+		    }
+		}
+	    } elsif ($sel eq "o") {
+		$print_options = 1;
+		$redraw = 1;
+	    } elsif ($sel eq "g") {
+		if ($str eq "f") {
+		    bool_invert(\$email_git_fallback);
+		} else {
+		    bool_invert(\$email_git);
+		}
+		$rerun = 1;
+	    } elsif ($sel eq "b") {
+		if ($str eq "s") {
+		    bool_invert(\$email_git_blame_signatures);
+		} else {
+		    bool_invert(\$email_git_blame);
+		}
+		$rerun = 1;
+	    } elsif ($sel eq "c") {
+		if ($val > 0) {
+		    $email_git_min_signatures = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "x") {
+		if ($val > 0) {
+		    $email_git_max_maintainers = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "%") {
+		if ($str ne "" && $val >= 0) {
+		    $email_git_min_percent = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "d") {
+		if (vcs_is_git()) {
+		    $email_git_since = $str;
+		} elsif (vcs_is_hg()) {
+		    $email_hg_since = $str;
+		}
+		$rerun = 1;
+	    } elsif ($sel eq "t") {
+		bool_invert(\$email_git_all_signature_types);
+		$rerun = 1;
+	    } elsif ($sel eq "f") {
+		bool_invert(\$file_emails);
+		$rerun = 1;
+	    } elsif ($sel eq "r") {
+		bool_invert(\$email_remove_duplicates);
+		$rerun = 1;
+	    } elsif ($sel eq "m") {
+		bool_invert(\$email_use_mailmap);
+		read_mailmap();
+		$rerun = 1;
+	    } elsif ($sel eq "k") {
+		bool_invert(\$keywords);
+		$rerun = 1;
+	    } elsif ($sel eq "p") {
+		if ($str ne "" && $val >= 0) {
+		    $pattern_depth = $val;
+		    $rerun = 1;
+		}
+	    } elsif ($sel eq "h" || $sel eq "?") {
+		print STDERR <<EOT
+
+Interactive mode allows you to select the various maintainers, submitters,
+commit signers and mailing lists that could be CC'd on a patch.
+
+Any *'d entry is selected.
+
+If you have git or hg installed, you can choose to summarize the commit
+history of files in the patch.  Also, each line of the current file can
+be matched to its commit author and that commits signers with blame.
+
+Various knobs exist to control the length of time for active commit
+tracking, the maximum number of commit authors and signers to add,
+and such.
+
+Enter selections at the prompt until you are satisfied that the selected
+maintainers are appropriate.  You may enter multiple selections separated
+by either commas or spaces.
+
+EOT
+	    } else {
+		print STDERR "invalid option: '$nr'\n";
+		$redraw = 0;
+	    }
+	}
+	if ($rerun) {
+	    print STDERR "git-blame can be very slow, please have patience..."
+		if ($email_git_blame);
+	    goto &get_maintainers;
+	}
+    }
+
+    #drop not selected entries
+    $count = 0;
+    my @new_emailto = ();
+    foreach my $entry (@list) {
+	if ($selected{$count}) {
+	    push(@new_emailto, $list[$count]);
+	}
+	$count++;
+    }
+    return @new_emailto;
+}
+
+sub bool_invert {
+    my ($bool_ref) = @_;
+
+    if ($$bool_ref) {
+	$$bool_ref = 0;
+    } else {
+	$$bool_ref = 1;
+    }
+}
+
+sub deduplicate_email {
+    my ($email) = @_;
+
+    my $matched = 0;
+    my ($name, $address) = parse_email($email);
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+
+    return $email if (!$email_remove_duplicates);
+
+    ($name, $address) = parse_email($email);
+
+    if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
+	$name = $deduplicate_name_hash{lc($name)}->[0];
+	$address = $deduplicate_name_hash{lc($name)}->[1];
+	$matched = 1;
+    } elsif ($deduplicate_address_hash{lc($address)}) {
+	$name = $deduplicate_address_hash{lc($address)}->[0];
+	$address = $deduplicate_address_hash{lc($address)}->[1];
+	$matched = 1;
+    }
+    if (!$matched) {
+	$deduplicate_name_hash{lc($name)} = [ $name, $address ];
+	$deduplicate_address_hash{lc($address)} = [ $name, $address ];
+    }
+    $email = format_email($name, $address, 1);
+    $email = mailmap_email($email);
+    return $email;
+}
+
+sub save_commits_by_author {
+    my (@lines) = @_;
+
+    my @authors = ();
+    my @commits = ();
+    my @subjects = ();
+
+    foreach my $line (@lines) {
+	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+	    my $author = $1;
+	    $author = deduplicate_email($author);
+	    push(@authors, $author);
+	}
+	push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+	push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+    }
+
+    for (my $i = 0; $i < @authors; $i++) {
+	my $exists = 0;
+	foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
+	    if (@{$ref}[0] eq $commits[$i] &&
+		@{$ref}[1] eq $subjects[$i]) {
+		$exists = 1;
+		last;
+	    }
+	}
+	if (!$exists) {
+	    push(@{$commit_author_hash{$authors[$i]}},
+		 [ ($commits[$i], $subjects[$i]) ]);
+	}
+    }
+}
+
+sub save_commits_by_signer {
+    my (@lines) = @_;
+
+    my $commit = "";
+    my $subject = "";
+
+    foreach my $line (@lines) {
+	$commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
+	$subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
+	if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
+	    my @signatures = ($line);
+	    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+	    my @types = @$types_ref;
+	    my @signers = @$signers_ref;
+
+	    my $type = $types[0];
+	    my $signer = $signers[0];
+
+	    $signer = deduplicate_email($signer);
+
+	    my $exists = 0;
+	    foreach my $ref(@{$commit_signer_hash{$signer}}) {
+		if (@{$ref}[0] eq $commit &&
+		    @{$ref}[1] eq $subject &&
+		    @{$ref}[2] eq $type) {
+		    $exists = 1;
+		    last;
+		}
+	    }
+	    if (!$exists) {
+		push(@{$commit_signer_hash{$signer}},
+		     [ ($commit, $subject, $type) ]);
+	    }
+	}
+    }
+}
+
+sub vcs_assign {
+    my ($role, $divisor, @lines) = @_;
+
+    my %hash;
+    my $count = 0;
+
+    return if (@lines <= 0);
+
+    if ($divisor <= 0) {
+	warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n");
+	$divisor = 1;
+    }
+
+    @lines = mailmap(@lines);
+
+    return if (@lines <= 0);
+
+    @lines = sort(@lines);
+
+    # uniq -c
+    $hash{$_}++ for @lines;
+
+    # sort -rn
+    foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
+	my $sign_offs = $hash{$line};
+	my $percent = $sign_offs * 100 / $divisor;
+
+	$percent = 100 if ($percent > 100);
+	$count++;
+	last if ($sign_offs < $email_git_min_signatures ||
+		 $count > $email_git_max_maintainers ||
+		 $percent < $email_git_min_percent);
+	push_email_address($line, '');
+	if ($output_rolestats) {
+	    my $fmt_percent = sprintf("%.0f", $percent);
+	    add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%");
+	} else {
+	    add_role($line, $role);
+	}
+    }
+}
+
+sub vcs_file_signoffs {
+    my ($file) = @_;
+
+    my @signers = ();
+    my $commits;
+
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
+
+    my $cmd = $VCS_cmds{"find_signers_cmd"};
+    $cmd =~ s/(\$\w+)/$1/eeg;		# interpolate $cmd
+
+    ($commits, @signers) = vcs_find_signers($cmd);
+
+    foreach my $signer (@signers) {
+	$signer = deduplicate_email($signer);
+    }
+
+    vcs_assign("commit_signer", $commits, @signers);
+}
+
+sub vcs_file_blame {
+    my ($file) = @_;
+
+    my @signers = ();
+    my @all_commits = ();
+    my @commits = ();
+    my $total_commits;
+    my $total_lines;
+
+    $vcs_used = vcs_exists();
+    return if (!$vcs_used);
+
+    @all_commits = vcs_blame($file);
+    @commits = uniq(@all_commits);
+    $total_commits = @commits;
+    $total_lines = @all_commits;
+
+    if ($email_git_blame_signatures) {
+	if (vcs_is_hg()) {
+	    my $commit_count;
+	    my @commit_signers = ();
+	    my $commit = join(" -r ", @commits);
+	    my $cmd;
+
+	    $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+	    $cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
+
+	    ($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+	    push(@signers, @commit_signers);
+	} else {
+	    foreach my $commit (@commits) {
+		my $commit_count;
+		my @commit_signers = ();
+		my $cmd;
+
+		$cmd = $VCS_cmds{"find_commit_signers_cmd"};
+		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
+
+		($commit_count, @commit_signers) = vcs_find_signers($cmd);
+
+		push(@signers, @commit_signers);
+	    }
+	}
+    }
+
+    if ($from_filename) {
+	if ($output_rolestats) {
+	    my @blame_signers;
+	    if (vcs_is_hg()) {{		# Double brace for last exit
+		my $commit_count;
+		my @commit_signers = ();
+		@commits = uniq(@commits);
+		@commits = sort(@commits);
+		my $commit = join(" -r ", @commits);
+		my $cmd;
+
+		$cmd = $VCS_cmds{"find_commit_author_cmd"};
+		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
+
+		my @lines = ();
+
+		@lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+		if (!$email_git_penguin_chiefs) {
+		    @lines = grep(!/${penguin_chiefs}/i, @lines);
+		}
+
+		last if !@lines;
+
+		my @authors = ();
+		foreach my $line (@lines) {
+		    if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
+			my $author = $1;
+			$author = deduplicate_email($author);
+			push(@authors, $author);
+		    }
+		}
+
+		save_commits_by_author(@lines) if ($interactive);
+		save_commits_by_signer(@lines) if ($interactive);
+
+		push(@signers, @authors);
+	    }}
+	    else {
+		foreach my $commit (@commits) {
+		    my $i;
+		    my $cmd = $VCS_cmds{"find_commit_author_cmd"};
+		    $cmd =~ s/(\$\w+)/$1/eeg;	#interpolate $cmd
+		    my @author = vcs_find_author($cmd);
+		    next if !@author;
+
+		    my $formatted_author = deduplicate_email($author[0]);
+
+		    my $count = grep(/$commit/, @all_commits);
+		    for ($i = 0; $i < $count ; $i++) {
+			push(@blame_signers, $formatted_author);
+		    }
+		}
+	    }
+	    if (@blame_signers) {
+		vcs_assign("authored lines", $total_lines, @blame_signers);
+	    }
+	}
+	foreach my $signer (@signers) {
+	    $signer = deduplicate_email($signer);
+	}
+	vcs_assign("commits", $total_commits, @signers);
+    } else {
+	foreach my $signer (@signers) {
+	    $signer = deduplicate_email($signer);
+	}
+	vcs_assign("modified commits", $total_commits, @signers);
+    }
+}
+
+sub uniq {
+    my (@parms) = @_;
+
+    my %saw;
+    @parms = grep(!$saw{$_}++, @parms);
+    return @parms;
+}
+
+sub sort_and_uniq {
+    my (@parms) = @_;
+
+    my %saw;
+    @parms = sort @parms;
+    @parms = grep(!$saw{$_}++, @parms);
+    return @parms;
+}
+
+sub clean_file_emails {
+    my (@file_emails) = @_;
+    my @fmt_emails = ();
+
+    foreach my $email (@file_emails) {
+	$email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g;
+	my ($name, $address) = parse_email($email);
+	if ($name eq '"[,\.]"') {
+	    $name = "";
+	}
+
+	my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name);
+	if (@nw > 2) {
+	    my $first = $nw[@nw - 3];
+	    my $middle = $nw[@nw - 2];
+	    my $last = $nw[@nw - 1];
+
+	    if (((length($first) == 1 && $first =~ m/[A-Za-z]/) ||
+		 (length($first) == 2 && substr($first, -1) eq ".")) ||
+		(length($middle) == 1 ||
+		 (length($middle) == 2 && substr($middle, -1) eq "."))) {
+		$name = "$first $middle $last";
+	    } else {
+		$name = "$middle $last";
+	    }
+	}
+
+	if (substr($name, -1) =~ /[,\.]/) {
+	    $name = substr($name, 0, length($name) - 1);
+	} elsif (substr($name, -2) =~ /[,\.]"/) {
+	    $name = substr($name, 0, length($name) - 2) . '"';
+	}
+
+	if (substr($name, 0, 1) =~ /[,\.]/) {
+	    $name = substr($name, 1, length($name) - 1);
+	} elsif (substr($name, 0, 2) =~ /"[,\.]/) {
+	    $name = '"' . substr($name, 2, length($name) - 2);
+	}
+
+	my $fmt_email = format_email($name, $address, $email_usename);
+	push(@fmt_emails, $fmt_email);
+    }
+    return @fmt_emails;
+}
+
+sub merge_email {
+    my @lines;
+    my %saw;
+
+    for (@_) {
+	my ($address, $role) = @$_;
+	if (!$saw{$address}) {
+	    if ($output_roles) {
+		push(@lines, "$address ($role)");
+	    } else {
+		push(@lines, $address);
+	    }
+	    $saw{$address} = 1;
+	}
+    }
+
+    return @lines;
+}
+
+sub output {
+    my (@parms) = @_;
+
+    if ($output_multiline) {
+	foreach my $line (@parms) {
+	    print("${line}\n");
+	}
+    } else {
+	print(join($output_separator, @parms));
+	print("\n");
+    }
+}
+
+my $rfc822re;
+
+sub make_rfc822re {
+#   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
+#   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
+#   This regexp will only work on addresses which have had comments stripped
+#   and replaced with rfc822_lwsp.
+
+    my $specials = '()<>@,;:\\\\".\\[\\]';
+    my $controls = '\\000-\\037\\177';
+
+    my $dtext = "[^\\[\\]\\r\\\\]";
+    my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*";
+
+    my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*";
+
+#   Use zero-width assertion to spot the limit of an atom.  A simple
+#   $rfc822_lwsp* causes the regexp engine to hang occasionally.
+    my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
+    my $word = "(?:$atom|$quoted_string)";
+    my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*";
+
+    my $sub_domain = "(?:$atom|$domain_literal)";
+    my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
+
+    my $addr_spec = "$localpart\@$rfc822_lwsp*$domain";
+
+    my $phrase = "$word*";
+    my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
+    my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*";
+    my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
+
+    my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
+    my $address = "(?:$mailbox|$group)";
+
+    return "$rfc822_lwsp*$address";
+}
+
+sub rfc822_strip_comments {
+    my $s = shift;
+#   Recursively remove comments, and replace with a single space.  The simpler
+#   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
+#   chars in atoms, for example.
+
+    while ($s =~ s/^((?:[^"\\]|\\.)*
+                    (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
+                    \((?:[^()\\]|\\.)*\)/$1 /osx) {}
+    return $s;
+}
+
+#   valid: returns true if the parameter is an RFC822 valid address
+#
+sub rfc822_valid {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+
+    return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/;
+}
+
+#   validlist: In scalar context, returns true if the parameter is an RFC822
+#              valid list of addresses.
+#
+#              In list context, returns an empty list on failure (an invalid
+#              address was found); otherwise a list whose first element is the
+#              number of addresses found and whose remaining elements are the
+#              addresses.  This is needed to disambiguate failure (invalid)
+#              from success with no addresses found, because an empty string is
+#              a valid list.
+
+sub rfc822_validlist {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+    # * null list items are valid according to the RFC
+    # * the '1' business is to aid in distinguishing failure from no results
+
+    my @r;
+    if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so &&
+	$s =~ m/^$rfc822_char*$/) {
+        while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) {
+            push(@r, $1);
+        }
+        return wantarray ? (scalar(@r), @r) : 1;
+    }
+    return wantarray ? () : 0;
+}

+ 7 - 3
target-alpha/translate.c

@@ -1661,9 +1661,12 @@ static void gen_mtpr(int rb, int regno)
 static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
 static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
 {
 {
     uint32_t palcode;
     uint32_t palcode;
-    int32_t disp21, disp16, disp12;
+    int32_t disp21, disp16;
+#ifndef CONFIG_USER_ONLY
+    int32_t disp12;
+#endif
     uint16_t fn11;
     uint16_t fn11;
-    uint8_t opc, ra, rb, rc, fpfn, fn7, fn2, islit, real_islit;
+    uint8_t opc, ra, rb, rc, fpfn, fn7, islit, real_islit;
     uint8_t lit;
     uint8_t lit;
     ExitStatus ret;
     ExitStatus ret;
 
 
@@ -1681,11 +1684,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     palcode = insn & 0x03FFFFFF;
     palcode = insn & 0x03FFFFFF;
     disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11;
     disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11;
     disp16 = (int16_t)(insn & 0x0000FFFF);
     disp16 = (int16_t)(insn & 0x0000FFFF);
+#ifndef CONFIG_USER_ONLY
     disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20;
     disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20;
+#endif
     fn11 = (insn >> 5) & 0x000007FF;
     fn11 = (insn >> 5) & 0x000007FF;
     fpfn = fn11 & 0x3F;
     fpfn = fn11 & 0x3F;
     fn7 = (insn >> 5) & 0x0000007F;
     fn7 = (insn >> 5) & 0x0000007F;
-    fn2 = (insn >> 5) & 0x00000003;
     LOG_DISAS("opc %02x ra %2d rb %2d rc %2d disp16 %6d\n",
     LOG_DISAS("opc %02x ra %2d rb %2d rc %2d disp16 %6d\n",
               opc, ra, rb, rc, disp16);
               opc, ra, rb, rc, disp16);