Patchwork [03/10] pci: fix pci_bus_reset() with 64bit BAR and several clean ups.

login
register
mail settings
Submitter Isaku Yamahata
Date June 17, 2010, 6:15 a.m.
Message ID <551d7f5ea27a3bf8fcf69dea059d237493a92a2b.1276755023.git.yamahata@valinux.co.jp>
Download mbox | patch
Permalink /patch/55968/
State New
Headers show

Comments

Isaku Yamahata - June 17, 2010, 6:15 a.m.
fix pci_device_reset() with 64bit BAR.
export pci_bus_reset(), pci_device_reset() and two helper functions
for later use. And several clean ups.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
 hw/pci.c |   44 ++++++++++++++++++++++++++++++++++++--------
 hw/pci.h |    5 +++++
 2 files changed, 41 insertions(+), 8 deletions(-)

Patch

diff --git a/hw/pci.c b/hw/pci.c
index 9ba62eb..87f5e6c 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -144,28 +144,50 @@  static void pci_update_irq_status(PCIDevice *dev)
     }
 }
 
-static void pci_device_reset(PCIDevice *dev)
+void pci_device_reset_default(PCIDevice *dev)
 {
     int r;
 
     dev->irq_state = 0;
     pci_update_irq_status(dev);
-    dev->config[PCI_COMMAND] &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-                                  PCI_COMMAND_MASTER);
+    pci_set_word(dev->config + PCI_COMMAND,
+                 pci_get_word(dev->config + PCI_COMMAND) &
+                 ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
     dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
     dev->config[PCI_INTERRUPT_LINE] = 0x0;
     for (r = 0; r < PCI_NUM_REGIONS; ++r) {
-        if (!dev->io_regions[r].size) {
+        PCIIORegion *region = &dev->io_regions[r];
+        if (!region->size) {
             continue;
         }
-        pci_set_long(dev->config + pci_bar(dev, r), dev->io_regions[r].type);
+
+        if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
+            region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+            pci_set_quad(dev->config + pci_bar(dev, r), region->type);
+        } else {
+            pci_set_long(dev->config + pci_bar(dev, r), region->type);
+        }
     }
     pci_update_mappings(dev);
 }
 
-static void pci_bus_reset(void *opaque)
+void pci_device_reset(PCIDevice *dev)
+{
+    if (!dev->qdev.info) {
+        /* for not qdevified device */
+        pci_device_reset_default(dev);
+        return;
+    }
+
+    qdev_reset(&dev->qdev);
+
+    /* TODO: make DeviceInfo::reset call
+       pci_device_reset_default() itself. */
+    pci_device_reset_default(dev);
+}
+
+void pci_bus_reset(PCIBus *bus)
 {
-    PCIBus *bus = opaque;
     int i;
 
     for (i = 0; i < bus->nirq; i++) {
@@ -178,6 +200,12 @@  static void pci_bus_reset(void *opaque)
     }
 }
 
+static void pci_bus_resetfn(void *opaque)
+{
+    PCIBus *bus = opaque;
+    pci_bus_reset(bus);
+}
+
 static void pci_host_bus_register(int domain, PCIBus *bus)
 {
     struct PCIHostBus *host;
@@ -231,7 +259,7 @@  void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
     pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */
 
     vmstate_register(-1, &vmstate_pcibus, bus);
-    qemu_register_reset(pci_bus_reset, bus);
+    qemu_register_reset(pci_bus_resetfn, bus);
 }
 
 PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min)
diff --git a/hw/pci.h b/hw/pci.h
index f6e2551..2a2c8ef 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -199,6 +199,11 @@  int pci_device_load(PCIDevice *s, QEMUFile *f);
 typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
 typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, int state);
+
+void pci_device_reset_default(PCIDevice *dev);
+void pci_device_reset(PCIDevice *dev);
+void pci_bus_reset(PCIBus *bus);
+
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          const char *name, int devfn_min);
 PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min);