reiserfs: replace inode uid,gid,mode initialization with helper function
[safe/jmp/linux-2.6] / drivers / pci / pcie / portdrv_core.c
index 079bbc3..e73effb 100644 (file)
@@ -27,7 +27,7 @@
  */
 static void release_pcie_device(struct device *dev)
 {
-       kfree(to_pcie_device(dev));                     
+       kfree(to_pcie_device(dev));
 }
 
 /**
@@ -109,8 +109,8 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
                 * used to generate the interrupt message."
                 */
                pos = pci_pcie_cap(dev);
-               pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg16);
-               entry = (reg16 >> 9) & PCIE_PORT_MSI_VECTOR_MASK;
+               pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
+               entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
                if (entry >= nr_entries)
                        goto Error;
 
@@ -177,37 +177,48 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
 }
 
 /**
- * assign_interrupt_mode - choose interrupt mode for PCI Express port services
- *                         (INTx, MSI-X, MSI) and set up vectors
+ * init_service_irqs - initialize irqs for PCI Express port services
  * @dev: PCI Express port to handle
- * @vectors: Array of interrupt vectors to populate
+ * @irqs: Array of irqs to populate
  * @mask: Bitmask of port capabilities returned by get_port_device_capability()
  *
  * Return value: Interrupt mode associated with the port
  */
-static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
+static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
 {
-       int irq, interrupt_mode = PCIE_PORT_NO_IRQ;
-       int i;
+       int i, irq = -1;
+
+       /* We have to use INTx if MSI cannot be used for PCIe PME. */
+       if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) {
+               if (dev->pin)
+                       irq = dev->irq;
+               goto no_msi;
+       }
 
        /* Try to use MSI-X if supported */
-       if (!pcie_port_enable_msix(dev, vectors, mask))
-               return PCIE_PORT_MSIX_MODE;
+       if (!pcie_port_enable_msix(dev, irqs, mask))
+               return 0;
 
        /* We're not going to use MSI-X, so try MSI and fall back to INTx */
-       if (!pci_enable_msi(dev))
-               interrupt_mode = PCIE_PORT_MSI_MODE;
-
-       if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin)
-               interrupt_mode = PCIE_PORT_INTx_MODE;
+       if (!pci_enable_msi(dev) || dev->pin)
+               irq = dev->irq;
 
-       irq = interrupt_mode != PCIE_PORT_NO_IRQ ? dev->irq : -1;
+ no_msi:
        for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
-               vectors[i] = irq;
+               irqs[i] = irq;
+       irqs[PCIE_PORT_SERVICE_VC_SHIFT] = -1;
 
-       vectors[PCIE_PORT_SERVICE_VC_SHIFT] = -1;
+       if (irq < 0)
+               return -ENODEV;
+       return 0;
+}
 
-       return interrupt_mode;
+static void cleanup_service_irqs(struct pci_dev *dev)
+{
+       if (dev->msix_enabled)
+               pci_disable_msix(dev);
+       else if (dev->msi_enabled)
+               pci_disable_msi(dev);
 }
 
 /**
@@ -227,12 +238,11 @@ static int get_port_device_capability(struct pci_dev *dev)
        u32 reg32;
 
        pos = pci_pcie_cap(dev);
-       pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg16);
+       pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
        /* Hot-Plug Capable */
-       if (reg16 & PORT_TO_SLOT_MASK) {
-               pci_read_config_dword(dev, 
-                       pos + PCIE_SLOT_CAPABILITIES_REG, &reg32);
-               if (reg32 & SLOT_HP_CAPABLE_MASK)
+       if (reg16 & PCI_EXP_FLAGS_SLOT) {
+               pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
+               if (reg32 & PCI_EXP_SLTCAP_HPC)
                        services |= PCIE_PORT_SERVICE_HP;
        }
        /* AER capable */
@@ -275,6 +285,7 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
                     pci_name(pdev),
                     get_descriptor_id(pdev->pcie_type, service));
        device->parent = &pdev->dev;
+       device_enable_async_suspend(device);
 
        retval = device_register(device);
        if (retval)
