PCI PM: Fix pci_update_current_state
[cascardo/linux.git] / drivers / pci / pci.c
index bd52ca4..9d2aa63 100644 (file)
@@ -56,6 +56,22 @@ unsigned char pci_bus_max_busnr(struct pci_bus* bus)
 }
 EXPORT_SYMBOL_GPL(pci_bus_max_busnr);
 
+#ifdef CONFIG_HAS_IOMEM
+void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
+{
+       /*
+        * Make sure the BAR is actually a memory resource, not an IO resource
+        */
+       if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
+               WARN_ON(1);
+               return NULL;
+       }
+       return ioremap_nocache(pci_resource_start(pdev, bar),
+                                    pci_resource_len(pdev, bar));
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_bar);
+#endif
+
 #if 0
 /**
  * pci_max_busnr - returns maximum PCI bus number
@@ -360,25 +376,10 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
 static void
 pci_restore_bars(struct pci_dev *dev)
 {
-       int i, numres;
-
-       switch (dev->hdr_type) {
-       case PCI_HEADER_TYPE_NORMAL:
-               numres = 6;
-               break;
-       case PCI_HEADER_TYPE_BRIDGE:
-               numres = 2;
-               break;
-       case PCI_HEADER_TYPE_CARDBUS:
-               numres = 1;
-               break;
-       default:
-               /* Should never get here, but just in case... */
-               return;
-       }
+       int i;
 
-       for (i = 0; i < numres; i ++)
-               pci_update_resource(dev, &dev->resource[i], i);
+       for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
+               pci_update_resource(dev, i);
 }
 
 static struct pci_platform_pm_ops *pci_platform_pm;
@@ -524,14 +525,17 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
  * pci_update_current_state - Read PCI power state of given device from its
  *                            PCI PM registers and cache it
  * @dev: PCI device to handle.
+ * @state: State to cache in case the device doesn't have the PM capability
  */
-static void pci_update_current_state(struct pci_dev *dev)
+static void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
 {
        if (dev->pm_cap) {
                u16 pmcsr;
 
                pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
                dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
+       } else {
+               dev->current_state = state;
        }
 }
 
@@ -574,7 +578,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                 */
                int ret = platform_pci_set_power_state(dev, PCI_D0);
                if (!ret)
-                       pci_update_current_state(dev);
+                       pci_update_current_state(dev, PCI_D0);
        }
        /* This device is quirked not to be put into D3, so
           don't put it in D3 */
@@ -587,7 +591,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                /* Allow the platform to finalize the transition */
                int ret = platform_pci_set_power_state(dev, state);
                if (!ret) {
-                       pci_update_current_state(dev);
+                       pci_update_current_state(dev, state);
                        error = 0;
                }
        }
@@ -1091,7 +1095,7 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
        int error = 0;
        bool pme_done = false;
 
-       if (!device_may_wakeup(&dev->dev))
+       if (enable && !device_may_wakeup(&dev->dev))
                return -EINVAL;
 
        /*
@@ -1284,6 +1288,26 @@ void pci_pm_init(struct pci_dev *dev)
        }
 }
 
+/**
+ * platform_pci_wakeup_init - init platform wakeup if present
+ * @dev: PCI device
+ *
+ * Some devices don't have PCI PM caps but can still generate wakeup
+ * events through platform methods (like ACPI events).  If @dev supports
+ * platform wakeup events, set the device flag to indicate as much.  This
+ * may be redundant if the device also supports PCI PM caps, but double
+ * initialization should be safe in that case.
+ */
+void platform_pci_wakeup_init(struct pci_dev *dev)
+{
+       if (!platform_pci_can_wakeup(dev))
+               return;
+
+       device_set_wakeup_capable(&dev->dev, true);
+       device_set_wakeup_enable(&dev->dev, false);
+       platform_pci_sleep_wake(dev, false);
+}
+
 /**
  * pci_add_save_buffer - allocate buffer for saving given capability registers
  * @dev: the PCI device
@@ -1366,6 +1390,20 @@ void pci_enable_ari(struct pci_dev *dev)
        bridge->ari_enabled = 1;
 }
 
+/**
+ * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
+ * @dev: the PCI device
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * Perform INTx swizzling for a device behind one level of bridge.  This is
+ * required by section 9.1 of the PCI-to-PCI bridge specification for devices
+ * behind bridges on add-in cards.
+ */
+u8 pci_swizzle_interrupt_pin(struct pci_dev *dev, u8 pin)
+{
+       return (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1;
+}
+
 int
 pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
 {
@@ -1376,7 +1414,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
                return -1;
 
        while (dev->bus->self) {
-               pin = (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1;
+               pin = pci_swizzle_interrupt_pin(dev, pin);
                dev = dev->bus->self;
        }
        *bridge = dev;
@@ -2186,6 +2224,28 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
        return bars;
 }
 
+/**
+ * pci_resource_bar - get position of the BAR associated with a resource
+ * @dev: the PCI device
+ * @resno: the resource number
+ * @type: the BAR type to be filled in
+ *
+ * Returns BAR position in config space, or 0 if the BAR is invalid.
+ */
+int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
+{
+       if (resno < PCI_ROM_RESOURCE) {
+               *type = pci_bar_unknown;
+               return PCI_BASE_ADDRESS_0 + 4 * resno;
+       } else if (resno == PCI_ROM_RESOURCE) {
+               *type = pci_bar_mem32;
+               return dev->rom_base_reg;
+       }
+
+       dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno);
+       return 0;
+}
+
 static void __devinit pci_no_domains(void)
 {
 #ifdef CONFIG_PCI_DOMAINS