Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux
[cascardo/linux.git] / arch / powerpc / sysdev / fsl_msi.c
index b32e79d..de40b48 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
 #include <sysdev/fsl_soc.h>
 #include <asm/prom.h>
 #include <asm/hw_irq.h>
@@ -50,6 +52,7 @@ struct fsl_msi_feature {
 struct fsl_msi_cascade_data {
        struct fsl_msi *msi_data;
        int index;
+       int virq;
 };
 
 static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
@@ -65,11 +68,24 @@ static void fsl_msi_end_irq(struct irq_data *d)
 {
 }
 
+static void fsl_msi_print_chip(struct irq_data *irqd, struct seq_file *p)
+{
+       struct fsl_msi *msi_data = irqd->domain->host_data;
+       irq_hw_number_t hwirq = irqd_to_hwirq(irqd);
+       int cascade_virq, srs;
+
+       srs = (hwirq >> msi_data->srs_shift) & MSI_SRS_MASK;
+       cascade_virq = msi_data->cascade_array[srs]->virq;
+
+       seq_printf(p, " fsl-msi-%d", cascade_virq);
+}
+
+
 static struct irq_chip fsl_msi_chip = {
        .irq_mask       = mask_msi_irq,
        .irq_unmask     = unmask_msi_irq,
        .irq_ack        = fsl_msi_end_irq,
-       .name           = "FSL-MSI",
+       .irq_print_chip = fsl_msi_print_chip,
 };
 
 static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq,
@@ -175,7 +191,8 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        np = of_parse_phandle(hose->dn, "fsl,msi", 0);
        if (np) {
                if (of_device_is_compatible(np, "fsl,mpic-msi") ||
-                   of_device_is_compatible(np, "fsl,vmpic-msi"))
+                   of_device_is_compatible(np, "fsl,vmpic-msi") ||
+                   of_device_is_compatible(np, "fsl,vmpic-msi-v4.3"))
                        phandle = np->phandle;
                else {
                        dev_err(&pdev->dev,
@@ -234,40 +251,24 @@ out_free:
        return rc;
 }
 
-static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
+static irqreturn_t fsl_msi_cascade(int irq, void *data)
 {
-       struct irq_chip *chip = irq_desc_get_chip(desc);
-       struct irq_data *idata = irq_desc_get_irq_data(desc);
        unsigned int cascade_irq;
        struct fsl_msi *msi_data;
        int msir_index = -1;
        u32 msir_value = 0;
        u32 intr_index;
        u32 have_shift = 0;
-       struct fsl_msi_cascade_data *cascade_data;
+       struct fsl_msi_cascade_data *cascade_data = data;
+       irqreturn_t ret = IRQ_NONE;
 
-       cascade_data = irq_get_handler_data(irq);
        msi_data = cascade_data->msi_data;
 
-       raw_spin_lock(&desc->lock);
-       if ((msi_data->feature &  FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
-               if (chip->irq_mask_ack)
-                       chip->irq_mask_ack(idata);
-               else {
-                       chip->irq_mask(idata);
-                       chip->irq_ack(idata);
-               }
-       }
-
-       if (unlikely(irqd_irq_inprogress(idata)))
-               goto unlock;
-
        msir_index = cascade_data->index;
 
        if (msir_index >= NR_MSI_REG_MAX)
                cascade_irq = NO_IRQ;
 
-       irqd_set_chained_irq_inprogress(idata);
        switch (msi_data->feature & FSL_PIC_IP_MASK) {
        case FSL_PIC_IP_MPIC:
                msir_value = fsl_msi_read(msi_data->msi_regs,
@@ -296,40 +297,32 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
                cascade_irq = irq_linear_revmap(msi_data->irqhost,
                                msi_hwirq(msi_data, msir_index,
                                          intr_index + have_shift));
-               if (cascade_irq != NO_IRQ)
+               if (cascade_irq != NO_IRQ) {
                        generic_handle_irq(cascade_irq);
+                       ret = IRQ_HANDLED;
+               }
                have_shift += intr_index + 1;
                msir_value = msir_value >> (intr_index + 1);
        }
-       irqd_clr_chained_irq_inprogress(idata);
 
-       switch (msi_data->feature & FSL_PIC_IP_MASK) {
-       case FSL_PIC_IP_MPIC:
-       case FSL_PIC_IP_VMPIC:
-               chip->irq_eoi(idata);
-               break;
-       case FSL_PIC_IP_IPIC:
-               if (!irqd_irq_disabled(idata) && chip->irq_unmask)
-                       chip->irq_unmask(idata);
-               break;
-       }
-unlock:
-       raw_spin_unlock(&desc->lock);
+       return ret;
 }
 
 static int fsl_of_msi_remove(struct platform_device *ofdev)
 {
        struct fsl_msi *msi = platform_get_drvdata(ofdev);
        int virq, i;
-       struct fsl_msi_cascade_data *cascade_data;
 
        if (msi->list.prev != NULL)
                list_del(&msi->list);
        for (i = 0; i < NR_MSI_REG_MAX; i++) {
-               virq = msi->msi_virqs[i];
-               if (virq != NO_IRQ) {
-                       cascade_data = irq_get_handler_data(virq);
-                       kfree(cascade_data);
+               if (msi->cascade_array[i]) {
+                       virq = msi->cascade_array[i]->virq;
+
+                       BUG_ON(virq == NO_IRQ);
+
+                       free_irq(virq, msi->cascade_array[i]);
+                       kfree(msi->cascade_array[i]);
                        irq_dispose_mapping(virq);
                }
        }
@@ -348,7 +341,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
                               int offset, int irq_index)
 {
        struct fsl_msi_cascade_data *cascade_data = NULL;
-       int virt_msir, i;
+       int virt_msir, i, ret;
 
        virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index);
        if (virt_msir == NO_IRQ) {
@@ -363,11 +356,18 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
                return -ENOMEM;
        }
        irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class);
-       msi->msi_virqs[irq_index] = virt_msir;
        cascade_data->index = offset;
        cascade_data->msi_data = msi;
-       irq_set_handler_data(virt_msir, cascade_data);
-       irq_set_chained_handler(virt_msir, fsl_msi_cascade);
+       cascade_data->virq = virt_msir;
+       msi->cascade_array[irq_index] = cascade_data;
+
+       ret = request_irq(virt_msir, fsl_msi_cascade, 0,
+                         "fsl-msi-cascade", cascade_data);
+       if (ret) {
+               dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n",
+                       virt_msir, ret);
+               return ret;
+       }
 
        /* Release the hwirqs corresponding to this MSI register */
        for (i = 0; i < IRQS_PER_MSI_REG; i++)
@@ -461,7 +461,8 @@ static int fsl_of_msi_probe(struct platform_device *dev)
 
        p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
 
-       if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3")) {
+       if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3") ||
+           of_device_is_compatible(dev->dev.of_node, "fsl,vmpic-msi-v4.3")) {
                msi->srs_shift = MSIIR1_SRS_SHIFT;
                msi->ibs_shift = MSIIR1_IBS_SHIFT;
                if (p)
@@ -566,6 +567,10 @@ static const struct of_device_id fsl_of_msi_ids[] = {
                .compatible = "fsl,vmpic-msi",
                .data = &vmpic_msi_feature,
        },
+       {
+               .compatible = "fsl,vmpic-msi-v4.3",
+               .data = &vmpic_msi_feature,
+       },
 #endif
        {}
 };