diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2006-10-04 05:16:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:27 -0400 |
commit | 38bc0361303535c86f6b67b151a541728d7bdae6 (patch) | |
tree | 6a3939b1f7aea3b00fc4ecd72646fd8442c95766 | |
parent | 0366f8f7137deb072991e4c50769c6da31f8940c (diff) |
[PATCH] genirq: msi: refactor the msi_ops
The current msi_ops are short sighted in a number of ways, this patch attempts
to fix the glaring deficiences.
- Report in msi_ops if a 64bit address is needed in the msi message, so we
can fail 32bit only msi structures.
- Send and receive a full struct msi_msg in both setup and target. This is
a little cleaner and allows for architectures that need to modify the data
to retarget the msi interrupt to a different cpu.
- In target pass in the full cpu mask instead of just the first cpu in case
we can make use of the full cpu mask.
- Operate in terms of irqs and not vectors, currently there is still a 1-1
relationship but on architectures other than ia64 I expect this will change.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rajesh Shah <rajesh.shah@intel.com>
Cc: Andi Kleen <ak@muc.de>
Cc: "Protasevich, Natalie" <Natalie.Protasevich@UNISYS.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/pci/msi-altix.c | 49 | ||||
-rw-r--r-- | drivers/pci/msi-apic.c | 36 | ||||
-rw-r--r-- | drivers/pci/msi.c | 22 | ||||
-rw-r--r-- | drivers/pci/msi.h | 62 | ||||
-rw-r--r-- | include/linux/pci.h | 62 |
5 files changed, 116 insertions, 115 deletions
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c index bed4183a5e39..7aedc2ac8c28 100644 --- a/drivers/pci/msi-altix.c +++ b/drivers/pci/msi-altix.c | |||
@@ -26,7 +26,7 @@ struct sn_msi_info { | |||
26 | static struct sn_msi_info *sn_msi_info; | 26 | static struct sn_msi_info *sn_msi_info; |
27 | 27 | ||
28 | static void | 28 | static void |
29 | sn_msi_teardown(unsigned int vector) | 29 | sn_msi_teardown(unsigned int irq) |
30 | { | 30 | { |
31 | nasid_t nasid; | 31 | nasid_t nasid; |
32 | int widget; | 32 | int widget; |
@@ -36,7 +36,7 @@ sn_msi_teardown(unsigned int vector) | |||
36 | struct pcibus_bussoft *bussoft; | 36 | struct pcibus_bussoft *bussoft; |
37 | struct sn_pcibus_provider *provider; | 37 | struct sn_pcibus_provider *provider; |
38 | 38 | ||
39 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | 39 | sn_irq_info = sn_msi_info[irq].sn_irq_info; |
40 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | 40 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) |
41 | return; | 41 | return; |
42 | 42 | ||
@@ -45,9 +45,9 @@ sn_msi_teardown(unsigned int vector) | |||
45 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | 45 | provider = SN_PCIDEV_BUSPROVIDER(pdev); |
46 | 46 | ||
47 | (*provider->dma_unmap)(pdev, | 47 | (*provider->dma_unmap)(pdev, |
48 | sn_msi_info[vector].pci_addr, | 48 | sn_msi_info[irq].pci_addr, |
49 | PCI_DMA_FROMDEVICE); | 49 | PCI_DMA_FROMDEVICE); |
50 | sn_msi_info[vector].pci_addr = 0; | 50 | sn_msi_info[irq].pci_addr = 0; |
51 | 51 | ||
52 | bussoft = SN_PCIDEV_BUSSOFT(pdev); | 52 | bussoft = SN_PCIDEV_BUSSOFT(pdev); |
53 | nasid = NASID_GET(bussoft->bs_base); | 53 | nasid = NASID_GET(bussoft->bs_base); |
@@ -56,14 +56,13 @@ sn_msi_teardown(unsigned int vector) | |||
56 | SWIN_WIDGETNUM(bussoft->bs_base); | 56 | SWIN_WIDGETNUM(bussoft->bs_base); |
57 | 57 | ||
58 | sn_intr_free(nasid, widget, sn_irq_info); | 58 | sn_intr_free(nasid, widget, sn_irq_info); |
59 | sn_msi_info[vector].sn_irq_info = NULL; | 59 | sn_msi_info[irq].sn_irq_info = NULL; |
60 | 60 | ||
61 | return; | 61 | return; |
62 | } | 62 | } |
63 | 63 | ||
64 | int | 64 | int |
65 | sn_msi_setup(struct pci_dev *pdev, unsigned int vector, | 65 | sn_msi_setup(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) |
66 | u32 *addr_hi, u32 *addr_lo, u32 *data) | ||
67 | { | 66 | { |
68 | int widget; | 67 | int widget; |
69 | int status; | 68 | int status; |
@@ -93,7 +92,7 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int vector, | |||
93 | if (! sn_irq_info) | 92 | if (! sn_irq_info) |
94 | return -ENOMEM; | 93 | return -ENOMEM; |
95 | 94 | ||
96 | status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); | 95 | status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1); |
97 | if (status) { | 96 | if (status) { |
98 | kfree(sn_irq_info); | 97 | kfree(sn_irq_info); |
99 | return -ENOMEM; | 98 | return -ENOMEM; |
@@ -119,28 +118,27 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int vector, | |||
119 | return -ENOMEM; | 118 | return -ENOMEM; |
120 | } | 119 | } |
121 | 120 | ||
122 | sn_msi_info[vector].sn_irq_info = sn_irq_info; | 121 | sn_msi_info[irq].sn_irq_info = sn_irq_info; |
123 | sn_msi_info[vector].pci_addr = bus_addr; | 122 | sn_msi_info[irq].pci_addr = bus_addr; |
124 | 123 | ||
125 | *addr_hi = (u32)(bus_addr >> 32); | 124 | msg->address_hi = (u32)(bus_addr >> 32); |
126 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | 125 | msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); |
127 | 126 | ||
128 | /* | 127 | /* |
129 | * In the SN platform, bit 16 is a "send vector" bit which | 128 | * In the SN platform, bit 16 is a "send vector" bit which |
130 | * must be present in order to move the vector through the system. | 129 | * must be present in order to move the vector through the system. |
131 | */ | 130 | */ |
132 | *data = 0x100 + (unsigned int)vector; | 131 | msg->data = 0x100 + irq; |
133 | 132 | ||
134 | #ifdef CONFIG_SMP | 133 | #ifdef CONFIG_SMP |
135 | set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); | 134 | set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0); |
136 | #endif | 135 | #endif |
137 | 136 | ||
138 | return 0; | 137 | return 0; |
139 | } | 138 | } |
140 | 139 | ||
141 | static void | 140 | static void |
142 | sn_msi_target(unsigned int vector, unsigned int cpu, | 141 | sn_msi_target(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) |
143 | u32 *addr_hi, u32 *addr_lo) | ||
144 | { | 142 | { |
145 | int slice; | 143 | int slice; |
146 | nasid_t nasid; | 144 | nasid_t nasid; |
@@ -150,8 +148,10 @@ sn_msi_target(unsigned int vector, unsigned int cpu, | |||
150 | struct sn_irq_info *sn_irq_info; | 148 | struct sn_irq_info *sn_irq_info; |
151 | struct sn_irq_info *new_irq_info; | 149 | struct sn_irq_info *new_irq_info; |
152 | struct sn_pcibus_provider *provider; | 150 | struct sn_pcibus_provider *provider; |
151 | unsigned int cpu; | ||
153 | 152 | ||
154 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | 153 | cpu = first_cpu(cpu_mask); |
154 | sn_irq_info = sn_msi_info[irq].sn_irq_info; | ||
155 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | 155 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) |
156 | return; | 156 | return; |
157 | 157 | ||
@@ -163,15 +163,15 @@ sn_msi_target(unsigned int vector, unsigned int cpu, | |||
163 | pdev = sn_pdev->pdi_linux_pcidev; | 163 | pdev = sn_pdev->pdi_linux_pcidev; |
164 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | 164 | provider = SN_PCIDEV_BUSPROVIDER(pdev); |
165 | 165 | ||
166 | bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); | 166 | bus_addr = (u64)(msg->address_hi) << 32 | (u64)(msg->address_lo); |
167 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); | 167 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); |
168 | sn_msi_info[vector].pci_addr = 0; | 168 | sn_msi_info[irq].pci_addr = 0; |
169 | 169 | ||
170 | nasid = cpuid_to_nasid(cpu); | 170 | nasid = cpuid_to_nasid(cpu); |
171 | slice = cpuid_to_slice(cpu); | 171 | slice = cpuid_to_slice(cpu); |
172 | 172 | ||
173 | new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); | 173 | new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); |
174 | sn_msi_info[vector].sn_irq_info = new_irq_info; | 174 | sn_msi_info[irq].sn_irq_info = new_irq_info; |
175 | if (new_irq_info == NULL) | 175 | if (new_irq_info == NULL) |
176 | return; | 176 | return; |
177 | 177 | ||
@@ -184,12 +184,13 @@ sn_msi_target(unsigned int vector, unsigned int cpu, | |||
184 | sizeof(new_irq_info->irq_xtalkaddr), | 184 | sizeof(new_irq_info->irq_xtalkaddr), |
185 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | 185 | SN_DMA_MSI|SN_DMA_ADDR_XIO); |
186 | 186 | ||
187 | sn_msi_info[vector].pci_addr = bus_addr; | 187 | sn_msi_info[irq].pci_addr = bus_addr; |
188 | *addr_hi = (u32)(bus_addr >> 32); | 188 | msg->address_hi = (u32)(bus_addr >> 32); |
189 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | 189 | msg->address_lo = (u32)(bus_addr & 0x00000000ffffffff); |
190 | } | 190 | } |
191 | 191 | ||
192 | struct msi_ops sn_msi_ops = { | 192 | struct msi_ops sn_msi_ops = { |
193 | .needs_64bit_address = 1, | ||
193 | .setup = sn_msi_setup, | 194 | .setup = sn_msi_setup, |
194 | .teardown = sn_msi_teardown, | 195 | .teardown = sn_msi_teardown, |
195 | #ifdef CONFIG_SMP | 196 | #ifdef CONFIG_SMP |
@@ -201,7 +202,7 @@ int | |||
201 | sn_msi_init(void) | 202 | sn_msi_init(void) |
202 | { | 203 | { |
203 | sn_msi_info = | 204 | sn_msi_info = |
204 | kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); | 205 | kzalloc(sizeof(struct sn_msi_info) * NR_IRQS, GFP_KERNEL); |
205 | if (! sn_msi_info) | 206 | if (! sn_msi_info) |
206 | return -ENOMEM; | 207 | return -ENOMEM; |
207 | 208 | ||
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c index 5ed798b319c7..afc0ed13aa89 100644 --- a/drivers/pci/msi-apic.c +++ b/drivers/pci/msi-apic.c | |||
@@ -46,37 +46,36 @@ | |||
46 | 46 | ||
47 | 47 | ||
48 | static void | 48 | static void |
49 | msi_target_apic(unsigned int vector, | 49 | msi_target_apic(unsigned int irq, cpumask_t cpu_mask, struct msi_msg *msg) |
50 | unsigned int dest_cpu, | ||
51 | u32 *address_hi, /* in/out */ | ||
52 | u32 *address_lo) /* in/out */ | ||
53 | { | 50 | { |
54 | u32 addr = *address_lo; | 51 | u32 addr = msg->address_lo; |
55 | 52 | ||
56 | addr &= MSI_ADDR_DESTID_MASK; | 53 | addr &= MSI_ADDR_DESTID_MASK; |
57 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); | 54 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask))); |
58 | 55 | ||
59 | *address_lo = addr; | 56 | msg->address_lo = addr; |
60 | } | 57 | } |
61 | 58 | ||
62 | static int | 59 | static int |
63 | msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ | 60 | msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ |
64 | unsigned int vector, | 61 | unsigned int irq, |
65 | u32 *address_hi, | 62 | struct msi_msg *msg) |
66 | u32 *address_lo, | ||
67 | u32 *data) | ||
68 | { | 63 | { |
69 | unsigned long dest_phys_id; | 64 | unsigned long dest_phys_id; |
65 | unsigned int vector; | ||
70 | 66 | ||
71 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); | 67 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); |
68 | vector = irq; | ||
72 | 69 | ||
73 | *address_hi = 0; | 70 | msg->address_hi = 0; |
74 | *address_lo = MSI_ADDR_HEADER | | 71 | msg->address_lo = |
75 | MSI_ADDR_DESTMODE_PHYS | | 72 | MSI_ADDR_HEADER | |
76 | MSI_ADDR_REDIRECTION_CPU | | 73 | MSI_ADDR_DESTMODE_PHYS | |
77 | MSI_ADDR_DESTID_CPU(dest_phys_id); | 74 | MSI_ADDR_REDIRECTION_CPU | |
75 | MSI_ADDR_DESTID_CPU(dest_phys_id); | ||
78 | 76 | ||
79 | *data = MSI_DATA_TRIGGER_EDGE | | 77 | msg->data = |
78 | MSI_DATA_TRIGGER_EDGE | | ||
80 | MSI_DATA_LEVEL_ASSERT | | 79 | MSI_DATA_LEVEL_ASSERT | |
81 | MSI_DATA_DELIVERY_FIXED | | 80 | MSI_DATA_DELIVERY_FIXED | |
82 | MSI_DATA_VECTOR(vector); | 81 | MSI_DATA_VECTOR(vector); |
@@ -85,7 +84,7 @@ msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ | |||
85 | } | 84 | } |
86 | 85 | ||
87 | static void | 86 | static void |
88 | msi_teardown_apic(unsigned int vector) | 87 | msi_teardown_apic(unsigned int irq) |
89 | { | 88 | { |
90 | return; /* no-op */ | 89 | return; /* no-op */ |
91 | } | 90 | } |
@@ -95,6 +94,7 @@ msi_teardown_apic(unsigned int vector) | |||
95 | */ | 94 | */ |
96 | 95 | ||
97 | struct msi_ops msi_apic_ops = { | 96 | struct msi_ops msi_apic_ops = { |
97 | .needs_64bit_address = 0, | ||
98 | .setup = msi_setup_apic, | 98 | .setup = msi_setup_apic, |
99 | .teardown = msi_teardown_apic, | 99 | .teardown = msi_teardown_apic, |
100 | .target = msi_target_apic, | 100 | .target = msi_target_apic, |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index cca6cb3ccdac..6d9de026e141 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -165,19 +165,17 @@ static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | #ifdef CONFIG_SMP | 167 | #ifdef CONFIG_SMP |
168 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | 168 | static void set_msi_affinity(unsigned int irq, cpumask_t cpu_mask) |
169 | { | 169 | { |
170 | struct msi_desc *entry; | 170 | struct msi_desc *entry; |
171 | struct msi_msg msg; | 171 | struct msi_msg msg; |
172 | unsigned int irq = vector; | ||
173 | unsigned int dest_cpu = first_cpu(cpu_mask); | ||
174 | 172 | ||
175 | entry = (struct msi_desc *)msi_desc[vector]; | 173 | entry = msi_desc[irq]; |
176 | if (!entry || !entry->dev) | 174 | if (!entry || !entry->dev) |
177 | return; | 175 | return; |
178 | 176 | ||
179 | read_msi_msg(entry, &msg); | 177 | read_msi_msg(entry, &msg); |
180 | msi_ops->target(vector, dest_cpu, &msg.address_hi, &msg.address_lo); | 178 | msi_ops->target(irq, cpu_mask, &msg); |
181 | write_msi_msg(entry, &msg); | 179 | write_msi_msg(entry, &msg); |
182 | set_native_irq_info(irq, cpu_mask); | 180 | set_native_irq_info(irq, cpu_mask); |
183 | } | 181 | } |
@@ -701,14 +699,14 @@ static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
701 | { | 699 | { |
702 | int status; | 700 | int status; |
703 | struct msi_msg msg; | 701 | struct msi_msg msg; |
704 | int pos, vector = dev->irq; | 702 | int pos; |
705 | u16 control; | 703 | u16 control; |
706 | 704 | ||
707 | pos = entry->msi_attrib.pos; | 705 | pos = entry->msi_attrib.pos; |
708 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 706 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
709 | 707 | ||
710 | /* Configure MSI capability structure */ | 708 | /* Configure MSI capability structure */ |
711 | status = msi_ops->setup(dev, vector, &msg.address_hi, &msg.address_lo, &msg.data); | 709 | status = msi_ops->setup(dev, dev->irq, &msg); |
712 | if (status < 0) | 710 | if (status < 0) |
713 | return status; | 711 | return status; |
714 | 712 | ||
@@ -863,10 +861,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
863 | /* Replace with MSI-X handler */ | 861 | /* Replace with MSI-X handler */ |
864 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); | 862 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); |
865 | /* Configure MSI-X capability structure */ | 863 | /* Configure MSI-X capability structure */ |
866 | status = msi_ops->setup(dev, vector, | 864 | status = msi_ops->setup(dev, vector, &msg); |
867 | &msg.address_hi, | ||
868 | &msg.address_lo, | ||
869 | &msg.data); | ||
870 | if (status < 0) | 865 | if (status < 0) |
871 | break; | 866 | break; |
872 | 867 | ||
@@ -928,6 +923,7 @@ int pci_msi_supported(struct pci_dev * dev) | |||
928 | int pci_enable_msi(struct pci_dev* dev) | 923 | int pci_enable_msi(struct pci_dev* dev) |
929 | { | 924 | { |
930 | int pos, temp, status; | 925 | int pos, temp, status; |
926 | u16 control; | ||
931 | 927 | ||
932 | if (pci_msi_supported(dev) < 0) | 928 | if (pci_msi_supported(dev) < 0) |
933 | return -EINVAL; | 929 | return -EINVAL; |
@@ -942,6 +938,10 @@ int pci_enable_msi(struct pci_dev* dev) | |||
942 | if (!pos) | 938 | if (!pos) |
943 | return -EINVAL; | 939 | return -EINVAL; |
944 | 940 | ||
941 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
942 | if (!is_64bit_address(control) && msi_ops->needs_64bit_address) | ||
943 | return -EINVAL; | ||
944 | |||
945 | WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSI)); | 945 | WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSI)); |
946 | 946 | ||
947 | /* Check whether driver already requested for MSI-X vectors */ | 947 | /* Check whether driver already requested for MSI-X vectors */ |
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 62f61b61d2c9..3519eca50d8a 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h | |||
@@ -6,68 +6,6 @@ | |||
6 | #ifndef MSI_H | 6 | #ifndef MSI_H |
7 | #define MSI_H | 7 | #define MSI_H |
8 | 8 | ||
9 | /* | ||
10 | * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) | ||
11 | * to abstract platform-specific tasks relating to MSI address generation | ||
12 | * and resource management. | ||
13 | */ | ||
14 | struct msi_ops { | ||
15 | /** | ||
16 | * setup - generate an MSI bus address and data for a given vector | ||
17 | * @pdev: PCI device context (in) | ||
18 | * @vector: vector allocated by the msi core (in) | ||
19 | * @addr_hi: upper 32 bits of PCI bus MSI address (out) | ||
20 | * @addr_lo: lower 32 bits of PCI bus MSI address (out) | ||
21 | * @data: MSI data payload (out) | ||
22 | * | ||
23 | * Description: The setup op is used to generate a PCI bus addres and | ||
24 | * data which the msi core will program into the card MSI capability | ||
25 | * registers. The setup routine is responsible for picking an initial | ||
26 | * cpu to target the MSI at. The setup routine is responsible for | ||
27 | * examining pdev to determine the MSI capabilities of the card and | ||
28 | * generating a suitable address/data. The setup routine is | ||
29 | * responsible for allocating and tracking any system resources it | ||
30 | * needs to route the MSI to the cpu it picks, and for associating | ||
31 | * those resources with the passed in vector. | ||
32 | * | ||
33 | * Returns 0 if the MSI address/data was successfully setup. | ||
34 | **/ | ||
35 | |||
36 | int (*setup) (struct pci_dev *pdev, unsigned int vector, | ||
37 | u32 *addr_hi, u32 *addr_lo, u32 *data); | ||
38 | |||
39 | /** | ||
40 | * teardown - release resources allocated by setup | ||
41 | * @vector: vector context for resources (in) | ||
42 | * | ||
43 | * Description: The teardown op is used to release any resources | ||
44 | * that were allocated in the setup routine associated with the passed | ||
45 | * in vector. | ||
46 | **/ | ||
47 | |||
48 | void (*teardown) (unsigned int vector); | ||
49 | |||
50 | /** | ||
51 | * target - retarget an MSI at a different cpu | ||
52 | * @vector: vector context for resources (in) | ||
53 | * @cpu: new cpu to direct vector at (in) | ||
54 | * @addr_hi: new value of PCI bus upper 32 bits (in/out) | ||
55 | * @addr_lo: new value of PCI bus lower 32 bits (in/out) | ||
56 | * | ||
57 | * Description: The target op is used to redirect an MSI vector | ||
58 | * at a different cpu. addr_hi/addr_lo coming in are the existing | ||
59 | * values that the MSI core has programmed into the card. The | ||
60 | * target code is responsible for freeing any resources (if any) | ||
61 | * associated with the old address, and generating a new PCI bus | ||
62 | * addr_hi/addr_lo that will redirect the vector at the indicated cpu. | ||
63 | **/ | ||
64 | |||
65 | void (*target) (unsigned int vector, unsigned int cpu, | ||
66 | u32 *addr_hi, u32 *addr_lo); | ||
67 | }; | ||
68 | |||
69 | extern int msi_register(struct msi_ops *ops); | ||
70 | |||
71 | #include <asm/msi.h> | 9 | #include <asm/msi.h> |
72 | 10 | ||
73 | /* | 11 | /* |
diff --git a/include/linux/pci.h b/include/linux/pci.h index b9bb6c46e056..2aabe90f1cd2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -617,6 +617,68 @@ extern int pci_enable_msix(struct pci_dev* dev, | |||
617 | struct msix_entry *entries, int nvec); | 617 | struct msix_entry *entries, int nvec); |
618 | extern void pci_disable_msix(struct pci_dev *dev); | 618 | extern void pci_disable_msix(struct pci_dev *dev); |
619 | extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); | 619 | 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 | |||
620 | #endif | 682 | #endif |
621 | 683 | ||
622 | extern void pci_block_user_cfg_access(struct pci_dev *dev); | 684 | extern void pci_block_user_cfg_access(struct pci_dev *dev); |