2 * Platform dependent support for SGI SN
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
8 * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
11 #include <linux/irq.h>
12 #include <asm/sn/intr.h>
13 #include <asm/sn/addrs.h>
14 #include <asm/sn/arch.h>
15 #include "xtalk/xwidgetdev.h"
16 #include "pci/pcibus_provider_defs.h"
17 #include "pci/pcidev.h"
18 #include "pci/pcibr_provider.h"
19 #include <asm/sn/shub_mmr.h>
20 #include <asm/sn/sn_sal.h>
22 static void force_interrupt(int irq
);
23 static void register_intr_pda(struct sn_irq_info
*sn_irq_info
);
24 static void unregister_intr_pda(struct sn_irq_info
*sn_irq_info
);
26 extern int sn_force_interrupt_flag
;
27 extern int sn_ioif_inited
;
28 struct sn_irq_info
**sn_irq
;
30 static inline uint64_t sn_intr_alloc(nasid_t local_nasid
, int local_widget
,
32 int req_irq
, nasid_t req_nasid
,
35 struct ia64_sal_retval ret_stuff
;
39 SAL_CALL_NOLOCK(ret_stuff
, (u64
) SN_SAL_IOIF_INTERRUPT
,
40 (u64
) SAL_INTR_ALLOC
, (u64
) local_nasid
,
41 (u64
) local_widget
, (u64
) sn_irq_info
, (u64
) req_irq
,
42 (u64
) req_nasid
, (u64
) req_slice
);
43 return ret_stuff
.status
;
46 static inline void sn_intr_free(nasid_t local_nasid
, int local_widget
,
47 struct sn_irq_info
*sn_irq_info
)
49 struct ia64_sal_retval ret_stuff
;
53 SAL_CALL_NOLOCK(ret_stuff
, (u64
) SN_SAL_IOIF_INTERRUPT
,
54 (u64
) SAL_INTR_FREE
, (u64
) local_nasid
,
55 (u64
) local_widget
, (u64
) sn_irq_info
->irq_irq
,
56 (u64
) sn_irq_info
->irq_cookie
, 0, 0);
59 static unsigned int sn_startup_irq(unsigned int irq
)
64 static void sn_shutdown_irq(unsigned int irq
)
68 static void sn_disable_irq(unsigned int irq
)
72 static void sn_enable_irq(unsigned int irq
)
76 static void sn_ack_irq(unsigned int irq
)
78 uint64_t event_occurred
, mask
= 0;
84 HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid
, SH_EVENT_OCCURRED
));
85 if (event_occurred
& SH_EVENT_OCCURRED_UART_INT_MASK
) {
86 mask
|= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT
);
88 if (event_occurred
& SH_EVENT_OCCURRED_IPI_INT_MASK
) {
89 mask
|= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT
);
91 if (event_occurred
& SH_EVENT_OCCURRED_II_INT0_MASK
) {
92 mask
|= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT
);
94 if (event_occurred
& SH_EVENT_OCCURRED_II_INT1_MASK
) {
95 mask
|= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT
);
97 HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid
, SH_EVENT_OCCURRED_ALIAS
),
99 __set_bit(irq
, (volatile void *)pda
->sn_in_service_ivecs
);
104 static void sn_end_irq(unsigned int irq
)
108 uint64_t event_occurred
;
111 if (ivec
== SGI_UART_VECTOR
) {
113 event_occurred
= HUB_L((uint64_t *) GLOBAL_MMR_ADDR
114 (nasid
, SH_EVENT_OCCURRED
));
115 /* If the UART bit is set here, we may have received an
116 * interrupt from the UART that the driver missed. To
117 * make sure, we IPI ourselves to force us to look again.
119 if (event_occurred
& SH_EVENT_OCCURRED_UART_INT_MASK
) {
120 platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR
,
124 __clear_bit(ivec
, (volatile void *)pda
->sn_in_service_ivecs
);
125 if (sn_force_interrupt_flag
)
126 force_interrupt(irq
);
129 static void sn_set_affinity_irq(unsigned int irq
, cpumask_t mask
)
131 struct sn_irq_info
*sn_irq_info
= sn_irq
[irq
];
132 struct sn_irq_info
*tmp_sn_irq_info
;
134 nasid_t t_nasid
; /* nasid to target */
135 int t_slice
; /* slice to target */
137 /* allocate a temp sn_irq_info struct to get new target info */
138 tmp_sn_irq_info
= kmalloc(sizeof(*tmp_sn_irq_info
), GFP_KERNEL
);
139 if (!tmp_sn_irq_info
)
142 cpuid
= first_cpu(mask
);
143 cpuphys
= cpu_physical_id(cpuid
);
144 t_nasid
= cpuid_to_nasid(cpuid
);
145 t_slice
= cpuid_to_slice(cpuid
);
147 while (sn_irq_info
) {
150 uint64_t bridge
= (uint64_t) sn_irq_info
->irq_bridge
;
151 nasid_t local_nasid
= NASID_GET(bridge
);
154 break; /* irq is not a device interrupt */
157 local_widget
= TIO_SWIN_WIDGETNUM(bridge
);
159 local_widget
= SWIN_WIDGETNUM(bridge
);
161 /* Free the old PROM sn_irq_info structure */
162 sn_intr_free(local_nasid
, local_widget
, sn_irq_info
);
164 /* allocate a new PROM sn_irq_info struct */
165 status
= sn_intr_alloc(local_nasid
, local_widget
,
166 __pa(tmp_sn_irq_info
), irq
, t_nasid
,
170 /* Update kernels sn_irq_info with new target info */
171 unregister_intr_pda(sn_irq_info
);
172 sn_irq_info
->irq_cpuid
= cpuid
;
173 sn_irq_info
->irq_nasid
= t_nasid
;
174 sn_irq_info
->irq_slice
= t_slice
;
175 sn_irq_info
->irq_xtalkaddr
=
176 tmp_sn_irq_info
->irq_xtalkaddr
;
177 sn_irq_info
->irq_cookie
= tmp_sn_irq_info
->irq_cookie
;
178 register_intr_pda(sn_irq_info
);
180 if (IS_PCI_BRIDGE_ASIC(sn_irq_info
->irq_bridge_type
)) {
181 pcibr_change_devices_irq(sn_irq_info
);
184 sn_irq_info
= sn_irq_info
->irq_next
;
187 set_irq_affinity_info((irq
& 0xff), cpuphys
, 0);
190 break; /* snp_affinity failed the intr_alloc */
193 kfree(tmp_sn_irq_info
);
196 struct hw_interrupt_type irq_type_sn
= {
207 unsigned int sn_local_vector_to_irq(u8 vector
)
209 return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector
));
212 void sn_irq_init(void)
215 irq_desc_t
*base_desc
= irq_desc
;
217 for (i
= 0; i
< NR_IRQS
; i
++) {
218 if (base_desc
[i
].handler
== &no_irq_type
) {
219 base_desc
[i
].handler
= &irq_type_sn
;
224 static void register_intr_pda(struct sn_irq_info
*sn_irq_info
)
226 int irq
= sn_irq_info
->irq_irq
;
227 int cpu
= sn_irq_info
->irq_cpuid
;
229 if (pdacpu(cpu
)->sn_last_irq
< irq
) {
230 pdacpu(cpu
)->sn_last_irq
= irq
;
233 if (pdacpu(cpu
)->sn_first_irq
== 0 || pdacpu(cpu
)->sn_first_irq
> irq
) {
234 pdacpu(cpu
)->sn_first_irq
= irq
;
238 static void unregister_intr_pda(struct sn_irq_info
*sn_irq_info
)
240 int irq
= sn_irq_info
->irq_irq
;
241 int cpu
= sn_irq_info
->irq_cpuid
;
242 struct sn_irq_info
*tmp_irq_info
;
245 if (pdacpu(cpu
)->sn_last_irq
== irq
) {
247 for (i
= pdacpu(cpu
)->sn_last_irq
- 1; i
; i
--) {
248 tmp_irq_info
= sn_irq
[i
];
249 while (tmp_irq_info
) {
250 if (tmp_irq_info
->irq_cpuid
== cpu
) {
254 tmp_irq_info
= tmp_irq_info
->irq_next
;
260 pdacpu(cpu
)->sn_last_irq
= i
;
263 if (pdacpu(cpu
)->sn_first_irq
== irq
) {
265 for (i
= pdacpu(cpu
)->sn_first_irq
+ 1; i
< NR_IRQS
; i
++) {
266 tmp_irq_info
= sn_irq
[i
];
267 while (tmp_irq_info
) {
268 if (tmp_irq_info
->irq_cpuid
== cpu
) {
272 tmp_irq_info
= tmp_irq_info
->irq_next
;
278 pdacpu(cpu
)->sn_first_irq
= ((i
== NR_IRQS
) ? 0 : i
);
282 struct sn_irq_info
*sn_irq_alloc(nasid_t local_nasid
, int local_widget
, int irq
,
283 nasid_t nasid
, int slice
)
285 struct sn_irq_info
*sn_irq_info
;
288 sn_irq_info
= kmalloc(sizeof(*sn_irq_info
), GFP_KERNEL
);
289 if (sn_irq_info
== NULL
)
292 memset(sn_irq_info
, 0x0, sizeof(*sn_irq_info
));
295 sn_intr_alloc(local_nasid
, local_widget
, __pa(sn_irq_info
), irq
,
306 void sn_irq_free(struct sn_irq_info
*sn_irq_info
)
308 uint64_t bridge
= (uint64_t) sn_irq_info
->irq_bridge
;
309 nasid_t local_nasid
= NASID_GET(bridge
);
312 if (local_nasid
& 1) /* tio check */
313 local_widget
= TIO_SWIN_WIDGETNUM(bridge
);
315 local_widget
= SWIN_WIDGETNUM(bridge
);
317 sn_intr_free(local_nasid
, local_widget
, sn_irq_info
);
322 void sn_irq_fixup(struct pci_dev
*pci_dev
, struct sn_irq_info
*sn_irq_info
)
324 nasid_t nasid
= sn_irq_info
->irq_nasid
;
325 int slice
= sn_irq_info
->irq_slice
;
326 int cpu
= nasid_slice_to_cpuid(nasid
, slice
);
328 sn_irq_info
->irq_cpuid
= cpu
;
329 sn_irq_info
->irq_pciioinfo
= SN_PCIDEV_INFO(pci_dev
);
331 /* link it into the sn_irq[irq] list */
332 sn_irq_info
->irq_next
= sn_irq
[sn_irq_info
->irq_irq
];
333 sn_irq
[sn_irq_info
->irq_irq
] = sn_irq_info
;
335 (void)register_intr_pda(sn_irq_info
);
338 static void force_interrupt(int irq
)
340 struct sn_irq_info
*sn_irq_info
;
344 sn_irq_info
= sn_irq
[irq
];
345 while (sn_irq_info
) {
346 if (IS_PCI_BRIDGE_ASIC(sn_irq_info
->irq_bridge_type
) &&
347 (sn_irq_info
->irq_bridge
!= NULL
)) {
348 pcibr_force_interrupt(sn_irq_info
);
350 sn_irq_info
= sn_irq_info
->irq_next
;
355 * Check for lost interrupts. If the PIC int_status reg. says that
356 * an interrupt has been sent, but not handled, and the interrupt
357 * is not pending in either the cpu irr regs or in the soft irr regs,
358 * and the interrupt is not in service, then the interrupt may have
359 * been lost. Force an interrupt on that pin. It is possible that
360 * the interrupt is in flight, so we may generate a spurious interrupt,
361 * but we should never miss a real lost interrupt.
363 static void sn_check_intr(int irq
, struct sn_irq_info
*sn_irq_info
)
369 struct pcidev_info
*pcidev_info
;
370 struct pcibus_info
*pcibus_info
;
372 pcidev_info
= (struct pcidev_info
*)sn_irq_info
->irq_pciioinfo
;
377 (struct pcibus_info
*)pcidev_info
->pdi_host_pcidev_info
->
379 regval
= pcireg_intr_status_get(pcibus_info
);
381 irr_reg_num
= irq_to_vector(irq
) / 64;
382 irr_bit
= irq_to_vector(irq
) % 64;
383 switch (irr_reg_num
) {
385 irr_reg
= ia64_getreg(_IA64_REG_CR_IRR0
);
388 irr_reg
= ia64_getreg(_IA64_REG_CR_IRR1
);
391 irr_reg
= ia64_getreg(_IA64_REG_CR_IRR2
);
394 irr_reg
= ia64_getreg(_IA64_REG_CR_IRR3
);
397 if (!test_bit(irr_bit
, &irr_reg
)) {
398 if (!test_bit(irq
, pda
->sn_soft_irr
)) {
399 if (!test_bit(irq
, pda
->sn_in_service_ivecs
)) {
401 if (sn_irq_info
->irq_int_bit
& regval
&
402 sn_irq_info
->irq_last_intr
) {
405 irq_int_bit
& regval
);
406 pcibr_force_interrupt(sn_irq_info
);
411 sn_irq_info
->irq_last_intr
= regval
;
414 void sn_lb_int_war_check(void)
418 if (!sn_ioif_inited
|| pda
->sn_first_irq
== 0)
420 for (i
= pda
->sn_first_irq
; i
<= pda
->sn_last_irq
; i
++) {
421 struct sn_irq_info
*sn_irq_info
= sn_irq
[i
];
422 while (sn_irq_info
) {
423 /* Only call for PCI bridges that are fully initialized. */
424 if (IS_PCI_BRIDGE_ASIC(sn_irq_info
->irq_bridge_type
) &&
425 (sn_irq_info
->irq_bridge
!= NULL
)) {
426 sn_check_intr(i
, sn_irq_info
);
428 sn_irq_info
= sn_irq_info
->irq_next
;