patch-2.4.0-test2 linux/arch/ppc/kernel/xics.c
Next file: linux/arch/ppc/kernel/xics.h
Previous file: linux/arch/ppc/kernel/time.c
Back to the patch index
Back to the overall index
- Lines: 215
- Date:
Mon Jun 19 17:59:36 2000
- Orig file:
v2.4.0-test1/linux/arch/ppc/kernel/xics.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.0-test1/linux/arch/ppc/kernel/xics.c linux/arch/ppc/kernel/xics.c
@@ -0,0 +1,214 @@
+/*
+ * arch/ppc/kernel/xics.c
+ *
+ * Copyright 2000 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/threads.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include "i8259.h"
+#include "xics.h"
+
+void xics_enable_irq(u_int irq);
+void xics_disable_irq(u_int irq);
+void xics_mask_and_ack_irq(u_int irq);
+void xics_end_irq(u_int irq);
+
+struct hw_interrupt_type xics_pic = {
+ " XICS ",
+ NULL,
+ NULL,
+ xics_enable_irq,
+ xics_disable_irq,
+ xics_mask_and_ack_irq,
+ xics_end_irq
+};
+
+struct hw_interrupt_type xics_8259_pic = {
+ " XICS/8259",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ xics_mask_and_ack_irq,
+ NULL
+};
+
+#define XICS_IPI 2
+#define XICS_IRQ_8259_CASCADE 0x2c
+#define XICS_IRQ_OFFSET 16
+#define XICS_IRQ_SPURIOUS 0
+
+#define DEFAULT_SERVER 0
+#define DEFAULT_PRIORITY 0
+
+struct xics_ipl {
+ union {
+ u32 word;
+ u8 bytes[4];
+ } xirr_poll;
+ union {
+ u32 word;
+ u8 bytes[4];
+ } xirr;
+ u32 dummy;
+ union {
+ u32 word;
+ u8 bytes[4];
+ } qirr;
+};
+
+struct xics_info {
+ volatile struct xics_ipl * per_cpu[NR_CPUS];
+};
+
+struct xics_info xics_info;
+
+#define xirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.word)
+#define cppr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.bytes[0])
+#define poll_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr_poll.word)
+#define qirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->qirr.bytes[0])
+
+void
+xics_enable_irq(
+ u_int irq
+ )
+{
+ int status;
+ int call_status;
+
+ irq -= XICS_IRQ_OFFSET;
+ if (irq == XICS_IPI)
+ return;
+ call_status = call_rtas("ibm,set-xive", 3, 1, (ulong*)&status,
+ irq, DEFAULT_SERVER, DEFAULT_PRIORITY);
+ if( call_status != 0 ) {
+ printk("xics_enable_irq: irq=%x: call_rtas failed; retn=%x, status=%x\n",
+ irq, call_status, status);
+ return;
+ }
+}
+
+void
+xics_disable_irq(
+ u_int irq
+ )
+{
+ int status;
+ int call_status;
+
+ irq -= XICS_IRQ_OFFSET;
+ call_status = call_rtas("ibm,int-off", 1, 1, (ulong*)&status, irq);
+ if( call_status != 0 ) {
+ printk("xics_disable_irq: irq=%x: call_rtas failed, retn=%x\n",
+ irq, call_status);
+ return;
+ }
+}
+
+void
+xics_end_irq(
+ u_int irq
+ )
+{
+ int cpu = smp_processor_id();
+
+ cppr_info(cpu) = 0; /* actually the value overwritten by ack */
+ xirr_info(cpu) = (0xff<<24) | (irq-XICS_IRQ_OFFSET);
+}
+
+void
+xics_mask_and_ack_irq(
+ u_int irq
+ )
+{
+ int cpu = smp_processor_id();
+
+ if( irq < XICS_IRQ_OFFSET ) {
+ i8259_pic.ack(irq);
+ xirr_info(cpu) = (0xff<<24) | XICS_IRQ_8259_CASCADE;
+ }
+ else {
+ cppr_info(cpu) = 0xff;
+ }
+}
+
+int
+xics_get_irq(struct pt_regs *regs)
+{
+ u_int cpu = smp_processor_id();
+ u_int vec;
+ int irq;
+
+ vec = xirr_info(cpu);
+ /* (vec >> 24) == old priority */
+ vec &= 0x00ffffff;
+ /* for sanity, this had better be < NR_IRQS - 16 */
+ if( vec == XICS_IRQ_8259_CASCADE )
+ irq = i8259_irq(cpu);
+ else if( vec == XICS_IRQ_SPURIOUS )
+ irq = -1;
+ else
+ irq = vec + XICS_IRQ_OFFSET;
+ return irq;
+}
+
+#ifdef CONFIG_SMP
+void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
+{
+ qirr_info(smp_processor_id()) = 0xff;
+ smp_message_recv(MSG_RESCHEDULE);
+}
+
+void xics_cause_IPI(int cpu)
+{
+ qirr_info(cpu) = 0;
+}
+
+void xics_setup_cpu(void)
+{
+ int cpu = smp_processor_id();
+
+ cppr_info(cpu) = 0xff;
+}
+#endif /* CONFIG_SMP */
+
+void
+xics_init_IRQ( void )
+{
+ int i;
+ extern unsigned long smp_chrp_cpu_nr;
+
+#ifdef CONFIG_SMP
+ for (i = 0; i < smp_chrp_cpu_nr; ++i)
+ xics_info.per_cpu[i] =
+ ioremap(0xfe000000 + smp_hw_index[i] * 0x1000, 0x20);
+#else
+ xics_info.per_cpu[0] = ioremap(0xfe000000, 0x20);
+#endif /* CONFIG_SMP */
+ xics_8259_pic.enable = i8259_pic.enable;
+ xics_8259_pic.disable = i8259_pic.disable;
+ for (i = 0; i < 16; ++i)
+ irq_desc[i].handler = &xics_8259_pic;
+ for (; i < NR_IRQS; ++i)
+ irq_desc[i].handler = &xics_pic;
+
+ cppr_info(0) = 0xff;
+ if (request_irq(XICS_IRQ_8259_CASCADE + XICS_IRQ_OFFSET, no_action,
+ 0, "8259 cascade", 0))
+ printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");
+ i8259_init();
+
+#ifdef CONFIG_SMP
+ request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);
+#endif
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)