diff options
Diffstat (limited to 'arch/mips/pci/pci-xlr.c')
-rw-r--r-- | arch/mips/pci/pci-xlr.c | 128 |
1 files changed, 127 insertions, 1 deletions
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 38fece16c43..3d701a962ef 100644 --- a/arch/mips/pci/pci-xlr.c +++ b/arch/mips/pci/pci-xlr.c | |||
@@ -36,12 +36,18 @@ | |||
36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
37 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/msi.h> | ||
39 | #include <linux/mm.h> | 40 | #include <linux/mm.h> |
41 | #include <linux/irq.h> | ||
42 | #include <linux/irqdesc.h> | ||
40 | #include <linux/console.h> | 43 | #include <linux/console.h> |
41 | 44 | ||
42 | #include <asm/io.h> | 45 | #include <asm/io.h> |
43 | 46 | ||
44 | #include <asm/netlogic/interrupt.h> | 47 | #include <asm/netlogic/interrupt.h> |
48 | #include <asm/netlogic/haldefs.h> | ||
49 | |||
50 | #include <asm/netlogic/xlr/msidef.h> | ||
45 | #include <asm/netlogic/xlr/iomap.h> | 51 | #include <asm/netlogic/xlr/iomap.h> |
46 | #include <asm/netlogic/xlr/pic.h> | 52 | #include <asm/netlogic/xlr/pic.h> |
47 | #include <asm/netlogic/xlr/xlr.h> | 53 | #include <asm/netlogic/xlr/xlr.h> |
@@ -150,7 +156,7 @@ struct pci_controller nlm_pci_controller = { | |||
150 | .io_offset = 0x00000000UL, | 156 | .io_offset = 0x00000000UL, |
151 | }; | 157 | }; |
152 | 158 | ||
153 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | 159 | static int get_irq_vector(const struct pci_dev *dev) |
154 | { | 160 | { |
155 | if (!nlm_chip_is_xls()) | 161 | if (!nlm_chip_is_xls()) |
156 | return PIC_PCIX_IRQ; /* for XLR just one IRQ*/ | 162 | return PIC_PCIX_IRQ; /* for XLR just one IRQ*/ |
@@ -182,6 +188,101 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | |||
182 | return 0; | 188 | return 0; |
183 | } | 189 | } |
184 | 190 | ||
191 | #ifdef CONFIG_PCI_MSI | ||
192 | void destroy_irq(unsigned int irq) | ||
193 | { | ||
194 | /* nothing to do yet */ | ||
195 | } | ||
196 | |||
197 | void arch_teardown_msi_irq(unsigned int irq) | ||
198 | { | ||
199 | destroy_irq(irq); | ||
200 | } | ||
201 | |||
202 | int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) | ||
203 | { | ||
204 | struct msi_msg msg; | ||
205 | int irq, ret; | ||
206 | |||
207 | irq = get_irq_vector(dev); | ||
208 | if (irq <= 0) | ||
209 | return 1; | ||
210 | |||
211 | msg.address_hi = MSI_ADDR_BASE_HI; | ||
212 | msg.address_lo = MSI_ADDR_BASE_LO | | ||
213 | MSI_ADDR_DEST_MODE_PHYSICAL | | ||
214 | MSI_ADDR_REDIRECTION_CPU; | ||
215 | |||
216 | msg.data = MSI_DATA_TRIGGER_EDGE | | ||
217 | MSI_DATA_LEVEL_ASSERT | | ||
218 | MSI_DATA_DELIVERY_FIXED; | ||
219 | |||
220 | ret = irq_set_msi_desc(irq, desc); | ||
221 | if (ret < 0) { | ||
222 | destroy_irq(irq); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | write_msi_msg(irq, &msg); | ||
227 | return 0; | ||
228 | } | ||
229 | #endif | ||
230 | |||
231 | /* Extra ACK needed for XLR on chip PCI controller */ | ||
232 | static void xlr_pci_ack(struct irq_data *d) | ||
233 | { | ||
234 | uint64_t pcibase = nlm_mmio_base(NETLOGIC_IO_PCIX_OFFSET); | ||
235 | |||
236 | nlm_read_reg(pcibase, (0x140 >> 2)); | ||
237 | } | ||
238 | |||
239 | /* Extra ACK needed for XLS on chip PCIe controller */ | ||
240 | static void xls_pcie_ack(struct irq_data *d) | ||
241 | { | ||
242 | uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); | ||
243 | |||
244 | switch (d->irq) { | ||
245 | case PIC_PCIE_LINK0_IRQ: | ||
246 | nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); | ||
247 | break; | ||
248 | case PIC_PCIE_LINK1_IRQ: | ||
249 | nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); | ||
250 | break; | ||
251 | case PIC_PCIE_LINK2_IRQ: | ||
252 | nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); | ||
253 | break; | ||
254 | case PIC_PCIE_LINK3_IRQ: | ||
255 | nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | /* For XLS B silicon, the 3,4 PCI interrupts are different */ | ||
261 | static void xls_pcie_ack_b(struct irq_data *d) | ||
262 | { | ||
263 | uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); | ||
264 | |||
265 | switch (d->irq) { | ||
266 | case PIC_PCIE_LINK0_IRQ: | ||
267 | nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); | ||
268 | break; | ||
269 | case PIC_PCIE_LINK1_IRQ: | ||
270 | nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); | ||
271 | break; | ||
272 | case PIC_PCIE_XLSB0_LINK2_IRQ: | ||
273 | nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); | ||
274 | break; | ||
275 | case PIC_PCIE_XLSB0_LINK3_IRQ: | ||
276 | nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
282 | { | ||
283 | return get_irq_vector(dev); | ||
284 | } | ||
285 | |||
185 | /* Do platform specific device initialization at pci_enable_device() time */ | 286 | /* Do platform specific device initialization at pci_enable_device() time */ |
186 | int pcibios_plat_dev_init(struct pci_dev *dev) | 287 | int pcibios_plat_dev_init(struct pci_dev *dev) |
187 | { | 288 | { |
@@ -204,6 +305,31 @@ static int __init pcibios_init(void) | |||
204 | pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n"); | 305 | pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n"); |
205 | register_pci_controller(&nlm_pci_controller); | 306 | register_pci_controller(&nlm_pci_controller); |
206 | 307 | ||
308 | /* | ||
309 | * For PCI interrupts, we need to ack the PCI controller too, overload | ||
310 | * irq handler data to do this | ||
311 | */ | ||
312 | if (nlm_chip_is_xls()) { | ||
313 | if (nlm_chip_is_xls_b()) { | ||
314 | irq_set_handler_data(PIC_PCIE_LINK0_IRQ, | ||
315 | xls_pcie_ack_b); | ||
316 | irq_set_handler_data(PIC_PCIE_LINK1_IRQ, | ||
317 | xls_pcie_ack_b); | ||
318 | irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, | ||
319 | xls_pcie_ack_b); | ||
320 | irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, | ||
321 | xls_pcie_ack_b); | ||
322 | } else { | ||
323 | irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); | ||
324 | irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); | ||
325 | irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); | ||
326 | irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); | ||
327 | } | ||
328 | } else { | ||
329 | /* XLR PCI controller ACK */ | ||
330 | irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); | ||
331 | } | ||
332 | |||
207 | return 0; | 333 | return 0; |
208 | } | 334 | } |
209 | 335 | ||