diff options
author | Mark Maule <maule@sgi.com> | 2006-04-14 17:03:54 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-21 14:59:59 -0400 |
commit | 83821d3f558dc651e555d62182ed0c95651f41a6 (patch) | |
tree | 60f3ae42e9b729a5061b8e4e2dce522b03e54810 /arch/ia64/sn/kernel/irq.c | |
parent | 10083072bfabc40bc47306e512c158c57cf55c2e (diff) |
[PATCH] PCI: altix: msi support
MSI callouts for altix. Involves a fair amount of code reorg in sn irq.c
code as well as adding some extensions to the altix PCI provider abstaction.
Signed-off-by: Mark Maule <maule@sgi.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'arch/ia64/sn/kernel/irq.c')
-rw-r--r-- | arch/ia64/sn/kernel/irq.c | 135 |
1 files changed, 77 insertions, 58 deletions
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index db187f5cdae1..dc8e2b696713 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c | |||
@@ -26,11 +26,11 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info); | |||
26 | 26 | ||
27 | int sn_force_interrupt_flag = 1; | 27 | int sn_force_interrupt_flag = 1; |
28 | extern int sn_ioif_inited; | 28 | extern int sn_ioif_inited; |
29 | static struct list_head **sn_irq_lh; | 29 | struct list_head **sn_irq_lh; |
30 | static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ | 30 | static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ |
31 | 31 | ||
32 | static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, | 32 | u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, |
33 | u64 sn_irq_info, | 33 | struct sn_irq_info *sn_irq_info, |
34 | int req_irq, nasid_t req_nasid, | 34 | int req_irq, nasid_t req_nasid, |
35 | int req_slice) | 35 | int req_slice) |
36 | { | 36 | { |
@@ -40,12 +40,13 @@ static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, | |||
40 | 40 | ||
41 | SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, | 41 | SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, |
42 | (u64) SAL_INTR_ALLOC, (u64) local_nasid, | 42 | (u64) SAL_INTR_ALLOC, (u64) local_nasid, |
43 | (u64) local_widget, (u64) sn_irq_info, (u64) req_irq, | 43 | (u64) local_widget, __pa(sn_irq_info), (u64) req_irq, |
44 | (u64) req_nasid, (u64) req_slice); | 44 | (u64) req_nasid, (u64) req_slice); |
45 | |||
45 | return ret_stuff.status; | 46 | return ret_stuff.status; |
46 | } | 47 | } |
47 | 48 | ||
48 | static inline void sn_intr_free(nasid_t local_nasid, int local_widget, | 49 | void sn_intr_free(nasid_t local_nasid, int local_widget, |
49 | struct sn_irq_info *sn_irq_info) | 50 | struct sn_irq_info *sn_irq_info) |
50 | { | 51 | { |
51 | struct ia64_sal_retval ret_stuff; | 52 | struct ia64_sal_retval ret_stuff; |
@@ -112,73 +113,91 @@ static void sn_end_irq(unsigned int irq) | |||
112 | 113 | ||
113 | static void sn_irq_info_free(struct rcu_head *head); | 114 | static void sn_irq_info_free(struct rcu_head *head); |
114 | 115 | ||
115 | static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) | 116 | struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, |
117 | nasid_t nasid, int slice) | ||
116 | { | 118 | { |
117 | struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; | 119 | int vector; |
118 | int cpuid, cpuphys; | 120 | int cpuphys; |
121 | int64_t bridge; | ||
122 | int local_widget, status; | ||
123 | nasid_t local_nasid; | ||
124 | struct sn_irq_info *new_irq_info; | ||
125 | struct sn_pcibus_provider *pci_provider; | ||
119 | 126 | ||
120 | cpuid = first_cpu(mask); | 127 | new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); |
121 | cpuphys = cpu_physical_id(cpuid); | 128 | if (new_irq_info == NULL) |
129 | return NULL; | ||
122 | 130 | ||
123 | list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, | 131 | memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); |
124 | sn_irq_lh[irq], list) { | ||
125 | u64 bridge; | ||
126 | int local_widget, status; | ||
127 | nasid_t local_nasid; | ||
128 | struct sn_irq_info *new_irq_info; | ||
129 | struct sn_pcibus_provider *pci_provider; | ||
130 | |||
131 | new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); | ||
132 | if (new_irq_info == NULL) | ||
133 | break; | ||
134 | memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); | ||
135 | |||
136 | bridge = (u64) new_irq_info->irq_bridge; | ||
137 | if (!bridge) { | ||
138 | kfree(new_irq_info); | ||
139 | break; /* irq is not a device interrupt */ | ||
140 | } | ||
141 | 132 | ||
142 | local_nasid = NASID_GET(bridge); | 133 | bridge = (u64) new_irq_info->irq_bridge; |
134 | if (!bridge) { | ||
135 | kfree(new_irq_info); | ||
136 | return NULL; /* irq is not a device interrupt */ | ||
137 | } | ||
143 | 138 | ||
144 | if (local_nasid & 1) | 139 | local_nasid = NASID_GET(bridge); |
145 | local_widget = TIO_SWIN_WIDGETNUM(bridge); | ||
146 | else | ||
147 | local_widget = SWIN_WIDGETNUM(bridge); | ||
148 | 140 | ||
149 | /* Free the old PROM new_irq_info structure */ | 141 | if (local_nasid & 1) |
150 | sn_intr_free(local_nasid, local_widget, new_irq_info); | 142 | local_widget = TIO_SWIN_WIDGETNUM(bridge); |
151 | /* Update kernels new_irq_info with new target info */ | 143 | else |
152 | unregister_intr_pda(new_irq_info); | 144 | local_widget = SWIN_WIDGETNUM(bridge); |
153 | 145 | ||
154 | /* allocate a new PROM new_irq_info struct */ | 146 | vector = sn_irq_info->irq_irq; |
155 | status = sn_intr_alloc(local_nasid, local_widget, | 147 | /* Free the old PROM new_irq_info structure */ |
156 | __pa(new_irq_info), irq, | 148 | sn_intr_free(local_nasid, local_widget, new_irq_info); |
157 | cpuid_to_nasid(cpuid), | 149 | /* Update kernels new_irq_info with new target info */ |
158 | cpuid_to_slice(cpuid)); | 150 | unregister_intr_pda(new_irq_info); |
159 | 151 | ||
160 | /* SAL call failed */ | 152 | /* allocate a new PROM new_irq_info struct */ |
161 | if (status) { | 153 | status = sn_intr_alloc(local_nasid, local_widget, |
162 | kfree(new_irq_info); | 154 | new_irq_info, vector, |
163 | break; | 155 | nasid, slice); |
164 | } | 156 | |
157 | /* SAL call failed */ | ||
158 | if (status) { | ||
159 | kfree(new_irq_info); | ||
160 | return NULL; | ||
161 | } | ||
165 | 162 | ||
166 | new_irq_info->irq_cpuid = cpuid; | 163 | cpuphys = nasid_slice_to_cpuid(nasid, slice); |
167 | register_intr_pda(new_irq_info); | 164 | new_irq_info->irq_cpuid = cpuphys; |
165 | register_intr_pda(new_irq_info); | ||
168 | 166 | ||
169 | pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; | 167 | pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; |
170 | if (pci_provider && pci_provider->target_interrupt) | 168 | |
171 | (pci_provider->target_interrupt)(new_irq_info); | 169 | /* |
170 | * If this represents a line interrupt, target it. If it's | ||
171 | * an msi (irq_int_bit < 0), it's already targeted. | ||
172 | */ | ||
173 | if (new_irq_info->irq_int_bit >= 0 && | ||
174 | pci_provider && pci_provider->target_interrupt) | ||
175 | (pci_provider->target_interrupt)(new_irq_info); | ||
172 | 176 | ||
173 | spin_lock(&sn_irq_info_lock); | 177 | spin_lock(&sn_irq_info_lock); |
174 | list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); | 178 | list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); |
175 | spin_unlock(&sn_irq_info_lock); | 179 | spin_unlock(&sn_irq_info_lock); |
176 | call_rcu(&sn_irq_info->rcu, sn_irq_info_free); | 180 | call_rcu(&sn_irq_info->rcu, sn_irq_info_free); |
177 | 181 | ||
178 | #ifdef CONFIG_SMP | 182 | #ifdef CONFIG_SMP |
179 | set_irq_affinity_info((irq & 0xff), cpuphys, 0); | 183 | set_irq_affinity_info((vector & 0xff), cpuphys, 0); |
180 | #endif | 184 | #endif |
181 | } | 185 | |
186 | return new_irq_info; | ||
187 | } | ||
188 | |||
189 | static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) | ||
190 | { | ||
191 | struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; | ||
192 | nasid_t nasid; | ||
193 | int slice; | ||
194 | |||
195 | nasid = cpuid_to_nasid(first_cpu(mask)); | ||
196 | slice = cpuid_to_slice(first_cpu(mask)); | ||
197 | |||
198 | list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, | ||
199 | sn_irq_lh[irq], list) | ||
200 | (void)sn_retarget_vector(sn_irq_info, nasid, slice); | ||
182 | } | 201 | } |
183 | 202 | ||
184 | struct hw_interrupt_type irq_type_sn = { | 203 | struct hw_interrupt_type irq_type_sn = { |