Merge branch 'topic/core-cleanup' into for-linus
[safe/jmp/linux-2.6] / drivers / pci / pcie / aer / aerdrv.c
index 6f5fabb..7a711ee 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/pm.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/pcieport_if.h>
+#include <linux/slab.h>
 
 #include "aerdrv.h"
+#include "../../pci.h"
 
 /*
  * Version Information
@@ -37,50 +40,38 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static int __devinit aer_probe (struct pcie_device *dev,
-       const struct pcie_port_service_id *id );
+static int __devinit aer_probe(struct pcie_device *dev);
 static void aer_remove(struct pcie_device *dev);
-static int aer_suspend(struct pcie_device *dev, pm_message_t state)
-{return 0;}
-static int aer_resume(struct pcie_device *dev) {return 0;}
 static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
        enum pci_channel_state error);
 static void aer_error_resume(struct pci_dev *dev);
 static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
 
-/*
- * PCI Express bus's AER Root service driver data structure
- */
-static struct pcie_port_service_id aer_id[] = {
-       {
-       .vendor         = PCI_ANY_ID,
-       .device         = PCI_ANY_ID,
-       .port_type      = PCIE_RC_PORT,
-       .service_type   = PCIE_PORT_SERVICE_AER,
-       },
-       { /* end: all zeroes */ }
-};
-
 static struct pci_error_handlers aer_error_handlers = {
        .error_detected = aer_error_detected,
-       .resume = aer_error_resume,
+       .resume         = aer_error_resume,
 };
 
-static struct pcie_port_service_driver aerdrv = {
+static struct pcie_port_service_driver aerdriver = {
        .name           = "aer",
-       .id_table       = &aer_id[0],
+       .port_type      = PCI_EXP_TYPE_ROOT_PORT,
+       .service        = PCIE_PORT_SERVICE_AER,
 
        .probe          = aer_probe,
        .remove         = aer_remove,
 
-       .suspend        = aer_suspend,
-       .resume         = aer_resume,
-
        .err_handler    = &aer_error_handlers,
 
        .reset_link     = aer_root_reset,
 };
 
+static int pcie_aer_disable;
+
+void pci_no_aer(void)
+{
+       pcie_aer_disable = 1;   /* has priority over 'forceload' */
+}
+
 /**
  * aer_irq - Root Port's ISR
  * @irq: IRQ assigned to Root Port
@@ -88,7 +79,7 @@ static struct pcie_port_service_driver aerdrv = {
  *
  * Invoked when Root Port detects AER messages.
  **/
-static irqreturn_t aer_irq(int irq, void *context)
+irqreturn_t aer_irq(int irq, void *context)
 {
        unsigned int status, id;
        struct pcie_device *pdev = (struct pcie_device *)context;
@@ -97,7 +88,7 @@ static irqreturn_t aer_irq(int irq, void *context)
        unsigned long flags;
        int pos;
 
-       pos = pci_find_aer_capability(pdev->port);
+       pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR);
        /*
         * Must lock access to Root Error Status Reg, Root Error ID Reg,
         * and Root error producer/consumer index
@@ -137,6 +128,7 @@ static irqreturn_t aer_irq(int irq, void *context)
 
        return IRQ_HANDLED;
 }
+EXPORT_SYMBOL_GPL(aer_irq);
 
 /**
  * aer_alloc_rpc - allocate Root Port data structure
@@ -144,20 +136,19 @@ static irqreturn_t aer_irq(int irq, void *context)
  *
  * Invoked when Root Port's AER service is loaded.
  **/
-static struct aer_rpcaer_alloc_rpc(struct pcie_device *dev)
+static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
 {
        struct aer_rpc *rpc;
 
-       if (!(rpc = kmalloc(sizeof(struct aer_rpc),
-               GFP_KERNEL)))
+       rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
+       if (!rpc)
                return NULL;
 
-       memset(rpc, 0, sizeof(struct aer_rpc));
        /*
         * Initialize Root lock access, e_lock, to Root Error Status Reg,
         * Root Error ID Reg, and Root error producer/consumer index.
         */
-       rpc->e_lock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&rpc->e_lock);
 
        rpc->rpd = dev;
        INIT_WORK(&rpc->dpc_handler, aer_isr);
@@ -165,7 +156,7 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
        mutex_init(&rpc->rpc_mutex);
        init_waitqueue_head(&rpc->wait_release);
 
-       /* Use PCIE bus function to store rpc into PCIE device */
+       /* Use PCIe bus function to store rpc into PCIe device */
        set_service_data(dev, rpc);
 
        return rpc;
@@ -200,30 +191,29 @@ static void aer_remove(struct pcie_device *dev)
  *
  * Invoked when PCI Express bus loads AER service driver.
  **/
-static int __devinit aer_probe (struct pcie_device *dev,
-                               const struct pcie_port_service_id *id )
+static int __devinit aer_probe(struct pcie_device *dev)
 {
        int status;
        struct aer_rpc *rpc;
        struct device *device = &dev->device;
 
        /* Init */
-       if ((status = aer_init(dev)))
+       status = aer_init(dev);
+       if (status)
                return status;
 
        /* Alloc rpc data structure */
-       if (!(rpc = aer_alloc_rpc(dev))) {
-               printk(KERN_DEBUG "%s: Alloc rpc fails on PCIE device[%s]\n",
-                       __FUNCTION__, device->bus_id);
+       rpc = aer_alloc_rpc(dev);
+       if (!rpc) {
+               dev_printk(KERN_DEBUG, device, "alloc rpc failed\n");
                aer_remove(dev);
                return -ENOMEM;
        }
 
        /* Request IRQ ISR */
-       if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv",
-                               dev))) {
-               printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n",
-                       __FUNCTION__, device->bus_id);
+       status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
+       if (status) {
+               dev_printk(KERN_DEBUG, device, "request IRQ failed\n");
                aer_remove(dev);
                return status;
        }
