diff options
-rw-r--r-- | arch/i386/kernel/io_apic.c | 81 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 89 | ||||
-rw-r--r-- | drivers/pci/msi-altix.c | 81 | ||||
-rw-r--r-- | drivers/pci/msi-apic.c | 86 | ||||
-rw-r--r-- | drivers/pci/msi.c | 150 | ||||
-rw-r--r-- | drivers/pci/msi.h | 27 | ||||
-rw-r--r-- | include/asm-i386/msi.h | 20 | ||||
-rw-r--r-- | include/asm-ia64/machvec.h | 21 | ||||
-rw-r--r-- | include/asm-ia64/machvec_sn2.h | 9 | ||||
-rw-r--r-- | include/asm-ia64/msi.h | 29 | ||||
-rw-r--r-- | include/asm-x86_64/msi.h | 21 | ||||
-rw-r--r-- | include/linux/msi.h | 49 | ||||
-rw-r--r-- | include/linux/pci.h | 67 |
13 files changed, 335 insertions, 395 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 100406b453b8..5a1252753dbb 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/sysdev.h> | 33 | #include <linux/sysdev.h> |
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/msi.h> | ||
35 | 36 | ||
36 | #include <asm/io.h> | 37 | #include <asm/io.h> |
37 | #include <asm/smp.h> | 38 | #include <asm/smp.h> |
@@ -2455,11 +2456,8 @@ void destroy_irq(unsigned int irq) | |||
2455 | * MSI mesage composition | 2456 | * MSI mesage composition |
2456 | */ | 2457 | */ |
2457 | #ifdef CONFIG_PCI_MSI | 2458 | #ifdef CONFIG_PCI_MSI |
2458 | static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | 2459 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) |
2459 | { | 2460 | { |
2460 | /* For now always this code always uses physical delivery | ||
2461 | * mode. | ||
2462 | */ | ||
2463 | int vector; | 2461 | int vector; |
2464 | unsigned dest; | 2462 | unsigned dest; |
2465 | 2463 | ||
@@ -2489,34 +2487,71 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg | |||
2489 | return vector; | 2487 | return vector; |
2490 | } | 2488 | } |
2491 | 2489 | ||
2492 | static void msi_msg_teardown(unsigned int irq) | 2490 | #ifdef CONFIG_SMP |
2493 | { | 2491 | static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) |
2494 | return; | ||
2495 | } | ||
2496 | |||
2497 | static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg) | ||
2498 | { | 2492 | { |
2493 | struct msi_msg msg; | ||
2494 | unsigned int dest; | ||
2495 | cpumask_t tmp; | ||
2499 | int vector; | 2496 | int vector; |
2500 | unsigned dest; | 2497 | |
2498 | cpus_and(tmp, mask, cpu_online_map); | ||
2499 | if (cpus_empty(tmp)) | ||
2500 | tmp = TARGET_CPUS; | ||
2501 | 2501 | ||
2502 | vector = assign_irq_vector(irq); | 2502 | vector = assign_irq_vector(irq); |
2503 | if (vector > 0) { | 2503 | if (vector < 0) |
2504 | dest = cpu_mask_to_apicid(mask); | 2504 | return; |
2505 | 2505 | ||
2506 | msg->data &= ~MSI_DATA_VECTOR_MASK; | 2506 | dest = cpu_mask_to_apicid(mask); |
2507 | msg->data |= MSI_DATA_VECTOR(vector); | 2507 | |
2508 | msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK; | 2508 | read_msi_msg(irq, &msg); |
2509 | msg->address_lo |= MSI_ADDR_DEST_ID(dest); | 2509 | |
2510 | } | 2510 | msg.data &= ~MSI_DATA_VECTOR_MASK; |
2511 | msg.data |= MSI_DATA_VECTOR(vector); | ||
2512 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
2513 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
2514 | |||
2515 | write_msi_msg(irq, &msg); | ||
2516 | set_native_irq_info(irq, mask); | ||
2511 | } | 2517 | } |
2518 | #endif /* CONFIG_SMP */ | ||
2512 | 2519 | ||
2513 | struct msi_ops arch_msi_ops = { | 2520 | /* |
2514 | .needs_64bit_address = 0, | 2521 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, |
2515 | .setup = msi_msg_setup, | 2522 | * which implement the MSI or MSI-X Capability Structure. |
2516 | .teardown = msi_msg_teardown, | 2523 | */ |
2517 | .target = msi_msg_set_affinity, | 2524 | static struct irq_chip msi_chip = { |
2525 | .name = "PCI-MSI", | ||
2526 | .unmask = unmask_msi_irq, | ||
2527 | .mask = mask_msi_irq, | ||
2528 | .ack = ack_ioapic_irq, | ||
2529 | #ifdef CONFIG_SMP | ||
2530 | .set_affinity = set_msi_irq_affinity, | ||
2531 | #endif | ||
2532 | .retrigger = ioapic_retrigger_irq, | ||
2518 | }; | 2533 | }; |
2519 | 2534 | ||
2535 | int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) | ||
2536 | { | ||
2537 | struct msi_msg msg; | ||
2538 | int ret; | ||
2539 | ret = msi_compose_msg(dev, irq, &msg); | ||
2540 | if (ret < 0) | ||
2541 | return ret; | ||
2542 | |||
2543 | write_msi_msg(irq, &msg); | ||
2544 | |||
2545 | set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); | ||
2546 | |||
2547 | return 0; | ||
2548 | } | ||
2549 | |||
2550 | void arch_teardown_msi_irq(unsigned int irq) | ||
2551 | { | ||
2552 | return; | ||
2553 | } | ||
2554 | |||
2520 | #endif /* CONFIG_PCI_MSI */ | 2555 | #endif /* CONFIG_PCI_MSI */ |
2521 | 2556 | ||
2522 | /* | 2557 | /* |
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 31c270fee337..e55028fba942 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/mc146818rtc.h> | 30 | #include <linux/mc146818rtc.h> |
31 | #include <linux/acpi.h> | 31 | #include <linux/acpi.h> |
32 | #include <linux/sysdev.h> | 32 | #include <linux/sysdev.h> |
33 | #include <linux/msi.h> | ||
33 | #ifdef CONFIG_ACPI | 34 | #ifdef CONFIG_ACPI |
34 | #include <acpi/acpi_bus.h> | 35 | #include <acpi/acpi_bus.h> |
35 | #endif | 36 | #endif |
@@ -1701,11 +1702,8 @@ void destroy_irq(unsigned int irq) | |||
1701 | * MSI mesage composition | 1702 | * MSI mesage composition |
1702 | */ | 1703 | */ |
1703 | #ifdef CONFIG_PCI_MSI | 1704 | #ifdef CONFIG_PCI_MSI |
1704 | static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | 1705 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) |
1705 | { | 1706 | { |
1706 | /* For now always this code always uses physical delivery | ||
1707 | * mode. | ||
1708 | */ | ||
1709 | int vector; | 1707 | int vector; |
1710 | unsigned dest; | 1708 | unsigned dest; |
1711 | 1709 | ||
@@ -1739,39 +1737,76 @@ static int msi_msg_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg | |||
1739 | return vector; | 1737 | return vector; |
1740 | } | 1738 | } |
1741 | 1739 | ||
1742 | static void msi_msg_teardown(unsigned int irq) | 1740 | #ifdef CONFIG_SMP |
1743 | { | 1741 | static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) |
1744 | return; | ||
1745 | } | ||
1746 | |||
1747 | static void msi_msg_set_affinity(unsigned int irq, cpumask_t mask, struct msi_msg *msg) | ||
1748 | { | 1742 | { |
1743 | struct msi_msg msg; | ||
1744 | unsigned int dest; | ||
1745 | cpumask_t tmp; | ||
1749 | int vector; | 1746 | int vector; |
1750 | unsigned dest; | 1747 | |
1748 | cpus_and(tmp, mask, cpu_online_map); | ||
1749 | if (cpus_empty(tmp)) | ||
1750 | tmp = TARGET_CPUS; | ||
1751 | |||
1752 | cpus_and(mask, tmp, CPU_MASK_ALL); | ||
1751 | 1753 | ||
1752 | vector = assign_irq_vector(irq, mask); | 1754 | vector = assign_irq_vector(irq, mask); |
1753 | if (vector > 0) { | 1755 | if (vector < 0) |
1754 | cpumask_t tmp; | 1756 | return; |
1755 | 1757 | ||
1756 | cpus_clear(tmp); | 1758 | cpus_clear(tmp); |
1757 | cpu_set(vector >> 8, tmp); | 1759 | cpu_set(vector >> 8, tmp); |
1758 | dest = cpu_mask_to_apicid(tmp); | 1760 | dest = cpu_mask_to_apicid(tmp); |
1759 | 1761 | ||
1760 | msg->data &= ~MSI_DATA_VECTOR_MASK; | 1762 | read_msi_msg(irq, &msg); |
1761 | msg->data |= MSI_DATA_VECTOR(vector); | 1763 | |
1762 | msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK; | 1764 | msg.data &= ~MSI_DATA_VECTOR_MASK; |
1763 | msg->address_lo |= MSI_ADDR_DEST_ID(dest); | 1765 | msg.data |= MSI_DATA_VECTOR(vector); |
1764 | } | 1766 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; |
1767 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
1768 | |||
1769 | write_msi_msg(irq, &msg); | ||
1770 | set_native_irq_info(irq, mask); | ||
1765 | } | 1771 | } |
1772 | #endif /* CONFIG_SMP */ | ||
1766 | 1773 | ||
1767 | struct msi_ops arch_msi_ops = { | 1774 | /* |
1768 | .needs_64bit_address = 0, | 1775 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, |
1769 | .setup = msi_msg_setup, | 1776 | * which implement the MSI or MSI-X Capability Structure. |
1770 | .teardown = msi_msg_teardown, | 1777 | */ |
1771 | .target = msi_msg_set_affinity, | 1778 | static struct irq_chip msi_chip = { |
1779 | .name = "PCI-MSI", | ||
1780 | .unmask = unmask_msi_irq, | ||
1781 | .mask = mask_msi_irq, | ||
1782 | .ack = ack_apic_edge, | ||
1783 | #ifdef CONFIG_SMP | ||
1784 | .set_affinity = set_msi_irq_affinity, | ||
1785 | #endif | ||
1786 | .retrigger = ioapic_retrigger_irq, | ||
1772 | }; | 1787 | }; |
1773 | 1788 | ||
1774 | #endif | 1789 | int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) |
1790 | { | ||
1791 | struct msi_msg msg; | ||
1792 | int ret; | ||
1793 | ret = msi_compose_msg(dev, irq, &msg); | ||
1794 | if (ret < 0) | ||
1795 | return ret; | ||
1796 | |||
1797 | write_msi_msg(irq, &msg); | ||
1798 | |||
1799 | set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); | ||
1800 | |||
1801 | return 0; | ||
1802 | } | ||
1803 | |||
1804 | void arch_teardown_msi_irq(unsigned int irq) | ||
1805 | { | ||
1806 | return; | ||
1807 | } | ||
1808 | |||
1809 | #endif /* CONFIG_PCI_MSI */ | ||
1775 | 1810 | ||
1776 | /* | 1811 | /* |
1777 | * Hypertransport interrupt support | 1812 | * Hypertransport interrupt support |
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 | }; | ||
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c index afc0ed13aa89..822e59a1b822 100644 --- a/drivers/pci/msi-apic.c +++ b/drivers/pci/msi-apic.c | |||
@@ -4,10 +4,9 @@ | |||
4 | 4 | ||
5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
6 | #include <linux/irq.h> | 6 | #include <linux/irq.h> |
7 | #include <linux/msi.h> | ||
7 | #include <asm/smp.h> | 8 | #include <asm/smp.h> |
8 | 9 | ||
9 | #include "msi.h" | ||
10 | |||
11 | /* | 10 | /* |
12 | * Shifts for APIC-based data | 11 | * Shifts for APIC-based data |
13 | */ | 12 | */ |
@@ -31,6 +30,7 @@ | |||
31 | * Shift/mask fields for APIC-based bus address | 30 | * Shift/mask fields for APIC-based bus address |
32 | */ | 31 | */ |
33 | 32 | ||
33 | #define MSI_TARGET_CPU_SHIFT 4 | ||
34 | #define MSI_ADDR_HEADER 0xfee00000 | 34 | #define MSI_ADDR_HEADER 0xfee00000 |
35 | 35 | ||
36 | #define MSI_ADDR_DESTID_MASK 0xfff0000f | 36 | #define MSI_ADDR_DESTID_MASK 0xfff0000f |
@@ -44,58 +44,100 @@ | |||
44 | #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) | 44 | #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) |
45 | #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) | 45 | #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) |
46 | 46 | ||
47 | static struct irq_chip ia64_msi_chip; | ||
47 | 48 | ||
48 | static void | 49 | #ifdef CONFIG_SMP |
49 | msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) | 50 | static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) |
50 | { | 51 | { |
51 | u32 addr = msg->address_lo; | 52 | struct msi_msg msg; |
53 | u32 addr; | ||
54 | |||
55 | read_msi_msg(irq, &msg); | ||
52 | 56 | ||
57 | addr = msg.address_lo; | ||
53 | addr &= MSI_ADDR_DESTID_MASK; | 58 | addr &= MSI_ADDR_DESTID_MASK; |
54 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask))); | 59 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask))); |
60 | msg.address_lo = addr; | ||
55 | 61 | ||
56 | msg->address_lo = addr; | 62 | write_msi_msg(irq, &msg); |
63 | set_native_irq_info(irq, cpu_mask); | ||
57 | } | 64 | } |
65 | #endif /* CONFIG_SMP */ | ||
58 | 66 | ||
59 | static int | 67 | int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) |
60 | msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ | ||
61 | unsigned int irq, | ||
62 | struct msi_msg *msg) | ||
63 | { | 68 | { |
69 | struct msi_msg msg; | ||
64 | unsigned long dest_phys_id; | 70 | unsigned long dest_phys_id; |
65 | unsigned int vector; | 71 | unsigned int vector; |
66 | 72 | ||
67 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); | 73 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); |
68 | vector = irq; | 74 | vector = irq; |
69 | 75 | ||
70 | msg->address_hi = 0; | 76 | msg.address_hi = 0; |
71 | msg->address_lo = | 77 | msg.address_lo = |
72 | MSI_ADDR_HEADER | | 78 | MSI_ADDR_HEADER | |
73 | MSI_ADDR_DESTMODE_PHYS | | 79 | MSI_ADDR_DESTMODE_PHYS | |
74 | MSI_ADDR_REDIRECTION_CPU | | 80 | MSI_ADDR_REDIRECTION_CPU | |
75 | MSI_ADDR_DESTID_CPU(dest_phys_id); | 81 | MSI_ADDR_DESTID_CPU(dest_phys_id); |
76 | 82 | ||
77 | msg->data = | 83 | msg.data = |
78 | MSI_DATA_TRIGGER_EDGE | | 84 | MSI_DATA_TRIGGER_EDGE | |
79 | MSI_DATA_LEVEL_ASSERT | | 85 | MSI_DATA_LEVEL_ASSERT | |
80 | MSI_DATA_DELIVERY_FIXED | | 86 | MSI_DATA_DELIVERY_FIXED | |
81 | MSI_DATA_VECTOR(vector); | 87 | MSI_DATA_VECTOR(vector); |
82 | 88 | ||
89 | write_msi_msg(irq, &msg); | ||
90 | set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); | ||
91 | |||
83 | return 0; | 92 | return 0; |
84 | } | 93 | } |
85 | 94 | ||
86 | static void | 95 | void ia64_teardown_msi_irq(unsigned int irq) |
87 | msi_teardown_apic(unsigned int irq) | ||
88 | { | 96 | { |
89 | return; /* no-op */ | 97 | return; /* no-op */ |
90 | } | 98 | } |
91 | 99 | ||
100 | static void ia64_ack_msi_irq(unsigned int irq) | ||
101 | { | ||
102 | move_native_irq(irq); | ||
103 | ia64_eoi(); | ||
104 | } | ||
105 | |||
106 | static int ia64_msi_retrigger_irq(unsigned int irq) | ||
107 | { | ||
108 | unsigned int vector = irq; | ||
109 | ia64_resend_irq(vector); | ||
110 | |||
111 | return 1; | ||
112 | } | ||
113 | |||
92 | /* | 114 | /* |
93 | * Generic ops used on most IA archs/platforms. Set with msi_register() | 115 | * Generic ops used on most IA64 platforms. |
94 | */ | 116 | */ |
95 | 117 | static struct irq_chip ia64_msi_chip = { | |
96 | struct msi_ops msi_apic_ops = { | 118 | .name = "PCI-MSI", |
97 | .needs_64bit_address = 0, | 119 | .mask = mask_msi_irq, |
98 | .setup = msi_setup_apic, | 120 | .unmask = unmask_msi_irq, |
99 | .teardown = msi_teardown_apic, | 121 | .ack = ia64_ack_msi_irq, |
100 | .target = msi_target_apic, | 122 | #ifdef CONFIG_SMP |
123 | .set_affinity = ia64_set_msi_irq_affinity, | ||
124 | #endif | ||
125 | .retrigger = ia64_msi_retrigger_irq, | ||
101 | }; | 126 | }; |
127 | |||
128 | |||
129 | int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) | ||
130 | { | ||
131 | if (platform_setup_msi_irq) | ||
132 | return platform_setup_msi_irq(irq, pdev); | ||
133 | |||
134 | return ia64_setup_msi_irq(irq, pdev); | ||
135 | } | ||
136 | |||
137 | void arch_teardown_msi_irq(unsigned int irq) | ||
138 | { | ||
139 | if (platform_teardown_msi_irq) | ||
140 | return platform_teardown_msi_irq(irq); | ||
141 | |||
142 | return ia64_teardown_msi_irq(irq); | ||
143 | } | ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index fc7dd2a239dd..f9fdc54473c4 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/smp_lock.h> | 15 | #include <linux/smp_lock.h> |
16 | #include <linux/pci.h> | 16 | #include <linux/pci.h> |
17 | #include <linux/proc_fs.h> | 17 | #include <linux/proc_fs.h> |
18 | #include <linux/msi.h> | ||
18 | 19 | ||
19 | #include <asm/errno.h> | 20 | #include <asm/errno.h> |
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
@@ -29,15 +30,6 @@ static kmem_cache_t* msi_cachep; | |||
29 | 30 | ||
30 | static int pci_msi_enable = 1; | 31 | static int pci_msi_enable = 1; |
31 | 32 | ||
32 | static struct msi_ops *msi_ops; | ||
33 | |||
34 | int | ||
35 | msi_register(struct msi_ops *ops) | ||
36 | { | ||
37 | msi_ops = ops; | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int msi_cache_init(void) | 33 | static int msi_cache_init(void) |
42 | { | 34 | { |
43 | msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc), | 35 | msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc), |
@@ -80,8 +72,9 @@ static void msi_set_mask_bit(unsigned int irq, int flag) | |||
80 | } | 72 | } |
81 | } | 73 | } |
82 | 74 | ||
83 | static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | 75 | void read_msi_msg(unsigned int irq, struct msi_msg *msg) |
84 | { | 76 | { |
77 | struct msi_desc *entry = get_irq_data(irq); | ||
85 | switch(entry->msi_attrib.type) { | 78 | switch(entry->msi_attrib.type) { |
86 | case PCI_CAP_ID_MSI: | 79 | case PCI_CAP_ID_MSI: |
87 | { | 80 | { |
@@ -118,8 +111,9 @@ static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
118 | } | 111 | } |
119 | } | 112 | } |
120 | 113 | ||
121 | static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | 114 | void write_msi_msg(unsigned int irq, struct msi_msg *msg) |
122 | { | 115 | { |
116 | struct msi_desc *entry = get_irq_data(irq); | ||
123 | switch (entry->msi_attrib.type) { | 117 | switch (entry->msi_attrib.type) { |
124 | case PCI_CAP_ID_MSI: | 118 | case PCI_CAP_ID_MSI: |
125 | { | 119 | { |
@@ -157,53 +151,16 @@ static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
157 | } | 151 | } |
158 | } | 152 | } |
159 | 153 | ||
160 | #ifdef CONFIG_SMP | 154 | void mask_msi_irq(unsigned int irq) |
161 | static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask) | ||
162 | { | ||
163 | struct msi_desc *entry; | ||
164 | struct msi_msg msg; | ||
165 | |||
166 | entry = msi_desc[irq]; | ||
167 | if (!entry || !entry->dev) | ||
168 | return; | ||
169 | |||
170 | read_msi_msg(entry, &msg); | ||
171 | msi_ops->target(irq, cpu_mask, &msg); | ||
172 | write_msi_msg(entry, &msg); | ||
173 | set_native_irq_info(irq, cpu_mask); | ||
174 | } | ||
175 | #else | ||
176 | #define set_msi_affinity NULL | ||
177 | #endif /* CONFIG_SMP */ | ||
178 | |||
179 | static void mask_MSI_irq(unsigned int irq) | ||
180 | { | 155 | { |
181 | msi_set_mask_bit(irq, 1); | 156 | msi_set_mask_bit(irq, 1); |
182 | } | 157 | } |
183 | 158 | ||
184 | static void unmask_MSI_irq(unsigned int irq) | 159 | void unmask_msi_irq(unsigned int irq) |
185 | { | 160 | { |
186 | msi_set_mask_bit(irq, 0); | 161 | msi_set_mask_bit(irq, 0); |
187 | } | 162 | } |
188 | 163 | ||
189 | static void ack_msi_irq(unsigned int irq) | ||
190 | { | ||
191 | move_native_irq(irq); | ||
192 | ack_APIC_irq(); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, | ||
197 | * which implement the MSI or MSI-X Capability Structure. | ||
198 | */ | ||
199 | static struct irq_chip msi_chip = { | ||
200 | .name = "PCI-MSI", | ||
201 | .unmask = unmask_MSI_irq, | ||
202 | .mask = mask_MSI_irq, | ||
203 | .ack = ack_msi_irq, | ||
204 | .set_affinity = set_msi_affinity | ||
205 | }; | ||
206 | |||
207 | static int msi_free_irq(struct pci_dev* dev, int irq); | 164 | static int msi_free_irq(struct pci_dev* dev, int irq); |
208 | static int msi_init(void) | 165 | static int msi_init(void) |
209 | { | 166 | { |
@@ -219,22 +176,6 @@ static int msi_init(void) | |||
219 | return status; | 176 | return status; |
220 | } | 177 | } |
221 | 178 | ||
222 | status = msi_arch_init(); | ||
223 | if (status < 0) { | ||
224 | pci_msi_enable = 0; | ||
225 | printk(KERN_WARNING | ||
226 | "PCI: MSI arch init failed. MSI disabled.\n"); | ||
227 | return status; | ||
228 | } | ||
229 | |||
230 | if (! msi_ops) { | ||
231 | pci_msi_enable = 0; | ||
232 | printk(KERN_WARNING | ||
233 | "PCI: MSI ops not registered. MSI disabled.\n"); | ||
234 | status = -EINVAL; | ||
235 | return status; | ||
236 | } | ||
237 | |||
238 | status = msi_cache_init(); | 179 | status = msi_cache_init(); |
239 | if (status < 0) { | 180 | if (status < 0) { |
240 | pci_msi_enable = 0; | 181 | pci_msi_enable = 0; |
@@ -268,7 +209,7 @@ static void attach_msi_entry(struct msi_desc *entry, int irq) | |||
268 | spin_unlock_irqrestore(&msi_lock, flags); | 209 | spin_unlock_irqrestore(&msi_lock, flags); |
269 | } | 210 | } |
270 | 211 | ||
271 | static int create_msi_irq(struct irq_chip *chip) | 212 | static int create_msi_irq(void) |
272 | { | 213 | { |
273 | struct msi_desc *entry; | 214 | struct msi_desc *entry; |
274 | int irq; | 215 | int irq; |
@@ -283,7 +224,6 @@ static int create_msi_irq(struct irq_chip *chip) | |||
283 | return -EBUSY; | 224 | return -EBUSY; |
284 | } | 225 | } |
285 | 226 | ||
286 | set_irq_chip_and_handler(irq, chip, handle_edge_irq); | ||
287 | set_irq_data(irq, entry); | 227 | set_irq_data(irq, entry); |
288 | 228 | ||
289 | return irq; | 229 | return irq; |
@@ -473,7 +413,7 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
473 | struct msi_desc *entry; | 413 | struct msi_desc *entry; |
474 | 414 | ||
475 | entry = msi_desc[irq]; | 415 | entry = msi_desc[irq]; |
476 | read_msi_msg(entry, &entry->msg_save); | 416 | read_msi_msg(irq, &entry->msg_save); |
477 | 417 | ||
478 | tail = msi_desc[irq]->link.tail; | 418 | tail = msi_desc[irq]->link.tail; |
479 | irq = tail; | 419 | irq = tail; |
@@ -512,7 +452,7 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
512 | irq = head = dev->irq; | 452 | irq = head = dev->irq; |
513 | while (head != tail) { | 453 | while (head != tail) { |
514 | entry = msi_desc[irq]; | 454 | entry = msi_desc[irq]; |
515 | write_msi_msg(entry, &entry->msg_save); | 455 | write_msi_msg(irq, &entry->msg_save); |
516 | 456 | ||
517 | tail = msi_desc[irq]->link.tail; | 457 | tail = msi_desc[irq]->link.tail; |
518 | irq = tail; | 458 | irq = tail; |
@@ -524,39 +464,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
524 | } | 464 | } |
525 | #endif | 465 | #endif |
526 | 466 | ||
527 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | ||
528 | { | ||
529 | int status; | ||
530 | struct msi_msg msg; | ||
531 | int pos; | ||
532 | u16 control; | ||
533 | |||
534 | pos = entry->msi_attrib.pos; | ||
535 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
536 | |||
537 | /* Configure MSI capability structure */ | ||
538 | status = msi_ops->setup(dev, dev->irq, &msg); | ||
539 | if (status < 0) | ||
540 | return status; | ||
541 | |||
542 | write_msi_msg(entry, &msg); | ||
543 | if (entry->msi_attrib.maskbit) { | ||
544 | unsigned int maskbits, temp; | ||
545 | /* All MSIs are unmasked by default, Mask them all */ | ||
546 | pci_read_config_dword(dev, | ||
547 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
548 | &maskbits); | ||
549 | temp = (1 << multi_msi_capable(control)); | ||
550 | temp = ((temp - 1) & ~temp); | ||
551 | maskbits |= temp; | ||
552 | pci_write_config_dword(dev, | ||
553 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
554 | maskbits); | ||
555 | } | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /** | 467 | /** |
561 | * msi_capability_init - configure device's MSI capability structure | 468 | * msi_capability_init - configure device's MSI capability structure |
562 | * @dev: pointer to the pci_dev data structure of MSI device function | 469 | * @dev: pointer to the pci_dev data structure of MSI device function |
@@ -576,7 +483,7 @@ static int msi_capability_init(struct pci_dev *dev) | |||
576 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 483 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
577 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 484 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
578 | /* MSI Entry Initialization */ | 485 | /* MSI Entry Initialization */ |
579 | irq = create_msi_irq(&msi_chip); | 486 | irq = create_msi_irq(); |
580 | if (irq < 0) | 487 | if (irq < 0) |
581 | return irq; | 488 | return irq; |
582 | 489 | ||
@@ -589,16 +496,27 @@ static int msi_capability_init(struct pci_dev *dev) | |||
589 | entry->msi_attrib.maskbit = is_mask_bit_support(control); | 496 | entry->msi_attrib.maskbit = is_mask_bit_support(control); |
590 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ | 497 | entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ |
591 | entry->msi_attrib.pos = pos; | 498 | entry->msi_attrib.pos = pos; |
592 | dev->irq = irq; | ||
593 | entry->dev = dev; | ||
594 | if (is_mask_bit_support(control)) { | 499 | if (is_mask_bit_support(control)) { |
595 | entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos, | 500 | entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos, |
596 | is_64bit_address(control)); | 501 | is_64bit_address(control)); |
597 | } | 502 | } |
503 | entry->dev = dev; | ||
504 | if (entry->msi_attrib.maskbit) { | ||
505 | unsigned int maskbits, temp; | ||
506 | /* All MSIs are unmasked by default, Mask them all */ | ||
507 | pci_read_config_dword(dev, | ||
508 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
509 | &maskbits); | ||
510 | temp = (1 << multi_msi_capable(control)); | ||
511 | temp = ((temp - 1) & ~temp); | ||
512 | maskbits |= temp; | ||
513 | pci_write_config_dword(dev, | ||
514 | msi_mask_bits_reg(pos, is_64bit_address(control)), | ||
515 | maskbits); | ||
516 | } | ||
598 | /* Configure MSI capability structure */ | 517 | /* Configure MSI capability structure */ |
599 | status = msi_register_init(dev, entry); | 518 | status = arch_setup_msi_irq(irq, dev); |
600 | if (status != 0) { | 519 | if (status < 0) { |
601 | dev->irq = entry->msi_attrib.default_irq; | ||
602 | destroy_msi_irq(irq); | 520 | destroy_msi_irq(irq); |
603 | return status; | 521 | return status; |
604 | } | 522 | } |
@@ -607,6 +525,7 @@ static int msi_capability_init(struct pci_dev *dev) | |||
607 | /* Set MSI enabled bits */ | 525 | /* Set MSI enabled bits */ |
608 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 526 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
609 | 527 | ||
528 | dev->irq = irq; | ||
610 | return 0; | 529 | return 0; |
611 | } | 530 | } |
612 | 531 | ||
@@ -624,7 +543,6 @@ static int msix_capability_init(struct pci_dev *dev, | |||
624 | struct msix_entry *entries, int nvec) | 543 | struct msix_entry *entries, int nvec) |
625 | { | 544 | { |
626 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 545 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
627 | struct msi_msg msg; | ||
628 | int status; | 546 | int status; |
629 | int irq, pos, i, j, nr_entries, temp = 0; | 547 | int irq, pos, i, j, nr_entries, temp = 0; |
630 | unsigned long phys_addr; | 548 | unsigned long phys_addr; |
@@ -648,7 +566,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
648 | 566 | ||
649 | /* MSI-X Table Initialization */ | 567 | /* MSI-X Table Initialization */ |
650 | for (i = 0; i < nvec; i++) { | 568 | for (i = 0; i < nvec; i++) { |
651 | irq = create_msi_irq(&msi_chip); | 569 | irq = create_msi_irq(); |
652 | if (irq < 0) | 570 | if (irq < 0) |
653 | break; | 571 | break; |
654 | 572 | ||
@@ -676,13 +594,12 @@ static int msix_capability_init(struct pci_dev *dev, | |||
676 | temp = irq; | 594 | temp = irq; |
677 | tail = entry; | 595 | tail = entry; |
678 | /* Configure MSI-X capability structure */ | 596 | /* Configure MSI-X capability structure */ |
679 | status = msi_ops->setup(dev, irq, &msg); | 597 | status = arch_setup_msi_irq(irq, dev); |
680 | if (status < 0) { | 598 | if (status < 0) { |
681 | destroy_msi_irq(irq); | 599 | destroy_msi_irq(irq); |
682 | break; | 600 | break; |
683 | } | 601 | } |
684 | 602 | ||
685 | write_msi_msg(entry, &msg); | ||
686 | attach_msi_entry(entry, irq); | 603 | attach_msi_entry(entry, irq); |
687 | } | 604 | } |
688 | if (i != nvec) { | 605 | if (i != nvec) { |
@@ -746,7 +663,6 @@ int pci_msi_supported(struct pci_dev * dev) | |||
746 | int pci_enable_msi(struct pci_dev* dev) | 663 | int pci_enable_msi(struct pci_dev* dev) |
747 | { | 664 | { |
748 | int pos, temp, status; | 665 | int pos, temp, status; |
749 | u16 control; | ||
750 | 666 | ||
751 | if (pci_msi_supported(dev) < 0) | 667 | if (pci_msi_supported(dev) < 0) |
752 | return -EINVAL; | 668 | return -EINVAL; |
@@ -761,10 +677,6 @@ int pci_enable_msi(struct pci_dev* dev) | |||
761 | if (!pos) | 677 | if (!pos) |
762 | return -EINVAL; | 678 | return -EINVAL; |
763 | 679 | ||
764 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
765 | if (!is_64bit_address(control) && msi_ops->needs_64bit_address) | ||
766 | return -EINVAL; | ||
767 | |||
768 | WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); | 680 | WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); |
769 | 681 | ||
770 | /* Check whether driver already requested for MSI-X irqs */ | 682 | /* Check whether driver already requested for MSI-X irqs */ |
@@ -831,7 +743,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq) | |||
831 | void __iomem *base; | 743 | void __iomem *base; |
832 | unsigned long flags; | 744 | unsigned long flags; |
833 | 745 | ||
834 | msi_ops->teardown(irq); | 746 | arch_teardown_msi_irq(irq); |
835 | 747 | ||
836 | spin_lock_irqsave(&msi_lock, flags); | 748 | spin_lock_irqsave(&msi_lock, flags); |
837 | entry = msi_desc[irq]; | 749 | entry = msi_desc[irq]; |
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 77823bfed5c1..f0cca1772f9c 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h | |||
@@ -6,8 +6,6 @@ | |||
6 | #ifndef MSI_H | 6 | #ifndef MSI_H |
7 | #define MSI_H | 7 | #define MSI_H |
8 | 8 | ||
9 | #include <asm/msi.h> | ||
10 | |||
11 | /* | 9 | /* |
12 | * MSI-X Address Register | 10 | * MSI-X Address Register |
13 | */ | 11 | */ |
@@ -49,29 +47,4 @@ | |||
49 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) | 47 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) |
50 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) | 48 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) |
51 | 49 | ||
52 | struct msi_desc { | ||
53 | struct { | ||
54 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | ||
55 | __u8 maskbit : 1; /* mask-pending bit supported ? */ | ||
56 | __u8 unused : 1; | ||
57 | __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ | ||
58 | __u8 pos; /* Location of the msi capability */ | ||
59 | __u16 entry_nr; /* specific enabled entry */ | ||
60 | unsigned default_irq; /* default pre-assigned irq */ | ||
61 | }msi_attrib; | ||
62 | |||
63 | struct { | ||
64 | __u16 head; | ||
65 | __u16 tail; | ||
66 | }link; | ||
67 | |||
68 | void __iomem *mask_base; | ||
69 | struct pci_dev *dev; | ||
70 | |||
71 | #ifdef CONFIG_PM | ||
72 | /* PM save area for MSIX address/data */ | ||
73 | struct msi_msg msg_save; | ||
74 | #endif | ||
75 | }; | ||
76 | |||
77 | #endif /* MSI_H */ | 50 | #endif /* MSI_H */ |
diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h deleted file mode 100644 index 7368a89a0f42..000000000000 --- a/include/asm-i386/msi.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003-2004 Intel | ||
3 | * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) | ||
4 | */ | ||
5 | |||
6 | #ifndef ASM_MSI_H | ||
7 | #define ASM_MSI_H | ||
8 | |||
9 | #include <asm/desc.h> | ||
10 | #include <mach_apic.h> | ||
11 | |||
12 | extern struct msi_ops arch_msi_ops; | ||
13 | |||
14 | static inline int msi_arch_init(void) | ||
15 | { | ||
16 | msi_register(&arch_msi_ops); | ||
17 | return 0; | ||
18 | } | ||
19 | |||
20 | #endif /* ASM_MSI_H */ | ||
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 15b545a897a4..90cba967df35 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h | |||
@@ -20,6 +20,7 @@ struct page; | |||
20 | struct mm_struct; | 20 | struct mm_struct; |
21 | struct pci_bus; | 21 | struct pci_bus; |
22 | struct task_struct; | 22 | struct task_struct; |
23 | struct pci_dev; | ||
23 | 24 | ||
24 | typedef void ia64_mv_setup_t (char **); | 25 | typedef void ia64_mv_setup_t (char **); |
25 | typedef void ia64_mv_cpu_init_t (void); | 26 | typedef void ia64_mv_cpu_init_t (void); |
@@ -75,7 +76,9 @@ typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *); | |||
75 | typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); | 76 | typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); |
76 | typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); | 77 | typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); |
77 | typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); | 78 | typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); |
78 | typedef int ia64_mv_msi_init_t (void); | 79 | |
80 | typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev); | ||
81 | typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq); | ||
79 | 82 | ||
80 | static inline void | 83 | static inline void |
81 | machvec_noop (void) | 84 | machvec_noop (void) |
@@ -154,7 +157,8 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *); | |||
154 | # define platform_readl_relaxed ia64_mv.readl_relaxed | 157 | # define platform_readl_relaxed ia64_mv.readl_relaxed |
155 | # define platform_readq_relaxed ia64_mv.readq_relaxed | 158 | # define platform_readq_relaxed ia64_mv.readq_relaxed |
156 | # define platform_migrate ia64_mv.migrate | 159 | # define platform_migrate ia64_mv.migrate |
157 | # define platform_msi_init ia64_mv.msi_init | 160 | # define platform_setup_msi_irq ia64_mv.setup_msi_irq |
161 | # define platform_teardown_msi_irq ia64_mv.teardown_msi_irq | ||
158 | # endif | 162 | # endif |
159 | 163 | ||
160 | /* __attribute__((__aligned__(16))) is required to make size of the | 164 | /* __attribute__((__aligned__(16))) is required to make size of the |
@@ -204,7 +208,8 @@ struct ia64_machine_vector { | |||
204 | ia64_mv_readl_relaxed_t *readl_relaxed; | 208 | ia64_mv_readl_relaxed_t *readl_relaxed; |
205 | ia64_mv_readq_relaxed_t *readq_relaxed; | 209 | ia64_mv_readq_relaxed_t *readq_relaxed; |
206 | ia64_mv_migrate_t *migrate; | 210 | ia64_mv_migrate_t *migrate; |
207 | ia64_mv_msi_init_t *msi_init; | 211 | ia64_mv_setup_msi_irq_t *setup_msi_irq; |
212 | ia64_mv_teardown_msi_irq_t *teardown_msi_irq; | ||
208 | } __attribute__((__aligned__(16))); /* align attrib? see above comment */ | 213 | } __attribute__((__aligned__(16))); /* align attrib? see above comment */ |
209 | 214 | ||
210 | #define MACHVEC_INIT(name) \ | 215 | #define MACHVEC_INIT(name) \ |
@@ -250,7 +255,8 @@ struct ia64_machine_vector { | |||
250 | platform_readl_relaxed, \ | 255 | platform_readl_relaxed, \ |
251 | platform_readq_relaxed, \ | 256 | platform_readq_relaxed, \ |
252 | platform_migrate, \ | 257 | platform_migrate, \ |
253 | platform_msi_init, \ | 258 | platform_setup_msi_irq, \ |
259 | platform_teardown_msi_irq, \ | ||
254 | } | 260 | } |
255 | 261 | ||
256 | extern struct ia64_machine_vector ia64_mv; | 262 | extern struct ia64_machine_vector ia64_mv; |
@@ -404,8 +410,11 @@ extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size | |||
404 | #ifndef platform_migrate | 410 | #ifndef platform_migrate |
405 | # define platform_migrate machvec_noop_task | 411 | # define platform_migrate machvec_noop_task |
406 | #endif | 412 | #endif |
407 | #ifndef platform_msi_init | 413 | #ifndef platform_setup_msi_irq |
408 | # define platform_msi_init ((ia64_mv_msi_init_t*)NULL) | 414 | # define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL) |
415 | #endif | ||
416 | #ifndef platform_teardown_msi_irq | ||
417 | # define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL) | ||
409 | #endif | 418 | #endif |
410 | 419 | ||
411 | #endif /* _ASM_IA64_MACHVEC_H */ | 420 | #endif /* _ASM_IA64_MACHVEC_H */ |
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h index cf724dc79d8c..c54b165b1c17 100644 --- a/include/asm-ia64/machvec_sn2.h +++ b/include/asm-ia64/machvec_sn2.h | |||
@@ -67,7 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device; | |||
67 | extern ia64_mv_dma_mapping_error sn_dma_mapping_error; | 67 | extern ia64_mv_dma_mapping_error sn_dma_mapping_error; |
68 | extern ia64_mv_dma_supported sn_dma_supported; | 68 | extern ia64_mv_dma_supported sn_dma_supported; |
69 | extern ia64_mv_migrate_t sn_migrate; | 69 | extern ia64_mv_migrate_t sn_migrate; |
70 | extern ia64_mv_msi_init_t sn_msi_init; | 70 | extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq; |
71 | extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq; | ||
71 | 72 | ||
72 | 73 | ||
73 | /* | 74 | /* |
@@ -120,9 +121,11 @@ extern ia64_mv_msi_init_t sn_msi_init; | |||
120 | #define platform_dma_supported sn_dma_supported | 121 | #define platform_dma_supported sn_dma_supported |
121 | #define platform_migrate sn_migrate | 122 | #define platform_migrate sn_migrate |
122 | #ifdef CONFIG_PCI_MSI | 123 | #ifdef CONFIG_PCI_MSI |
123 | #define platform_msi_init sn_msi_init | 124 | #define platform_setup_msi_irq sn_setup_msi_irq |
125 | #define platform_teardown_msi_irq sn_teardown_msi_irq | ||
124 | #else | 126 | #else |
125 | #define platform_msi_init ((ia64_mv_msi_init_t*)NULL) | 127 | #define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL) |
128 | #define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL) | ||
126 | #endif | 129 | #endif |
127 | 130 | ||
128 | #include <asm/sn/io.h> | 131 | #include <asm/sn/io.h> |
diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h deleted file mode 100644 index bb92b0dbde2f..000000000000 --- a/include/asm-ia64/msi.h +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003-2004 Intel | ||
3 | * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) | ||
4 | */ | ||
5 | |||
6 | #ifndef ASM_MSI_H | ||
7 | #define ASM_MSI_H | ||
8 | |||
9 | #define NR_VECTORS NR_IRQS | ||
10 | #define FIRST_DEVICE_VECTOR IA64_FIRST_DEVICE_VECTOR | ||
11 | #define LAST_DEVICE_VECTOR IA64_LAST_DEVICE_VECTOR | ||
12 | static inline void set_intr_gate (int nr, void *func) {} | ||
13 | #define IO_APIC_VECTOR(irq) (irq) | ||
14 | #define ack_APIC_irq ia64_eoi | ||
15 | #define MSI_TARGET_CPU_SHIFT 4 | ||
16 | |||
17 | extern struct msi_ops msi_apic_ops; | ||
18 | |||
19 | static inline int msi_arch_init(void) | ||
20 | { | ||
21 | if (platform_msi_init) | ||
22 | return platform_msi_init(); | ||
23 | |||
24 | /* default ops for most ia64 platforms */ | ||
25 | msi_register(&msi_apic_ops); | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | #endif /* ASM_MSI_H */ | ||
diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h deleted file mode 100644 index 1876fda52ae3..000000000000 --- a/include/asm-x86_64/msi.h +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003-2004 Intel | ||
3 | * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) | ||
4 | */ | ||
5 | |||
6 | #ifndef ASM_MSI_H | ||
7 | #define ASM_MSI_H | ||
8 | |||
9 | #include <asm/desc.h> | ||
10 | #include <asm/mach_apic.h> | ||
11 | #include <asm/smp.h> | ||
12 | |||
13 | extern struct msi_ops arch_msi_ops; | ||
14 | |||
15 | static inline int msi_arch_init(void) | ||
16 | { | ||
17 | msi_register(&arch_msi_ops); | ||
18 | return 0; | ||
19 | } | ||
20 | |||
21 | #endif /* ASM_MSI_H */ | ||
diff --git a/include/linux/msi.h b/include/linux/msi.h new file mode 100644 index 000000000000..c7ef94343673 --- /dev/null +++ b/include/linux/msi.h | |||
@@ -0,0 +1,49 @@ | |||
1 | #ifndef LINUX_MSI_H | ||
2 | #define LINUX_MSI_H | ||
3 | |||
4 | struct msi_msg { | ||
5 | u32 address_lo; /* low 32 bits of msi message address */ | ||
6 | u32 address_hi; /* high 32 bits of msi message address */ | ||
7 | u32 data; /* 16 bits of msi message data */ | ||
8 | }; | ||
9 | |||
10 | /* Heper functions */ | ||
11 | extern void mask_msi_irq(unsigned int irq); | ||
12 | extern void unmask_msi_irq(unsigned int irq); | ||
13 | extern void read_msi_msg(unsigned int irq, struct msi_msg *msg); | ||
14 | |||
15 | extern void write_msi_msg(unsigned int irq, struct msi_msg *msg); | ||
16 | |||
17 | struct msi_desc { | ||
18 | struct { | ||
19 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | ||
20 | __u8 maskbit : 1; /* mask-pending bit supported ? */ | ||
21 | __u8 unused : 1; | ||
22 | __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ | ||
23 | __u8 pos; /* Location of the msi capability */ | ||
24 | __u16 entry_nr; /* specific enabled entry */ | ||
25 | unsigned default_irq; /* default pre-assigned irq */ | ||
26 | }msi_attrib; | ||
27 | |||
28 | struct { | ||
29 | __u16 head; | ||
30 | __u16 tail; | ||
31 | }link; | ||
32 | |||
33 | void __iomem *mask_base; | ||
34 | struct pci_dev *dev; | ||
35 | |||
36 | #ifdef CONFIG_PM | ||
37 | /* PM save area for MSIX address/data */ | ||
38 | struct msi_msg msg_save; | ||
39 | #endif | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * The arch hook for setup up msi irqs | ||
44 | */ | ||
45 | int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev); | ||
46 | void arch_teardown_msi_irq(unsigned int irq); | ||
47 | |||
48 | |||
49 | #endif /* LINUX_MSI_H */ | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index 9b34bc8f34e4..0da5a4a8940f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -595,11 +595,6 @@ struct msix_entry { | |||
595 | u16 entry; /* driver uses to specify entry, OS writes */ | 595 | u16 entry; /* driver uses to specify entry, OS writes */ |
596 | }; | 596 | }; |
597 | 597 | ||
598 | struct msi_msg { | ||
599 | u32 address_lo; /* low 32 bits of msi message address */ | ||
600 | u32 address_hi; /* high 32 bits of msi message address */ | ||
601 | u32 data; /* 16 bits of msi message data */ | ||
602 | }; | ||
603 | 598 | ||
604 | #ifndef CONFIG_PCI_MSI | 599 | #ifndef CONFIG_PCI_MSI |
605 | static inline void pci_scan_msi_device(struct pci_dev *dev) {} | 600 | static inline void pci_scan_msi_device(struct pci_dev *dev) {} |
@@ -617,68 +612,6 @@ extern int pci_enable_msix(struct pci_dev* dev, | |||
617 | struct msix_entry *entries, int nvec); | 612 | struct msix_entry *entries, int nvec); |
618 | extern void pci_disable_msix(struct pci_dev *dev); | 613 | extern void pci_disable_msix(struct pci_dev *dev); |
619 | extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); | 614 | extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); |
620 | |||
621 | /* | ||
622 | * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) | ||
623 | * to abstract platform-specific tasks relating to MSI address generation | ||
624 | * and resource management. | ||
625 | */ | ||
626 | struct msi_ops { | ||
627 | int needs_64bit_address; | ||
628 | /** | ||
629 | * setup - generate an MSI bus address and data for a given vector | ||
630 | * @pdev: PCI device context (in) | ||
631 | * @irq: irq allocated by the msi core (in) | ||
632 | * @msg: PCI bus address and data for msi message (out) | ||
633 | * | ||
634 | * Description: The setup op is used to generate a PCI bus addres and | ||
635 | * data which the msi core will program into the card MSI capability | ||
636 | * registers. The setup routine is responsible for picking an initial | ||
637 | * cpu to target the MSI at. The setup routine is responsible for | ||
638 | * examining pdev to determine the MSI capabilities of the card and | ||
639 | * generating a suitable address/data. The setup routine is | ||
640 | * responsible for allocating and tracking any system resources it | ||
641 | * needs to route the MSI to the cpu it picks, and for associating | ||
642 | * those resources with the passed in vector. | ||
643 | * | ||
644 | * Returns 0 if the MSI address/data was successfully setup. | ||
645 | **/ | ||
646 | |||
647 | int (*setup) (struct pci_dev *pdev, unsigned int irq, | ||
648 | struct msi_msg *msg); | ||
649 | |||
650 | /** | ||
651 | * teardown - release resources allocated by setup | ||
652 | * @vector: vector context for resources (in) | ||
653 | * | ||
654 | * Description: The teardown op is used to release any resources | ||
655 | * that were allocated in the setup routine associated with the passed | ||
656 | * in vector. | ||
657 | **/ | ||
658 | |||
659 | void (*teardown) (unsigned int irq); | ||
660 | |||
661 | /** | ||
662 | * target - retarget an MSI at a different cpu | ||
663 | * @vector: vector context for resources (in) | ||
664 | * @cpu: new cpu to direct vector at (in) | ||
665 | * @addr_hi: new value of PCI bus upper 32 bits (in/out) | ||
666 | * @addr_lo: new value of PCI bus lower 32 bits (in/out) | ||
667 | * | ||
668 | * Description: The target op is used to redirect an MSI vector | ||
669 | * at a different cpu. addr_hi/addr_lo coming in are the existing | ||
670 | * values that the MSI core has programmed into the card. The | ||
671 | * target code is responsible for freeing any resources (if any) | ||
672 | * associated with the old address, and generating a new PCI bus | ||
673 | * addr_hi/addr_lo that will redirect the vector at the indicated cpu. | ||
674 | **/ | ||
675 | |||
676 | void (*target) (unsigned int irq, cpumask_t cpumask, | ||
677 | struct msi_msg *msg); | ||
678 | }; | ||
679 | |||
680 | extern int msi_register(struct msi_ops *ops); | ||
681 | |||
682 | #endif | 615 | #endif |
683 | 616 | ||
684 | #ifdef CONFIG_HT_IRQ | 617 | #ifdef CONFIG_HT_IRQ |