@@ -293,59 +304,49 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
  */
 int pcie_port_device_register(struct pci_dev *dev)
 {
-       struct pcie_port_data *port_data;
-       int status, capabilities, irq_mode, i, nr_serv;
-       int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
-
-       port_data = kzalloc(sizeof(*port_data), GFP_KERNEL);
-       if (!port_data)
-               return -ENOMEM;
-       pci_set_drvdata(dev, port_data);
-
-       port_data->port_type = dev->pcie_type;
+       int status, capabilities, i, nr_service;
+       int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
 
+       /* Get and check PCI Express port services */
        capabilities = get_port_device_capability(dev);
+       if (!capabilities)
+               return -ENODEV;
 
-       irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
-       if (irq_mode == PCIE_PORT_NO_IRQ) {
-               /*
-                * Don't use service devices that require interrupts if there is
-                * no way to generate them.
-                */
-               if (!(capabilities & PCIE_PORT_SERVICE_VC)) {
-                       status = -ENODEV;
-                       goto Error;
-               }
-               capabilities = PCIE_PORT_SERVICE_VC;
-       }
-       port_data->port_irq_mode = irq_mode;
-
+       /* Enable PCI Express port device */
        status = pci_enable_device(dev);
        if (status)
-               goto Error;
+               return status;
        pci_set_master(dev);
+       /*
+        * Initialize service irqs. Don't use service devices that
+        * require interrupts if there is no way to generate them.
+        */
+       status = init_service_irqs(dev, irqs, capabilities);
+       if (status) {
+               capabilities &= PCIE_PORT_SERVICE_VC;
+               if (!capabilities)
+                       goto error_disable;
+       }
 
        /* Allocate child services if any */
-       for (i = 0, nr_serv = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
+       status = -ENODEV;
+       nr_service = 0;
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
                int service = 1 << i;
-
                if (!(capabilities & service))
                        continue;
-
-               status = pcie_device_init(dev, service, vectors[i]);
-               if (!status)
-                       nr_serv++;
-       }
-       if (!nr_serv) {
-               pci_disable_device(dev);
-               status = -ENODEV;
-               goto Error;
+               if (!pcie_device_init(dev, service, irqs[i]))
+                       nr_service++;
        }
+       if (!nr_service)
+               goto error_cleanup_irqs;
 
        return 0;
 
- Error:
-       kfree(port_data);
+error_cleanup_irqs:
+       cleanup_service_irqs(dev);
+error_disable:
+       pci_disable_device(dev);
        return status;
 }
 
@@ -354,12 +355,11 @@ static int suspend_iter(struct device *dev, void *data)
 {
        struct pcie_port_service_driver *service_driver;
 
-       if ((dev->bus == &pcie_port_bus_type) &&
-           (dev->driver)) {
-               service_driver = to_service_driver(dev->driver);
-               if (service_driver->suspend)
-                       service_driver->suspend(to_pcie_device(dev));
-       }
+       if ((dev->bus == &pcie_port_bus_type) && dev->driver) {
+               service_driver = to_service_driver(dev->driver);
+               if (service_driver->suspend)
+                       service_driver->suspend(to_pcie_device(dev));
+       }
        return 0;
 }
 
@@ -413,21 +413,9 @@ static int remove_iter(struct device *dev, void *data)
  */
 void pcie_port_device_remove(struct pci_dev *dev)
 {
-       struct pcie_port_data *port_data = pci_get_drvdata(dev);
-
        device_for_each_child(&dev->dev, NULL, remove_iter);
+       cleanup_service_irqs(dev);
        pci_disable_device(dev);
-
-       switch (port_data->port_irq_mode) {
-       case PCIE_PORT_MSIX_MODE:
-               pci_disable_msix(dev);
-               break;
-       case PCIE_PORT_MSI_MODE:
-               pci_disable_msi(dev);
-               break;
-       }
-
-       kfree(port_data);
 }
 
 /**
@@ -514,6 +502,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new)
 
        return driver_register(&new->driver);
 }
+EXPORT_SYMBOL(pcie_port_service_register);
 
 /**
  * pcie_port_service_unregister - unregister PCI Express port service driver
@@ -523,6 +512,4 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *drv)
 {
        driver_unregister(&drv->driver);
 }
-
-EXPORT_SYMBOL(pcie_port_service_register);
 EXPORT_SYMBOL(pcie_port_service_unregister);