aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/kernel/irq.c
diff options
context:
space:
mode:
authorMark Maule <maule@sgi.com>2006-04-14 17:03:54 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 14:59:59 -0400
commit83821d3f558dc651e555d62182ed0c95651f41a6 (patch)
tree60f3ae42e9b729a5061b8e4e2dce522b03e54810 /arch/ia64/sn/kernel/irq.c
parent10083072bfabc40bc47306e512c158c57cf55c2e (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.c135
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
27int sn_force_interrupt_flag = 1; 27int sn_force_interrupt_flag = 1;
28extern int sn_ioif_inited; 28extern int sn_ioif_inited;
29static struct list_head **sn_irq_lh; 29struct list_head **sn_irq_lh;
30static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ 30static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
31 31
32static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, 32u64 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
48static inline void sn_intr_free(nasid_t local_nasid, int local_widget, 49void 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
113static void sn_irq_info_free(struct rcu_head *head); 114static void sn_irq_info_free(struct rcu_head *head);
114 115
115static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) 116struct 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
189static 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
184struct hw_interrupt_type irq_type_sn = { 203struct hw_interrupt_type irq_type_sn = {