1/*
2 * Platform dependent support for SGI SN1
3 *
4 * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of version 2 of the GNU General Public License
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 *
14 * Further, this software is distributed without any warranty that it is
15 * free of the rightful claim of any third person regarding infringement
16 * or the like.  Any license provided herein, whether implied or
17 * otherwise, applies only to this software file.  Patent licenses, if
18 * any, provided herein do not apply to combinations of this program with
19 * other software, or any other product whatsoever.
20 *
21 * You should have received a copy of the GNU General Public
22 * License along with this program; if not, write the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
24 *
25 * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
26 * Mountain View, CA  94043, or:
27 *
28 * http://www.sgi.com
29 *
30 * For further information regarding this notice, see:
31 *
32 * http://oss.sgi.com/projects/GenInfo/NoticeExplan
33 */
34
35#include <linux/config.h>
36#include <linux/init.h>
37#include <linux/sched.h>
38#include <asm/current.h>
39#include <linux/irq.h>
40#include <linux/interrupt.h>
41#include <asm/page.h>
42#include <asm/pgtable.h>
43#include <asm/sn/sgi.h>
44#include <asm/sn/iograph.h>
45#include <asm/sn/invent.h>
46#include <linux/devfs_fs_kernel.h>
47#include <asm/sn/hcl.h>
48#include <asm/sn/types.h>
49#include <asm/sn/pci/bridge.h>
50#include <asm/sn/pci/pciio.h>
51#include <asm/sn/pci/pciio_private.h>
52#ifdef ajmtestintr
53#include <asm/sn/pci/pcibr.h>
54#include <asm/sn/pci/pcibr_private.h>
55#endif /* ajmtestintr */
56#include <asm/sn/sn_cpuid.h>
57#include <asm/sn/io.h>
58#include <asm/sn/intr.h>
59#include <asm/sn/addrs.h>
60#include <asm/sn/driver.h>
61#include <asm/sn/arch.h>
62
63int irq_to_bit_pos(int irq);
64
65
66
67static unsigned int
68sn_startup_irq(unsigned int irq)
69{
70        return(0);
71}
72
73static void
74sn_shutdown_irq(unsigned int irq)
75{
76}
77
78static void
79sn_disable_irq(unsigned int irq)
80{
81}
82
83static void
84sn_enable_irq(unsigned int irq)
85{
86}
87
88static void
89sn_ack_irq(unsigned int irq)
90{
91#ifdef CONFIG_IA64_SGI_SN1
92	int bit = -1;
93	unsigned long long intpend_val;
94	int subnode;
95#endif
96#ifdef CONFIG_IA64_SGI_SN2
97	unsigned long event_occurred, mask = 0;
98#endif
99	int nasid;
100
101	irq = irq & 0xff;
102	nasid = smp_physical_node_id();
103#ifdef CONFIG_IA64_SGI_SN1
104	subnode = cpuid_to_subnode(smp_processor_id());
105	if (irq == SGI_UART_IRQ) {
106		intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0);
107		if (intpend_val & (1L<<GFX_INTR_A) ) {
108			bit = GFX_INTR_A;
109			REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
110		}
111		if ( intpend_val & (1L<<GFX_INTR_B) ) {
112			bit = GFX_INTR_B;
113			REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
114		}
115		if (intpend_val & (1L<<PG_MIG_INTR) ) {
116			bit = PG_MIG_INTR;
117			REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
118		}
119		if (intpend_val & (1L<<CC_PEND_A)) {
120			bit = CC_PEND_A;
121			REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
122		}
123		if (intpend_val & (1L<<CC_PEND_B)) {
124			bit = CC_PEND_B;
125			REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
126		}
127		return;
128	}
129	bit = irq_to_bit_pos(irq);
130	REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
131#endif
132
133#ifdef CONFIG_IA64_SGI_SN2
134	event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) );
135	if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
136		mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT);
137	}
138	if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) {
139		mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT);
140	}
141	if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) {
142		mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT);
143	}
144	if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) {
145		mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT);
146	}
147	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), mask );
148#endif
149}
150
151static void
152sn_end_irq(unsigned int irq)
153{
154#ifdef CONFIG_IA64_SGI_SN1
155	unsigned long long intpend_val, mask = 0x70L;
156	int subnode;
157#endif
158	int nasid;
159#ifdef CONFIG_IA64_SGI_SN2
160	unsigned long event_occurred;
161#endif
162
163	irq = irq & 0xff;
164#ifdef CONFIG_IA64_SGI_SN1
165	if (irq == SGI_UART_IRQ) {
166		nasid = smp_physical_node_id();
167		subnode = cpuid_to_subnode(smp_processor_id());
168		intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0);
169		if (intpend_val & mask) {
170			platform_send_ipi(smp_processor_id(), SGI_UART_IRQ, IA64_IPI_DM_INT, 0);
171		}
172	}
173#endif
174#ifdef CONFIG_IA64_SGI_SN2
175	if (irq == SGI_UART_VECTOR) {
176		nasid = smp_physical_node_id();
177		event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) );
178		// If the UART bit is set here, we may have received an interrupt from the
179		// UART that the driver missed.  To make sure, we IPI ourselves to force us
180		// to look again.
181		if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
182				platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0);
183		}
184	}
185#endif
186
187}
188
189static void
190sn_set_affinity_irq(unsigned int irq, unsigned long mask)
191{
192}
193
194
195struct hw_interrupt_type irq_type_iosapic_level = {
196	"SN hub",
197	sn_startup_irq,
198	sn_shutdown_irq,
199	sn_enable_irq,
200	sn_disable_irq,
201	sn_ack_irq,
202	sn_end_irq,
203	sn_set_affinity_irq
204};
205
206
207#define irq_type_sn irq_type_iosapic_level
208struct irq_desc *_sn_irq_desc[NR_CPUS];
209
210struct irq_desc *
211sn_irq_desc(unsigned int irq) {
212	int cpu = irq >> 8;
213
214	irq = irq & 0xff;
215
216	return(_sn_irq_desc[cpu] + irq);
217}
218
219u8
220sn_irq_to_vector(u8 irq) {
221	return(irq & 0xff);
222}
223
224unsigned int
225sn_local_vector_to_irq(u8 vector) {
226	return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
227}
228
229int
230sn_valid_irq(u8 irq) {
231
232	return( ((irq & 0xff) < NR_IRQS) && ((irq >> 8) < NR_CPUS) );
233}
234
235void *kmalloc(size_t, int);
236
237void
238sn_irq_init (void)
239{
240	int i;
241	irq_desc_t *base_desc = _irq_desc;
242
243	for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IRQS; i++) {
244		if (base_desc[i].handler == &no_irq_type) {
245			base_desc[i].handler = &irq_type_sn;
246		}
247	}
248}
249
250void
251sn_init_irq_desc(void) {
252	int i;
253	irq_desc_t *base_desc = _irq_desc, *p;
254
255	for (i=0; i < NR_CPUS; i++) {
256		p =  page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL,
257			get_order(sizeof(struct irq_desc) * NR_IRQS) ) );
258		ASSERT(p);
259		memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IRQS);
260		_sn_irq_desc[i] = p;
261	}
262}
263
264
265#if !defined(CONFIG_IA64_SGI_SN)
266void
267sn_pci_fixup(void)
268{
269}
270#endif
271
272int
273bit_pos_to_irq(int bit) {
274#define BIT_TO_IRQ 64
275	if (bit > 118) bit = 118;
276
277#ifdef CONFIG_IA64_SGI_SN1
278	if (bit >= GFX_INTR_A && bit <= CC_PEND_B) {
279		return SGI_UART_IRQ;
280	}
281#endif
282
283        return bit + BIT_TO_IRQ;
284}
285
286int
287irq_to_bit_pos(int irq) {
288#define IRQ_TO_BIT 64
289	int bit = irq - IRQ_TO_BIT;
290
291        return bit;
292}
293
294#ifdef ajmtestintr
295
296#include <linux/timer.h>
297struct timer_list intr_test_timer;
298int intr_test_icount[NR_IRQS];
299struct intr_test_reg_struct {
300	pcibr_soft_t pcibr_soft;
301	int slot;
302};
303struct intr_test_reg_struct intr_test_registered[NR_IRQS];
304
305void
306intr_test_handle_timer(unsigned long data) {
307	int i;
308	bridge_t	*bridge;
309
310	for (i=0;i<NR_IRQS;i++) {
311		if (intr_test_registered[i].pcibr_soft) {
312			pcibr_soft_t pcibr_soft = intr_test_registered[i].pcibr_soft;
313			xtalk_intr_t intr = pcibr_soft->bs_intr[intr_test_registered[i].slot].bsi_xtalk_intr;
314			/* send interrupt */
315			bridge = pcibr_soft->bs_base;
316			bridge->b_force_always[intr_test_registered[i].slot].intr = 1;
317		}
318	}
319	del_timer(&intr_test_timer);
320	intr_test_timer.expires = jiffies + HZ/100;
321	add_timer(&intr_test_timer);
322}
323
324void
325intr_test_set_timer(void) {
326	intr_test_timer.expires = jiffies + HZ/100;
327	intr_test_timer.function = intr_test_handle_timer;
328	add_timer(&intr_test_timer);
329}
330
331void
332intr_test_register_irq(int irq, pcibr_soft_t pcibr_soft, int slot) {
333	irq = irq & 0xff;
334	intr_test_registered[irq].pcibr_soft = pcibr_soft;
335	intr_test_registered[irq].slot = slot;
336}
337
338void
339intr_test_handle_intr(int irq, void *junk, struct pt_regs *morejunk) {
340	intr_test_icount[irq]++;
341	printk("RECEIVED %d INTERRUPTS ON IRQ %d\n",intr_test_icount[irq], irq);
342}
343#endif /* ajmtestintr */
344