aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-10-04 05:16:34 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-04 10:55:27 -0400
commit38bc0361303535c86f6b67b151a541728d7bdae6 (patch)
tree6a3939b1f7aea3b00fc4ecd72646fd8442c95766 /drivers/pci
parent0366f8f7137deb072991e4c50769c6da31f8940c (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>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/msi-altix.c49
-rw-r--r--drivers/pci/msi-apic.c36
-rw-r--r--drivers/pci/msi.c22
-rw-r--r--drivers/pci/msi.h62
4 files changed, 54 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 {
26static struct sn_msi_info *sn_msi_info; 26static struct sn_msi_info *sn_msi_info;
27 27
28static void 28static void
29sn_msi_teardown(unsigned int vector) 29sn_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
64int 64int
65sn_msi_setup(struct pci_dev *pdev, unsigned int vector, 65sn_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
141static void 140static void
142sn_msi_target(unsigned int vector, unsigned int cpu, 141sn_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
192struct msi_ops sn_msi_ops = { 192struct 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
201sn_msi_init(void) 202sn_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
48static void 48static void
49msi_target_apic(unsigned int vector, 49msi_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
62static int 59static int
63msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ 60msi_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
87static void 86static void
88msi_teardown_apic(unsigned int vector) 87msi_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
97struct msi_ops msi_apic_ops = { 96struct 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
168static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) 168static 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)
928int pci_enable_msi(struct pci_dev* dev) 923int 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 */
14struct 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
69extern int msi_register(struct msi_ops *ops);
70
71#include <asm/msi.h> 9#include <asm/msi.h>
72 10
73/* 11/*