diff options
Diffstat (limited to 'drivers/pci/msi-altix.c')
-rw-r--r-- | drivers/pci/msi-altix.c | 81 |
1 files changed, 50 insertions, 31 deletions
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c index 7aedc2ac8c28..6ffd1f850d41 100644 --- a/drivers/pci/msi-altix.c +++ b/drivers/pci/msi-altix.c | |||
@@ -7,8 +7,10 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/irq.h> | ||
10 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
11 | #include <linux/cpumask.h> | 12 | #include <linux/cpumask.h> |
13 | #include <linux/msi.h> | ||
12 | 14 | ||
13 | #include <asm/sn/addrs.h> | 15 | #include <asm/sn/addrs.h> |
14 | #include <asm/sn/intr.h> | 16 | #include <asm/sn/intr.h> |
@@ -16,17 +18,16 @@ | |||
16 | #include <asm/sn/pcidev.h> | 18 | #include <asm/sn/pcidev.h> |
17 | #include <asm/sn/nodepda.h> | 19 | #include <asm/sn/nodepda.h> |
18 | 20 | ||
19 | #include "msi.h" | ||
20 | |||
21 | struct sn_msi_info { | 21 | struct sn_msi_info { |
22 | u64 pci_addr; | 22 | u64 pci_addr; |
23 | struct sn_irq_info *sn_irq_info; | 23 | struct sn_irq_info *sn_irq_info; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | static struct sn_msi_info *sn_msi_info; | 26 | static struct sn_msi_info sn_msi_info[NR_IRQS]; |
27 | |||
28 | static struct irq_chip sn_msi_chip; | ||
27 | 29 | ||
28 | static void | 30 | void sn_teardown_msi_irq(unsigned int irq) |
29 | sn_msi_teardown(unsigned int irq) | ||
30 | { | 31 | { |
31 | nasid_t nasid; | 32 | nasid_t nasid; |
32 | int widget; | 33 | int widget; |
@@ -61,9 +62,10 @@ sn_msi_teardown(unsigned int irq) | |||
61 | return; | 62 | return; |
62 | } | 63 | } |
63 | 64 | ||
64 | int | 65 | int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) |
65 | sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | ||
66 | { | 66 | { |
67 | struct msi_msg msg; | ||
68 | struct msi_desc *entry; | ||
67 | int widget; | 69 | int widget; |
68 | int status; | 70 | int status; |
69 | nasid_t nasid; | 71 | nasid_t nasid; |
@@ -72,6 +74,10 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | |||
72 | struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); | 74 | struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); |
73 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | 75 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); |
74 | 76 | ||
77 | entry = get_irq_data(irq); | ||
78 | if (!entry->msi_attrib.is_64) | ||
79 | return -EINVAL; | ||
80 | |||
75 | if (bussoft == NULL) | 81 | if (bussoft == NULL) |
76 | return -EINVAL; | 82 | return -EINVAL; |
77 | 83 | ||
@@ -121,25 +127,29 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | |||
121 | sn_msi_info[irq].sn_irq_info = sn_irq_info; | 127 | sn_msi_info[irq].sn_irq_info = sn_irq_info; |
122 | sn_msi_info[irq].pci_addr = bus_addr; | 128 | sn_msi_info[irq].pci_addr = bus_addr; |
123 | 129 | ||
124 | msg->address_hi = (u32)(bus_addr >> 32); | 130 | msg.address_hi = (u32)(bus_addr >> 32); |
125 | msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); | 131 | msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); |
126 | 132 | ||
127 | /* | 133 | /* |
128 | * In the SN platform, bit 16 is a "send vector" bit which | 134 | * In the SN platform, bit 16 is a "send vector" bit which |
129 | * must be present in order to move the vector through the system. | 135 | * must be present in order to move the vector through the system. |
130 | */ | 136 | */ |
131 | msg->data = 0x100 + irq; | 137 | msg.data = 0x100 + irq; |
132 | 138 | ||
133 | #ifdef CONFIG_SMP | 139 | #ifdef CONFIG_SMP |
134 | set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0); | 140 | set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0); |
135 | #endif | 141 | #endif |
136 | 142 | ||
143 | write_msi_msg(irq, &msg); | ||
144 | set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); | ||
145 | |||
137 | return 0; | 146 | return 0; |
138 | } | 147 | } |
139 | 148 | ||
140 | static void | 149 | #ifdef CONFIG_SMP |
141 | sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) | 150 | static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) |
142 | { | 151 | { |
152 | struct msi_msg msg; | ||
143 | int slice; | 153 | int slice; |
144 | nasid_t nasid; | 154 | nasid_t nasid; |
145 | u64 bus_addr; | 155 | u64 bus_addr; |
@@ -159,11 +169,12 @@ sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) | |||
159 | * Release XIO resources for the old MSI PCI address | 169 | * Release XIO resources for the old MSI PCI address |
160 | */ | 170 | */ |
161 | 171 | ||
172 | read_msi_msg(irq, &msg); | ||
162 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | 173 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; |
163 | pdev = sn_pdev->pdi_linux_pcidev; | 174 | pdev = sn_pdev->pdi_linux_pcidev; |
164 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | 175 | provider = SN_PCIDEV_BUSPROVIDER(pdev); |
165 | 176 | ||
166 | bus_addr = (u64)(msg->address_hi) << 32 | (u64)(msg->address_lo); | 177 | bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo); |
167 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); | 178 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); |
168 | sn_msi_info[irq].pci_addr = 0; | 179 | sn_msi_info[irq].pci_addr = 0; |
169 | 180 | ||
@@ -185,27 +196,35 @@ sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) | |||
185 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | 196 | SN_DMA_MSI|SN_DMA_ADDR_XIO); |
186 | 197 | ||
187 | sn_msi_info[irq].pci_addr = bus_addr; | 198 | sn_msi_info[irq].pci_addr = bus_addr; |
188 | msg->address_hi = (u32)(bus_addr >> 32); | 199 | msg.address_hi = (u32)(bus_addr >> 32); |
189 | msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); | 200 | msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); |
201 | |||
202 | write_msi_msg(irq, &msg); | ||
203 | set_native_irq_info(irq, cpu_mask); | ||
190 | } | 204 | } |
205 | #endif /* CONFIG_SMP */ | ||
191 | 206 | ||
192 | struct msi_ops sn_msi_ops = { | 207 | static void sn_ack_msi_irq(unsigned int irq) |
193 | .needs_64bit_address = 1, | 208 | { |
194 | .setup = sn_msi_setup, | 209 | move_native_irq(irq); |
195 | .teardown = sn_msi_teardown, | 210 | ia64_eoi(); |
196 | #ifdef CONFIG_SMP | 211 | } |
197 | .target = sn_msi_target, | ||
198 | #endif | ||
199 | }; | ||
200 | 212 | ||
201 | int | 213 | static int sn_msi_retrigger_irq(unsigned int irq) |
202 | sn_msi_init(void) | ||
203 | { | 214 | { |
204 | sn_msi_info = | 215 | unsigned int vector = irq; |
205 | kzalloc(sizeof(struct sn_msi_info) * NR_IRQS, GFP_KERNEL); | 216 | ia64_resend_irq(vector); |
206 | if (! sn_msi_info) | ||
207 | return -ENOMEM; | ||
208 | 217 | ||
209 | msi_register(&sn_msi_ops); | 218 | return 1; |
210 | return 0; | ||
211 | } | 219 | } |
220 | |||
221 | static struct irq_chip sn_msi_chip = { | ||
222 | .name = "PCI-MSI", | ||
223 | .mask = mask_msi_irq, | ||
224 | .unmask = unmask_msi_irq, | ||
225 | .ack = sn_ack_msi_irq, | ||
226 | #ifdef CONFIG_SMP | ||
227 | .set_affinity = sn_set_msi_irq_affinity, | ||
228 | #endif | ||
229 | .retrigger = sn_msi_retrigger_irq, | ||
230 | }; | ||