patch-2.4.19 linux-2.4.19/arch/ia64/sn/kernel/irq.c
Next file: linux-2.4.19/arch/ia64/sn/kernel/llsc4.c
Previous file: linux-2.4.19/arch/ia64/sn/kernel/iomv.c
Back to the patch index
Back to the overall index
- Lines: 344
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/arch/ia64/sn/kernel/irq.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.18/arch/ia64/sn/kernel/irq.c linux-2.4.19/arch/ia64/sn/kernel/irq.c
@@ -0,0 +1,343 @@
+/*
+ * Platform dependent support for SGI SN1
+ *
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <asm/current.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/types.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pciio_private.h>
+#ifdef ajmtestintr
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#endif /* ajmtestintr */
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/io.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/arch.h>
+
+int irq_to_bit_pos(int irq);
+
+
+
+static unsigned int
+sn_startup_irq(unsigned int irq)
+{
+ return(0);
+}
+
+static void
+sn_shutdown_irq(unsigned int irq)
+{
+}
+
+static void
+sn_disable_irq(unsigned int irq)
+{
+}
+
+static void
+sn_enable_irq(unsigned int irq)
+{
+}
+
+static void
+sn_ack_irq(unsigned int irq)
+{
+#ifdef CONFIG_IA64_SGI_SN1
+ int bit = -1;
+ unsigned long long intpend_val;
+ int subnode;
+#endif
+#ifdef CONFIG_IA64_SGI_SN2
+ unsigned long event_occurred, mask = 0;
+#endif
+ int nasid;
+
+ irq = irq & 0xff;
+ nasid = smp_physical_node_id();
+#ifdef CONFIG_IA64_SGI_SN1
+ subnode = cpuid_to_subnode(smp_processor_id());
+ if (irq == SGI_UART_IRQ) {
+ intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0);
+ if (intpend_val & (1L<<GFX_INTR_A) ) {
+ bit = GFX_INTR_A;
+ REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
+ }
+ if ( intpend_val & (1L<<GFX_INTR_B) ) {
+ bit = GFX_INTR_B;
+ REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
+ }
+ if (intpend_val & (1L<<PG_MIG_INTR) ) {
+ bit = PG_MIG_INTR;
+ REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
+ }
+ if (intpend_val & (1L<<CC_PEND_A)) {
+ bit = CC_PEND_A;
+ REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
+ }
+ if (intpend_val & (1L<<CC_PEND_B)) {
+ bit = CC_PEND_B;
+ REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
+ }
+ return;
+ }
+ bit = irq_to_bit_pos(irq);
+ REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit);
+#endif
+
+#ifdef CONFIG_IA64_SGI_SN2
+ event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) );
+ if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
+ mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT);
+ }
+ if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) {
+ mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT);
+ }
+ if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) {
+ mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT);
+ }
+ if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) {
+ mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT);
+ }
+ HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), mask );
+#endif
+}
+
+static void
+sn_end_irq(unsigned int irq)
+{
+#ifdef CONFIG_IA64_SGI_SN1
+ unsigned long long intpend_val, mask = 0x70L;
+ int subnode;
+#endif
+ int nasid;
+#ifdef CONFIG_IA64_SGI_SN2
+ unsigned long event_occurred;
+#endif
+
+ irq = irq & 0xff;
+#ifdef CONFIG_IA64_SGI_SN1
+ if (irq == SGI_UART_IRQ) {
+ nasid = smp_physical_node_id();
+ subnode = cpuid_to_subnode(smp_processor_id());
+ intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0);
+ if (intpend_val & mask) {
+ platform_send_ipi(smp_processor_id(), SGI_UART_IRQ, IA64_IPI_DM_INT, 0);
+ }
+ }
+#endif
+#ifdef CONFIG_IA64_SGI_SN2
+ if (irq == SGI_UART_VECTOR) {
+ nasid = smp_physical_node_id();
+ event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) );
+ // If the UART bit is set here, we may have received an interrupt from the
+ // UART that the driver missed. To make sure, we IPI ourselves to force us
+ // to look again.
+ if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) {
+ platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0);
+ }
+ }
+#endif
+
+}
+
+static void
+sn_set_affinity_irq(unsigned int irq, unsigned long mask)
+{
+}
+
+
+struct hw_interrupt_type irq_type_iosapic_level = {
+ "SN hub",
+ sn_startup_irq,
+ sn_shutdown_irq,
+ sn_enable_irq,
+ sn_disable_irq,
+ sn_ack_irq,
+ sn_end_irq,
+ sn_set_affinity_irq
+};
+
+
+#define irq_type_sn irq_type_iosapic_level
+struct irq_desc *_sn_irq_desc[NR_CPUS];
+
+struct irq_desc *
+sn_irq_desc(unsigned int irq) {
+ int cpu = irq >> 8;
+
+ irq = irq & 0xff;
+
+ return(_sn_irq_desc[cpu] + irq);
+}
+
+u8
+sn_irq_to_vector(u8 irq) {
+ return(irq & 0xff);
+}
+
+unsigned int
+sn_local_vector_to_irq(u8 vector) {
+ return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
+}
+
+int
+sn_valid_irq(u8 irq) {
+
+ return( ((irq & 0xff) < NR_IRQS) && ((irq >> 8) < NR_CPUS) );
+}
+
+void *kmalloc(size_t, int);
+
+void
+sn_irq_init (void)
+{
+ int i;
+ irq_desc_t *base_desc = _irq_desc;
+
+ for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IRQS; i++) {
+ if (base_desc[i].handler == &no_irq_type) {
+ base_desc[i].handler = &irq_type_sn;
+ }
+ }
+}
+
+void
+sn_init_irq_desc(void) {
+ int i;
+ irq_desc_t *base_desc = _irq_desc, *p;
+
+ for (i=0; i < NR_CPUS; i++) {
+ p = page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL,
+ get_order(sizeof(struct irq_desc) * NR_IRQS) ) );
+ ASSERT(p);
+ memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IRQS);
+ _sn_irq_desc[i] = p;
+ }
+}
+
+
+#if !defined(CONFIG_IA64_SGI_SN)
+void
+sn_pci_fixup(void)
+{
+}
+#endif
+
+int
+bit_pos_to_irq(int bit) {
+#define BIT_TO_IRQ 64
+ if (bit > 118) bit = 118;
+
+#ifdef CONFIG_IA64_SGI_SN1
+ if (bit >= GFX_INTR_A && bit <= CC_PEND_B) {
+ return SGI_UART_IRQ;
+ }
+#endif
+
+ return bit + BIT_TO_IRQ;
+}
+
+int
+irq_to_bit_pos(int irq) {
+#define IRQ_TO_BIT 64
+ int bit = irq - IRQ_TO_BIT;
+
+ return bit;
+}
+
+#ifdef ajmtestintr
+
+#include <linux/timer.h>
+struct timer_list intr_test_timer;
+int intr_test_icount[NR_IRQS];
+struct intr_test_reg_struct {
+ pcibr_soft_t pcibr_soft;
+ int slot;
+};
+struct intr_test_reg_struct intr_test_registered[NR_IRQS];
+
+void
+intr_test_handle_timer(unsigned long data) {
+ int i;
+ bridge_t *bridge;
+
+ for (i=0;i<NR_IRQS;i++) {
+ if (intr_test_registered[i].pcibr_soft) {
+ pcibr_soft_t pcibr_soft = intr_test_registered[i].pcibr_soft;
+ xtalk_intr_t intr = pcibr_soft->bs_intr[intr_test_registered[i].slot].bsi_xtalk_intr;
+ /* send interrupt */
+ bridge = pcibr_soft->bs_base;
+ bridge->b_force_always[intr_test_registered[i].slot].intr = 1;
+ }
+ }
+ del_timer(&intr_test_timer);
+ intr_test_timer.expires = jiffies + HZ/100;
+ add_timer(&intr_test_timer);
+}
+
+void
+intr_test_set_timer(void) {
+ intr_test_timer.expires = jiffies + HZ/100;
+ intr_test_timer.function = intr_test_handle_timer;
+ add_timer(&intr_test_timer);
+}
+
+void
+intr_test_register_irq(int irq, pcibr_soft_t pcibr_soft, int slot) {
+ irq = irq & 0xff;
+ intr_test_registered[irq].pcibr_soft = pcibr_soft;
+ intr_test_registered[irq].slot = slot;
+}
+
+void
+intr_test_handle_intr(int irq, void *junk, struct pt_regs *morejunk) {
+ intr_test_icount[irq]++;
+ printk("RECEIVED %d INTERRUPTS ON IRQ %d\n",intr_test_icount[irq], irq);
+}
+#endif /* ajmtestintr */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)