2 * Copyright 2011 Michael Ellerman, IBM Corp.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
10 #include <linux/kernel.h>
11 #include <linux/pci.h>
12 #include <linux/msi.h>
13 #include <linux/irq.h>
14 #include <linux/interrupt.h>
20 /* Magic addresses for 32 & 64-bit MSIs with hardcoded MVE 0 */
21 #define MSI_ADDR_32 0xFFFF0000ul
22 #define MSI_ADDR_64 0x1000000000000000ul
24 int wsp_setup_msi_irqs(struct pci_dev
*dev
, int nvec
, int type
)
26 struct pci_controller
*phb
;
27 struct msi_desc
*entry
;
32 phb
= pci_bus_to_host(dev
->bus
);
36 entry
= list_first_entry(&dev
->msi_list
, struct msi_desc
, list
);
37 if (entry
->msi_attrib
.is_64
) {
39 msg
.address_hi
= MSI_ADDR_64
>> 32;
41 msg
.address_lo
= MSI_ADDR_32
;
45 list_for_each_entry(entry
, &dev
->msi_list
, list
) {
46 hwirq
= wsp_ics_alloc_irq(phb
->dn
, 1);
48 dev_warn(&dev
->dev
, "wsp_msi: hwirq alloc failed!\n");
52 virq
= irq_create_mapping(NULL
, hwirq
);
54 dev_warn(&dev
->dev
, "wsp_msi: virq alloc failed!\n");
58 dev_dbg(&dev
->dev
, "wsp_msi: allocated irq %#x/%#x\n",
61 wsp_ics_set_msi_chip(virq
);
62 irq_set_msi_desc(virq
, entry
);
63 msg
.data
= hwirq
& XIVE_ADDR_MASK
;
64 write_msi_msg(virq
, &msg
);
70 void wsp_teardown_msi_irqs(struct pci_dev
*dev
)
72 struct pci_controller
*phb
;
73 struct msi_desc
*entry
;
76 phb
= pci_bus_to_host(dev
->bus
);
78 dev_dbg(&dev
->dev
, "wsp_msi: tearing down msi irqs\n");
80 list_for_each_entry(entry
, &dev
->msi_list
, list
) {
81 if (entry
->irq
== NO_IRQ
)
84 irq_set_msi_desc(entry
->irq
, NULL
);
85 wsp_ics_set_std_chip(entry
->irq
);
87 hwirq
= virq_to_hw(entry
->irq
);
88 /* In this order to avoid racing with irq_create_mapping() */
89 irq_dispose_mapping(entry
->irq
);
90 wsp_ics_free_irq(phb
->dn
, hwirq
);
94 void wsp_setup_phb_msi(struct pci_controller
*phb
)
96 /* Create a single MVE at offset 0 that matches everything */
97 out_be64(phb
->cfg_data
+ PCIE_REG_IODA_ADDR
, PCIE_REG_IODA_AD_TBL_MVT
);
98 out_be64(phb
->cfg_data
+ PCIE_REG_IODA_DATA0
, 1ull << 63);
100 ppc_md
.setup_msi_irqs
= wsp_setup_msi_irqs
;
101 ppc_md
.teardown_msi_irqs
= wsp_teardown_msi_irqs
;