@@ -247,18 +237,24 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
        u32 status;
        int pos;
 
-       pos = pci_find_aer_capability(dev);
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 
        /* Disable Root's interrupt in response to error messages */
        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
 
        /* Assert Secondary Bus Reset */
        pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
-       p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET;
+       p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
 
+       /*
+        * we should send hot reset message for 2ms to allow it time to
+        * propogate to all downstream ports
+        */
+       msleep(2);
+
        /* De-assert Secondary Bus Reset */
-       p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET;
+       p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
 
        /*
@@ -267,7 +263,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
         * to issue Configuration Requests to those devices.
         */
        msleep(200);
-       printk(KERN_DEBUG "Complete link reset at Root[%s]\n", dev->dev.bus_id);
+       dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
 
        /* Enable Root Port's interrupt in response to error messages */
        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
@@ -306,12 +302,12 @@ static void aer_error_resume(struct pci_dev *dev)
        u16 reg16;
 
        /* Clean up Root device status */
-       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+       pos = pci_pcie_cap(dev);
        pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
        pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
 
        /* Clean AER Root Error Status */
-       pos = pci_find_aer_capability(dev);
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
        if (dev->error_state == pci_channel_io_normal)
@@ -328,7 +324,11 @@ static void aer_error_resume(struct pci_dev *dev)
  **/
 static int __init aer_service_init(void)
 {
-       return pcie_port_service_register(&aerdrv);
+       if (pcie_aer_disable)
+               return -ENXIO;
+       if (!pci_msi_enabled())
+               return -ENXIO;
+       return pcie_port_service_register(&aerdriver);
 }
 
 /**
@@ -338,7 +338,7 @@ static int __init aer_service_init(void)
  **/
 static void __exit aer_service_exit(void)
 {
-       pcie_port_service_unregister(&aerdrv);
+       pcie_port_service_unregister(&aerdriver);
 }
 
 module_init(aer_service_init);