]> Git Repo - qemu.git/blobdiff - hw/pci.c
pci: allow loading roms via fw_cfg.
[qemu.git] / hw / pci.c
index b0c32c69e5d9599c7f30f10bec3c6db057a0504f..2bdf27e04d787f7b05f8011d1ad93a18f5152b4e 100644 (file)
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -41,7 +41,6 @@ struct PCIBus {
     pci_set_irq_fn set_irq;
     pci_map_irq_fn map_irq;
     pci_hotplug_fn hotplug;
-    uint32_t config_reg; /* XXX: suppress */
     void *irq_opaque;
     PCIDevice *devices[256];
     PCIDevice *parent_dev;
@@ -65,6 +64,7 @@ static struct BusInfo pci_bus_info = {
     .props      = (Property[]) {
         DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
         DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
+        DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
         DEFINE_PROP_END_OF_LIST()
     }
 };
@@ -420,7 +420,7 @@ static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
 {
     uint16_t *id;
 
-    id = (void*)(&pci_dev->config[PCI_SUBVENDOR_ID]);
+    id = (void*)(&pci_dev->config[PCI_SUBSYSTEM_VENDOR_ID]);
     id[0] = cpu_to_le16(pci_default_sub_vendor_id);
     id[1] = cpu_to_le16(pci_default_sub_device_id);
     return 0;
@@ -526,7 +526,8 @@ static void pci_init_wmask(PCIDevice *dev)
     dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff;
     dev->wmask[PCI_INTERRUPT_LINE] = 0xff;
     pci_set_word(dev->wmask + PCI_COMMAND,
-                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+                 PCI_COMMAND_INTX_DISABLE);
 
     memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
            config_size - PCI_CONFIG_HEADER_SIZE);
@@ -899,7 +900,7 @@ static void pci_update_mappings(PCIDevice *d)
 {
     PCIIORegion *r;
     int i;
-    pcibus_t new_addr, filtered_size, bus_addr;
+    pcibus_t new_addr, filtered_size;
 
     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
@@ -921,7 +922,6 @@ static void pci_update_mappings(PCIDevice *d)
             continue;
 
         /* now do the real mapping */
-        bus_addr = r->addr;
         if (r->addr != PCI_BAR_UNMAPPED) {
             if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
                 int class;
@@ -934,8 +934,7 @@ static void pci_update_mappings(PCIDevice *d)
                     isa_unassign_ioport(r->addr, r->filtered_size);
                 }
             } else {
-                bus_addr = pci_to_cpu_addr(d->bus, r->addr);
-                cpu_register_physical_memory(bus_addr,
+                cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
                                              r->filtered_size,
                                              IO_MEM_UNASSIGNED);
                 qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
@@ -951,11 +950,35 @@ static void pci_update_mappings(PCIDevice *d)
              * Teach them such cases, such that filtered_size < size and
              * addr & (size - 1) != 0.
              */
-            r->map_func(d, i, bus_addr, r->filtered_size, r->type);
+            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+                r->map_func(d, i, r->addr, r->filtered_size, r->type);
+            } else {
+                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
+                            r->filtered_size, r->type);
+            }
         }
     }
 }
 
+static inline int pci_irq_disabled(PCIDevice *d)
+{
+    return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
+}
+
+/* Called after interrupt disabled field update in config space,
+ * assert/deassert interrupts if necessary.
+ * Gets original interrupt disable bit value (before update). */
+static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled)
+{
+    int i, disabled = pci_irq_disabled(d);
+    if (disabled == was_irq_disabled)
+        return;
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        int state = pci_irq_state(d, i);
+        pci_change_irq_level(d, i, disabled ? -state : state);
+    }
+}
+
 uint32_t pci_default_read_config(PCIDevice *d,
                                  uint32_t address, int len)
 {
@@ -968,7 +991,7 @@ uint32_t pci_default_read_config(PCIDevice *d,
 
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
-    int i;
+    int i, was_irq_disabled = pci_irq_disabled(d);
     uint32_t config_size = pci_config_size(d);
 
     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
@@ -980,6 +1003,9 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
         ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
         range_covers_byte(addr, l, PCI_COMMAND))
         pci_update_mappings(d);
+
+    if (range_covers_byte(addr, l, PCI_COMMAND))
+        pci_update_irq_disabled(d, was_irq_disabled);
 }
 
 /***********************************************************/
@@ -997,6 +1023,8 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
 
     pci_set_irq_state(pci_dev, irq_num, level);
     pci_update_irq_status(pci_dev);
+    if (pci_irq_disabled(pci_dev))
+        return;
     pci_change_irq_level(pci_dev, irq_num, change);
 }
 
@@ -1474,6 +1502,20 @@ static int pci_add_option_rom(PCIDevice *pdev)
     if (strlen(pdev->romfile) == 0)
         return 0;
 
+    if (!pdev->rom_bar) {
+        /*
+         * Load rom via fw_cfg instead of creating a rom bar,
+         * for 0.11 compatibility.
+         */
+        int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
+        if (class == 0x0300) {
+            rom_add_vga(pdev->romfile);
+        } else {
+            rom_add_option(pdev->romfile);
+        }
+        return 0;
+    }
+
     path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
     if (path == NULL) {
         path = qemu_strdup(pdev->romfile);
This page took 0.031258 seconds and 4 git commands to generate.