diff options
| -rw-r--r-- | arch/powerpc/sysdev/fsl_msi.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 3482e3fd89c0..c84fbb1c1b42 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved. | 2 | * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. |
| 3 | * | 3 | * |
| 4 | * Author: Tony Li <tony.li@freescale.com> | 4 | * Author: Tony Li <tony.li@freescale.com> |
| 5 | * Jason Jin <Jason.jin@freescale.com> | 5 | * Jason Jin <Jason.jin@freescale.com> |
| @@ -29,7 +29,6 @@ struct fsl_msi_feature { | |||
| 29 | u32 msiir_offset; | 29 | u32 msiir_offset; |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | static struct fsl_msi *fsl_msi; | ||
| 33 | 32 | ||
| 34 | static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) | 33 | static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) |
| 35 | { | 34 | { |
| @@ -54,10 +53,12 @@ static struct irq_chip fsl_msi_chip = { | |||
| 54 | static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, | 53 | static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, |
| 55 | irq_hw_number_t hw) | 54 | irq_hw_number_t hw) |
| 56 | { | 55 | { |
| 56 | struct fsl_msi *msi_data = h->host_data; | ||
| 57 | struct irq_chip *chip = &fsl_msi_chip; | 57 | struct irq_chip *chip = &fsl_msi_chip; |
| 58 | 58 | ||
| 59 | irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING; | 59 | irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING; |
| 60 | 60 | ||
| 61 | set_irq_chip_data(virq, msi_data); | ||
| 61 | set_irq_chip_and_handler(virq, chip, handle_edge_irq); | 62 | set_irq_chip_and_handler(virq, chip, handle_edge_irq); |
| 62 | 63 | ||
| 63 | return 0; | 64 | return 0; |
| @@ -96,11 +97,12 @@ static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) | |||
| 96 | static void fsl_teardown_msi_irqs(struct pci_dev *pdev) | 97 | static void fsl_teardown_msi_irqs(struct pci_dev *pdev) |
| 97 | { | 98 | { |
| 98 | struct msi_desc *entry; | 99 | struct msi_desc *entry; |
| 99 | struct fsl_msi *msi_data = fsl_msi; | 100 | struct fsl_msi *msi_data; |
| 100 | 101 | ||
| 101 | list_for_each_entry(entry, &pdev->msi_list, list) { | 102 | list_for_each_entry(entry, &pdev->msi_list, list) { |
| 102 | if (entry->irq == NO_IRQ) | 103 | if (entry->irq == NO_IRQ) |
| 103 | continue; | 104 | continue; |
| 105 | msi_data = get_irq_chip_data(entry->irq); | ||
| 104 | set_irq_msi(entry->irq, NULL); | 106 | set_irq_msi(entry->irq, NULL); |
| 105 | msi_bitmap_free_hwirqs(&msi_data->bitmap, | 107 | msi_bitmap_free_hwirqs(&msi_data->bitmap, |
| 106 | virq_to_hw(entry->irq), 1); | 108 | virq_to_hw(entry->irq), 1); |
| @@ -111,9 +113,10 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) | |||
| 111 | } | 113 | } |
| 112 | 114 | ||
| 113 | static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, | 115 | static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, |
| 114 | struct msi_msg *msg) | 116 | struct msi_msg *msg, |
| 117 | struct fsl_msi *fsl_msi_data) | ||
| 115 | { | 118 | { |
| 116 | struct fsl_msi *msi_data = fsl_msi; | 119 | struct fsl_msi *msi_data = fsl_msi_data; |
| 117 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); | 120 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); |
| 118 | u32 base = 0; | 121 | u32 base = 0; |
| 119 | 122 | ||
| @@ -134,9 +137,11 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 134 | unsigned int virq; | 137 | unsigned int virq; |
| 135 | struct msi_desc *entry; | 138 | struct msi_desc *entry; |
| 136 | struct msi_msg msg; | 139 | struct msi_msg msg; |
| 137 | struct fsl_msi *msi_data = fsl_msi; | 140 | struct fsl_msi *msi_data; |
| 138 | 141 | ||
| 139 | list_for_each_entry(entry, &pdev->msi_list, list) { | 142 | list_for_each_entry(entry, &pdev->msi_list, list) { |
| 143 | msi_data = get_irq_chip_data(entry->irq); | ||
| 144 | |||
| 140 | hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); | 145 | hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); |
| 141 | if (hwirq < 0) { | 146 | if (hwirq < 0) { |
| 142 | rc = hwirq; | 147 | rc = hwirq; |
| @@ -156,7 +161,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 156 | } | 161 | } |
| 157 | set_irq_msi(virq, entry); | 162 | set_irq_msi(virq, entry); |
| 158 | 163 | ||
| 159 | fsl_compose_msi_msg(pdev, hwirq, &msg); | 164 | fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data); |
| 160 | write_msi_msg(virq, &msg); | 165 | write_msi_msg(virq, &msg); |
| 161 | } | 166 | } |
| 162 | return 0; | 167 | return 0; |
| @@ -168,7 +173,7 @@ out_free: | |||
| 168 | static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | 173 | static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) |
| 169 | { | 174 | { |
| 170 | unsigned int cascade_irq; | 175 | unsigned int cascade_irq; |
| 171 | struct fsl_msi *msi_data = fsl_msi; | 176 | struct fsl_msi *msi_data = get_irq_chip_data(irq); |
| 172 | int msir_index = -1; | 177 | int msir_index = -1; |
| 173 | u32 msir_value = 0; | 178 | u32 msir_value = 0; |
| 174 | u32 intr_index; | 179 | u32 intr_index; |
| @@ -193,7 +198,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | |||
| 193 | cascade_irq = NO_IRQ; | 198 | cascade_irq = NO_IRQ; |
| 194 | 199 | ||
| 195 | desc->status |= IRQ_INPROGRESS; | 200 | desc->status |= IRQ_INPROGRESS; |
| 196 | switch (fsl_msi->feature & FSL_PIC_IP_MASK) { | 201 | switch (msi_data->feature & FSL_PIC_IP_MASK) { |
| 197 | case FSL_PIC_IP_MPIC: | 202 | case FSL_PIC_IP_MPIC: |
| 198 | msir_value = fsl_msi_read(msi_data->msi_regs, | 203 | msir_value = fsl_msi_read(msi_data->msi_regs, |
| 199 | msir_index * 0x10); | 204 | msir_index * 0x10); |
| @@ -307,15 +312,20 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, | |||
| 307 | if (virt_msir != NO_IRQ) { | 312 | if (virt_msir != NO_IRQ) { |
| 308 | set_irq_data(virt_msir, (void *)i); | 313 | set_irq_data(virt_msir, (void *)i); |
| 309 | set_irq_chained_handler(virt_msir, fsl_msi_cascade); | 314 | set_irq_chained_handler(virt_msir, fsl_msi_cascade); |
| 315 | set_irq_chip_data(virt_msir, msi); | ||
| 310 | } | 316 | } |
| 311 | } | 317 | } |
| 312 | 318 | ||
| 313 | fsl_msi = msi; | 319 | /* The multiple setting ppc_md.setup_msi_irqs will not harm things */ |
| 314 | 320 | if (!ppc_md.setup_msi_irqs) { | |
| 315 | WARN_ON(ppc_md.setup_msi_irqs); | 321 | ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; |
| 316 | ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; | 322 | ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; |
| 317 | ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; | 323 | ppc_md.msi_check_device = fsl_msi_check_device; |
| 318 | ppc_md.msi_check_device = fsl_msi_check_device; | 324 | } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) { |
| 325 | dev_err(&dev->dev, "Different MSI driver already installed!\n"); | ||
| 326 | err = -ENODEV; | ||
| 327 | goto error_out; | ||
| 328 | } | ||
| 319 | return 0; | 329 | return 0; |
| 320 | error_out: | 330 | error_out: |
| 321 | kfree(msi); | 331 | kfree(msi); |
