[PATCH] PCI: reverse pci config space restore order
[safe/jmp/linux-2.6] / drivers / pci / pci.c
index bea1ad1..1228627 100644 (file)
@@ -307,9 +307,11 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
         * Can enter D0 from any state, but if we can only go deeper 
         * to sleep if we're already in a low power state
         */
-       if (state != PCI_D0 && dev->current_state > state)
+       if (state != PCI_D0 && dev->current_state > state) {
+               printk(KERN_ERR "%s(): %s: state=%d, current state=%d\n",
+                       __FUNCTION__, pci_name(dev), state, dev->current_state);
                return -EINVAL;
-       else if (dev->current_state == state) 
+       } else if (dev->current_state == state)
                return 0;        /* we're already there */
 
        /* find PCI PM capability in list */
@@ -444,6 +446,10 @@ pci_save_state(struct pci_dev *dev)
        /* XXX: 100% dword access ok here? */
        for (i = 0; i < 16; i++)
                pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
+       if ((i = pci_save_msi_state(dev)) != 0)
+               return i;
+       if ((i = pci_save_msix_state(dev)) != 0)
+               return i;
        return 0;
 }
 
@@ -455,9 +461,25 @@ int
 pci_restore_state(struct pci_dev *dev)
 {
        int i;
+       int val;
 
-       for (i = 0; i < 16; i++)
-               pci_write_config_dword(dev,i * 4, dev->saved_config_space[i]);
+       /*
+        * The Base Address register should be programmed before the command
+        * register(s)
+        */
+       for (i = 15; i >= 0; i--) {
+               pci_read_config_dword(dev, i * 4, &val);
+               if (val != dev->saved_config_space[i]) {
+                       printk(KERN_DEBUG "PM: Writing back config space on "
+                               "device %s at offset %x (was %x, writing %x)\n",
+                               pci_name(dev), i,
+                               val, (int)dev->saved_config_space[i]);
+                       pci_write_config_dword(dev,i * 4,
+                               dev->saved_config_space[i]);
+               }
+       }
+       pci_restore_msi_state(dev);
+       pci_restore_msix_state(dev);
        return 0;
 }