diff options
Diffstat (limited to 'arch/powerpc')
-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); |