changeset: 9457:fd4dd4cdacbe
user: jimix@xxxxxxxxxxxxxxxxxxxxx
date: Fri Mar 24 17:50:52 2006 -0500
summary: [ppc] mpic and evtchn merge.
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/arch/ppc/external.c
--- a/xen/arch/ppc/external.c Thu Mar 23 16:19:12 2006 -0500
+++ b/xen/arch/ppc/external.c Fri Mar 24 17:50:52 2006 -0500
@@ -20,27 +20,51 @@
#include <xen/types.h>
#include <xen/sched.h>
#include <xen/lib.h>
+#include <xen/event.h>
+#include <xen/irq.h>
#include <public/xen.h>
#include <asm/current.h>
#include <asm/hardirq.h>
+#include <asm/mpic.h>
#undef DEBUG
-
-static int pending_dom0_ee;
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+extern void do_IRQ(struct cpu_user_regs *regs);
+
+int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
+unsigned long io_apic_irqs;
+static struct mpic *mpic;
+static struct hw_interrupt_type hc_irq;
/* deliver_ee: called with interrupts off when resuming every vcpu */
void deliver_ee(struct cpu_user_regs *regs)
{
- const ulong srr_mask = ~(MSR_IR | MSR_DR | MSR_FE0 | MSR_PR |
- MSR_FE1 | MSR_EE | MSR_RI);
+ const ulong srr_mask = ~(MSR_IR | MSR_DR | MSR_FE0 | MSR_FE1 | MSR_EE |
+ MSR_RI |
+ MSR_BE | MSR_FP | MSR_PMM | MSR_PR | MSR_SE);
+
+
+ local_irq_disable();
/* trigger exception only if we have a pending irq, we're resuming a guest
* (not the hypervisor), the guest is dom0, and it has MSR:EE set. */
- if ((!pending_dom0_ee)
- || (regs->msr & MSR_HV)
- || (current->domain->domain_id != 0)
- || !(regs->msr & MSR_EE))
+ if (!event_pending(current)) {
+ if (current->vcpu_info->evtchn_upcall_pending) {
+ printk("0x%lx,0x%x\n",
+ current->vcpu_info->evtchn_upcall_pending,
+ current->vcpu_info->evtchn_upcall_mask);
+ for (;;);
+ }
return;
+ }
+ if (regs->msr & MSR_HV) return;
+ if (current->domain->domain_id != 0) return;
+ if (!(regs->msr & MSR_EE)) return;
/* XXX OS error: EE was set but RI was not. We could trigger a machine
* check, or kill the domain... for now just crash Xen so we notice. */
@@ -51,53 +75,222 @@ void deliver_ee(struct cpu_user_regs *re
regs->srr1 = regs->msr & ~0x00000000783f0000;
regs->pc = 0x500;
regs->msr &= srr_mask;
- regs->msr |= MSR_SF;
-
-#ifdef DEBUG
- printk("<HV: pc=0x%lx, msr=0x%lx\n", regs->pc, regs->msr);
-#endif
-
- pending_dom0_ee = 0;
+ regs->msr |= MSR_SF | MSR_ME;
+
+ DBG("<HV: pc=0x%lx, msr=0x%lx\n", regs->pc, regs->msr);
}
void do_external(struct cpu_user_regs *regs)
{
- shared_info_t *si;
- ulong *irqp;
- ulong *maskp;
- uint64_t *selp;
- int irqs;
- int pend;
- int cpu = 0;
-
- /* currently dom0 gets all external interrupts */
- si = dom0->shared_info;
- irqp = si->evtchn_pending;
- maskp = si->evtchn_mask;
- irqs = sizeof (si->evtchn_pending) * 8;
- selp = &si->vcpu_info[cpu].evtchn_pending_sel;
-
-#ifdef DEBUG
- printk(">HV: pc=0x%lx, msr=0x%lx\n", regs->pc, regs->msr);
-#endif
-
- /* probe the external interrupt controller */
- pend = external_get_irq(irqp, maskp, selp, irqs);
- if (!pend) {
- int i;
- /* interrupt occured but it was masked */
- printk("%s all pending externals were masked\np: ", __func__);
- for (i = 0; i < ARRAY_SIZE(si->evtchn_pending); i++) {
- printk("0x%lx ", si->evtchn_pending[i]);
- }
- printk("\nm: ");
- for (i = 0; i < ARRAY_SIZE(si->evtchn_mask); i++) {
- printk("0x%lx ", si->evtchn_mask[i]);
- }
- printk("\n");
- return;
- }
-
- /* deliver all EEs to dom0 during resume */
- pending_dom0_ee = 1;
-}
+ int vec;
+
+ local_irq_disable();
+
+ vec = mpic_get_one_irq(mpic, regs);
+
+ DBG("EE:0x%lx isrc: %d\n", regs->msr, vec);
+ if (vec != -1) {
+ regs->entry_vector = vec;
+ do_IRQ(regs);
+ }
+}
+
+static int xen_local_irq(unsigned int irq)
+{
+ irq_desc_t *desc;
+ unsigned int vector;
+
+ vector = irq_to_vector(irq);
+ desc = &irq_desc[vector];
+
+ return !(desc->status & IRQ_GUEST);
+}
+
+static unsigned int xen_startup_irq(unsigned int irq)
+{
+ DBG("%s(%d)\n", __func__, irq);
+ if (xen_local_irq(irq)) {
+ return hc_irq.startup(irq);
+ }
+ return 0;
+}
+
+static void xen_shutdown_irq(unsigned int irq)
+{
+ DBG("%s(%d)\n", __func__, irq);
+ if (xen_local_irq(irq)) {
+ hc_irq.shutdown(irq);
+ }
+}
+
+static void xen_enable_irq(unsigned int irq)
+{
+ DBG("%s(%d)\n", __func__, irq);
+ if (xen_local_irq(irq)) {
+ hc_irq.enable(irq);
+ }
+}
+
+static void xen_disable_irq(unsigned int irq)
+{
+ DBG("%s(%d)\n", __func__, irq);
+ if (xen_local_irq(irq)) {
+ hc_irq.disable(irq);
+ }
+}
+
+static void xen_ack_irq(unsigned int irq)
+{
+ DBG("%s(%d)\n", __func__, irq);
+ if (xen_local_irq(irq)) {
+ if (hc_irq.ack) hc_irq.ack(irq);
+ }
+}
+
+static void xen_end_irq(unsigned int irq)
+{
+ DBG("%s(%d)\n", __func__, irq);
+ if (xen_local_irq(irq)) {
+ hc_irq.end(irq);
+ }
+}
+
+static void xen_set_affinity(unsigned int irq, cpumask_t mask)
+{
+ DBG("%s(%d)\n", __func__, irq);
+ if (xen_local_irq(irq)) {
+ if (hc_irq.set_affinity) hc_irq.set_affinity(irq, mask);
+ }
+}
+
+void init_IRQ(void)
+{
+ unsigned long opic_addr;
+ unsigned int isu_size;
+ unsigned int irq_offset;
+ unsigned int irq_count;
+ unsigned int ipi_offset;
+ unsigned char *senses;
+ unsigned int senses_count;
+
+ printk("%s: start\n", __func__);
+
+ io_apic_irqs = ~0; /* all IRQs go through IOAPIC */
+ irq_vector[0] = FIRST_DEVICE_VECTOR;
+ vector_irq[FIRST_DEVICE_VECTOR] = 0;
+
+ /* should find this in the devtree:
+ * G5 is at 0xffc00000
+ * Maple is at 0xf8040000
+ */
+ opic_addr = 0xf8040000;
+ isu_size = 0;
+ irq_offset = 0;
+ irq_count = 128;
+ ipi_offset = 128;
+ senses = NULL;
+ senses_count = 0;
+
+ mpic = mpic_alloc(opic_addr,
+ MPIC_PRIMARY | MPIC_BIG_ENDIAN |
+ MPIC_BROKEN_U3 | MPIC_WANTS_RESET,
+ isu_size, irq_offset, irq_count,
+ ipi_offset, senses, senses_count, "Xen-U3-MPIC");
+
+ BUG_ON(mpic == NULL);
+ mpic_init(mpic);
+
+ hc_irq.startup = mpic->hc_irq.startup;
+ mpic->hc_irq.startup = xen_startup_irq;
+
+ hc_irq.enable = mpic->hc_irq.enable;
+ mpic->hc_irq.enable = xen_enable_irq;
+
+ hc_irq.disable = mpic->hc_irq.disable;
+ mpic->hc_irq.disable = xen_disable_irq;
+
+ hc_irq.shutdown = mpic->hc_irq.shutdown;
+ mpic->hc_irq.shutdown = xen_shutdown_irq;
+
+ hc_irq.ack = mpic->hc_irq.ack;
+ mpic->hc_irq.ack = xen_ack_irq;
+
+ hc_irq.end = mpic->hc_irq.end;
+ mpic->hc_irq.end = xen_end_irq;
+
+ hc_irq.set_affinity = mpic->hc_irq.set_affinity;
+ mpic->hc_irq.set_affinity = xen_set_affinity;
+
+ printk("%s: success\n", __func__);
+}
+
+void ack_APIC_irq(void) {
+ printk("%s: EOI the whole MPIC?\n", __func__);
+ for (;;);
+}
+
+void ack_bad_irq(unsigned int irq)
+{
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+ /*
+ * Currently unexpected vectors happen only on SMP and APIC.
+ * We _must_ ack these because every local APIC has only N
+ * irq slots per priority level, and a 'hanging, unacked' IRQ
+ * holds up an irq slot - in excessive cases (when multiple
+ * unexpected vectors occur) that might lock up the APIC
+ * completely.
+ */
+ ack_APIC_irq();
+}
+
+void dump_ioapic_irq_info(void)
+{
+ printk("%s: can't dump yet\n", __func__);
+}
+
+/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
+u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
+int assign_irq_vector(int irq)
+{
+ static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+
+ BUG_ON(irq >= NR_IRQ_VECTORS);
+ if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
+ return IO_APIC_VECTOR(irq);
+next:
+ current_vector += 8;
+
+ /* Skip the hypercall vector. */
+ if (current_vector == HYPERCALL_VECTOR)
+ goto next;
+
+ /* Skip the Linux/BSD fast-trap vector. */
+ if (current_vector == FAST_TRAP)
+ goto next;
+
+ if (current_vector >= FIRST_SYSTEM_VECTOR) {
+ offset++;
+ if (!(offset%8))
+ return -ENOSPC;
+ current_vector = FIRST_DEVICE_VECTOR + offset;
+ }
+
+ vector_irq[current_vector] = irq;
+ if (irq != AUTO_ASSIGN)
+ IO_APIC_VECTOR(irq) = current_vector;
+
+ return current_vector;
+}
+
+int ioapic_guest_read(unsigned long physbase, unsigned int reg, u32 *pval)
+{
+ BUG_ON(pval != pval);
+
+ return 0;
+}
+
+int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val)
+{
+ BUG_ON(val != val);
+ return 0;
+}
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/arch/ppc/setup.c
--- a/xen/arch/ppc/setup.c Thu Mar 23 16:19:12 2006 -0500
+++ b/xen/arch/ppc/setup.c Fri Mar 24 17:50:52 2006 -0500
@@ -275,7 +275,6 @@ static void __init __start_xen(multiboot
debugger_trap_immediate();
#endif
- external_init(0xf8040000, 0);
start_of_day();
/* Create initial domain 0. */
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/drivers/char/console.c
--- a/xen/drivers/char/console.c Thu Mar 23 16:19:12 2006 -0500
+++ b/xen/drivers/char/console.c Fri Mar 24 17:50:52 2006 -0500
@@ -323,6 +323,7 @@ static long guest_console_write(GUEST_HA
{
char kbuf[128], *kptr;
int kcount;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
while ( count > 0 )
{
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/include/asm-ppc/io.h
--- a/xen/include/asm-ppc/io.h Thu Mar 23 16:19:12 2006 -0500
+++ b/xen/include/asm-ppc/io.h Fri Mar 24 17:50:52 2006 -0500
@@ -35,7 +35,7 @@ extern ulong isa_io_base;
#define inl(port) in_le32((void *)((ulong)(port) + isa_io_base))
#define outl(val, port) out_le32((void *)((ulong)(port) + isa_io_base), val)
-#define ioremap(x,l) (x)
+#define ioremap(x,l) (void __iomem *)(x)
#define readb(port) in_8((void *)(port))
#define writeb(val, port) out_8((void *)(port), val)
@@ -49,6 +49,18 @@ extern unsigned in_le32(const volatile u
extern unsigned in_le32(const volatile unsigned *addr);
extern void out_le32(volatile unsigned *addr, int val);
+#define in_be8 in_8
+#define in_be16 in_16
+#define in_be32 in_32
+#define out_be8 out_8
+#define out_be16 out_16
+#define out_be32 out_32
+
+#define readw(port) in_le16((void *)(port))
+#define readl(port) in_le32((void *)(port))
+#define writew(val, port) out_le16((void *)(port), val)
+#define writel(val, port) out_le32((void *)(port), val)
+
#define barrier() __asm__ __volatile__("": : :"memory")
#endif
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/include/asm-ppc/smp.h
--- a/xen/include/asm-ppc/smp.h Thu Mar 23 16:19:12 2006 -0500
+++ b/xen/include/asm-ppc/smp.h Fri Mar 24 17:50:52 2006 -0500
@@ -26,6 +26,8 @@ extern int smp_num_siblings;
extern int smp_num_siblings;
/* revisit when we support SMP */
+#define get_hard_smp_processor_id(i) i
+#define hard_smp_processor_id() 0
#define raw_smp_processor_id() 0
extern cpumask_t cpu_sibling_map[];
extern cpumask_t cpu_core_map[];
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/include/public/arch-ppc64.h
--- a/xen/include/public/arch-ppc64.h Thu Mar 23 16:19:12 2006 -0500
+++ b/xen/include/public/arch-ppc64.h Fri Mar 24 17:50:52 2006 -0500
@@ -74,7 +74,7 @@ typedef struct cpu_user_regs
uint32_t fpscr;
uint32_t cr;
uint32_t xer;
- uint32_t _pad;
+ uint32_t entry_vector;
} cpu_user_regs_t;
typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ /* XXX timebase */
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/include/xen/sched.h
--- a/xen/include/xen/sched.h Thu Mar 23 16:19:12 2006 -0500
+++ b/xen/include/xen/sched.h Fri Mar 24 17:50:52 2006 -0500
@@ -133,7 +133,7 @@ struct domain
*/
#define NR_PIRQS 256 /* Put this somewhere sane! */
u16 pirq_to_evtchn[NR_PIRQS];
- u32 pirq_mask[NR_PIRQS/32];
+ unsigned long pirq_mask[NR_PIRQS/BITS_PER_LONG];
/* I/O capabilities (access to IRQs and memory-mapped I/O). */
struct rangeset *iomem_caps;
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/arch/ppc/mpic.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/xen/arch/ppc/mpic.c Fri Mar 24 17:50:52 2006 -0500
@@ -0,0 +1,1096 @@
+/* make this generic */
+
+#define le32_to_cpu(x) \
+({ \
+ __u32 __x = (x); \
+ ((__u32)( \
+ (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | \
+ (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | \
+ (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | \
+ (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); \
+})
+
+static inline void smp_message_recv(int msg, void /* struct pt_regs */ *regs)
+{
+ return;
+}
+
+#define alloc_bootmem(x) xmalloc_bytes(x)
+#define request_irq(irq, handler, f, devname, dev_id) \
+ panic("IPI requested: %d: %p: %s: %p\n", irq, handler, devname, dev_id)
+
+typedef int irqreturn_t;
+
+#define IRQ_NONE (0)
+#define IRQ_HANDLED (1)
+#define IRQ_RETVAL(x) ((x) != 0)
+
+#define IRQ_SENSE_MASK 0x1
+#define IRQ_SENSE_LEVEL 0x1 /* interrupt on active level */
+#define IRQ_SENSE_EDGE 0x0 /* interrupt triggered by edge */
+
+#define IRQ_POLARITY_MASK 0x2
+#define IRQ_POLARITY_POSITIVE 0x2 /* high level or low->high edge */
+#define IRQ_POLARITY_NEGATIVE 0x0 /* low level or high->low edge */
+#define IRQ_LEVEL 64 /* IRQ level triggered */
+
+#define CONFIG_IRQ_ALL_CPUS 0
+#define distribute_irqs CONFIG_IRQ_ALL_CPUS
+#define CONFIG_MPIC_BROKEN_U3
+
+#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list
entry */
+#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
+#define PCI_CAP_LIST_ID 0 /* Capability ID */
+#define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */
+#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
+
+
+/*
+ * arch/powerpc/kernel/mpic.c
+ *
+ * Driver for interrupt controllers following the OpenPIC standard, the
+ * common implementation beeing IBM's MPIC. This driver also can deal
+ * with various broken implementations of this HW.
+ *
+ * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#undef DEBUG
+#undef DEBUG_IPI
+#undef DEBUG_IRQ
+#undef DEBUG_LOW
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/kernel.h>
+#include <xen/init.h>
+#include <xen/irq.h>
+#include <xen/smp.h>
+//#include <linux/interrupt.h>
+//#include <linux/bootmem.h>
+#include <xen/spinlock.h>
+//#include <asm/pci.h>
+
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+//#include <asm/pgtable.h>
+//#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/mpic.h>
+#include <asm/smp.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static struct mpic *mpics;
+static struct mpic *mpic_primary;
+static DEFINE_SPINLOCK(mpic_lock);
+
+#ifdef CONFIG_PPC32 /* XXX for now */
+#ifdef CONFIG_IRQ_ALL_CPUS
+#define distribute_irqs (1)
+#else
+#define distribute_irqs (0)
+#endif
+#endif
+
+/*
+ * Register accessor functions
+ */
+
+
+static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base,
+ unsigned int reg)
+{
+ if (be)
+ return in_be32(base + (reg >> 2));
+ else
+ return in_le32(base + (reg >> 2));
+}
+
+static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base,
+ unsigned int reg, u32 value)
+{
+ if (be)
+ out_be32(base + (reg >> 2), value);
+ else
+ out_le32(base + (reg >> 2), value);
+}
+
+static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
+{
+ unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0;
+ unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+
+ if (mpic->flags & MPIC_BROKEN_IPI)
+ be = !be;
+ return _mpic_read(be, mpic->gregs, offset);
+}
+
+static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32
value)
+{
+ unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+
+ _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value);
+}
+
+static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
+{
+ unsigned int cpu = 0;
+
+ if (mpic->flags & MPIC_PRIMARY)
+ cpu = hard_smp_processor_id();
+
+ return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu],
reg);
+}
+
+static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32
value)
+{
+ unsigned int cpu = 0;
+
+ if (mpic->flags & MPIC_PRIMARY)
+ cpu = hard_smp_processor_id();
+
+ _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg,
value);
+}
+
+static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no,
unsigned int reg)
+{
+ unsigned int isu = src_no >> mpic->isu_shift;
+ unsigned int idx = src_no & mpic->isu_mask;
+
+ return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
+ reg + (idx * MPIC_IRQ_STRIDE));
+}
+
+static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
+ unsigned int reg, u32 value)
+{
+ unsigned int isu = src_no >> mpic->isu_shift;
+ unsigned int idx = src_no & mpic->isu_mask;
+
+ _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
+ reg + (idx * MPIC_IRQ_STRIDE), value);
+}
+
+#define mpic_read(b,r) _mpic_read(mpic->flags &
MPIC_BIG_ENDIAN,(b),(r))
+#define mpic_write(b,r,v) _mpic_write(mpic->flags &
MPIC_BIG_ENDIAN,(b),(r),(v))
+#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i))
+#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v))
+#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i))
+#define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v))
+#define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r))
+#define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v))
+
+
+/*
+ * Low level utility functions
+ */
+
+
+
+/* Check if we have one of those nice broken MPICs with a flipped endian on
+ * reads from IPI registers
+ */
+static void __init mpic_test_broken_ipi(struct mpic *mpic)
+{
+ u32 r;
+
+ mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0, MPIC_VECPRI_MASK);
+ r = mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0);
+
+ if (r == le32_to_cpu(MPIC_VECPRI_MASK)) {
+ printk(KERN_INFO "mpic: Detected reversed IPI registers\n");
+ mpic->flags |= MPIC_BROKEN_IPI;
+ }
+}
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+
+/* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
+ * to force the edge setting on the MPIC and do the ack workaround.
+ */
+static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
+{
+ if (source >= 128 || !mpic->fixups)
+ return 0;
+ return mpic->fixups[source].base != NULL;
+}
+
+
+static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source)
+{
+ struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+
+ if (fixup->applebase) {
+ unsigned int soff = (fixup->index >> 3) & ~3;
+ unsigned int mask = 1U << (fixup->index & 0x1f);
+ writel(mask, fixup->applebase + soff);
+ } else {
+ spin_lock(&mpic->fixup_lock);
+ writeb(0x11 + 2 * fixup->index, fixup->base + 2);
+ writel(fixup->data, fixup->base + 4);
+ spin_unlock(&mpic->fixup_lock);
+ }
+}
+
+static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
+ unsigned int irqflags)
+{
+ struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+ unsigned long flags;
+ u32 tmp;
+
+ if (fixup->base == NULL)
+ return;
+
+ DBG("startup_ht_interrupt(%u, %u) index: %d\n",
+ source, irqflags, fixup->index);
+ spin_lock_irqsave(&mpic->fixup_lock, flags);
+ /* Enable and configure */
+ writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+ tmp = readl(fixup->base + 4);
+ tmp &= ~(0x23U);
+ if (irqflags & IRQ_LEVEL)
+ tmp |= 0x22;
+ writel(tmp, fixup->base + 4);
+ spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+}
+
+static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
+ unsigned int irqflags)
+{
+ struct mpic_irq_fixup *fixup = &mpic->fixups[source];
+ unsigned long flags;
+ u32 tmp;
+
+ if (fixup->base == NULL)
+ return;
+
+ DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags);
+
+ /* Disable */
+ spin_lock_irqsave(&mpic->fixup_lock, flags);
+ writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+ tmp = readl(fixup->base + 4);
+ tmp |= 1;
+ writel(tmp, fixup->base + 4);
+ spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+}
+
+static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
+ unsigned int devfn, u32 vdid)
+{
+ int i, irq, n;
+ u8 __iomem *base;
+ u32 tmp;
+ u8 pos;
+
+ for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
+ pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
+ u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
+ if (id == PCI_CAP_ID_HT_IRQCONF) {
+ id = readb(devbase + pos + 3);
+ if (id == 0x80)
+ break;
+ }
+ }
+ if (pos == 0)
+ return;
+
+ base = devbase + pos;
+ writeb(0x01, base + 2);
+ n = (readl(base + 4) >> 16) & 0xff;
+
+ printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x"
+ " has %d irqs\n",
+ devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1);
+
+ for (i = 0; i <= n; i++) {
+ writeb(0x10 + 2 * i, base + 2);
+ tmp = readl(base + 4);
+ irq = (tmp >> 16) & 0xff;
+ DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp);
+ /* mask it , will be unmasked later */
+ tmp |= 0x1;
+ writel(tmp, base + 4);
+ mpic->fixups[irq].index = i;
+ mpic->fixups[irq].base = base;
+ /* Apple HT PIC has a non-standard way of doing EOIs */
+ if ((vdid & 0xffff) == 0x106b)
+ mpic->fixups[irq].applebase = devbase + 0x60;
+ else
+ mpic->fixups[irq].applebase = NULL;
+ writeb(0x11 + 2 * i, base + 2);
+ mpic->fixups[irq].data = readl(base + 4) | 0x80000000;
+ }
+}
+
+
+static void __init mpic_scan_ht_pics(struct mpic *mpic)
+{
+ unsigned int devfn;
+ u8 __iomem *cfgspace;
+
+ printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n");
+
+ /* Allocate fixups array */
+ mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
+ BUG_ON(mpic->fixups == NULL);
+ memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup));
+
+ /* Init spinlock */
+ spin_lock_init(&mpic->fixup_lock);
+
+ /* Map U3 config space. We assume all IO-APICs are on the primary bus
+ * so we only need to map 64kB.
+ */
+ cfgspace = ioremap(0xf2000000, 0x10000);
+ BUG_ON(cfgspace == NULL);
+
+ /* Now we scan all slots. We do a very quick scan, we read the header
+ * type, vendor ID and device ID only, that's plenty enough
+ */
+ for (devfn = 0; devfn < 0x100; devfn++) {
+ u8 __iomem *devbase = cfgspace + (devfn << 8);
+ u8 hdr_type = readb(devbase + PCI_HEADER_TYPE);
+ u32 l = readl(devbase + PCI_VENDOR_ID);
+ u16 s;
+
+ DBG("devfn %x, l: %x\n", devfn, l);
+
+ /* If no device, skip */
+ if (l == 0xffffffff || l == 0x00000000 ||
+ l == 0x0000ffff || l == 0xffff0000)
+ goto next;
+ /* Check if is supports capability lists */
+ s = readw(devbase + PCI_STATUS);
+ if (!(s & PCI_STATUS_CAP_LIST))
+ goto next;
+
+ mpic_scan_ht_pic(mpic, devbase, devfn, l);
+
+ next:
+ /* next device, if function 0 */
+ if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0)
+ devfn += 7;
+ }
+}
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+
+/* Find an mpic associated with a given linux interrupt */
+static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi)
+{
+ struct mpic *mpic = mpics;
+
+ while(mpic) {
+ /* search IPIs first since they may override the main
interrupts */
+ if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) {
+ if (is_ipi)
+ *is_ipi = 1;
+ return mpic;
+ }
+ if (irq >= mpic->irq_offset &&
+ irq < (mpic->irq_offset + mpic->irq_count)) {
+ if (is_ipi)
+ *is_ipi = 0;
+ return mpic;
+ }
+ mpic = mpic -> next;
+ }
+ return NULL;
+}
+
+/* Convert a cpu mask from logical to physical cpu numbers. */
+static inline u32 mpic_physmask(u32 cpumask)
+{
+ int i;
+ u32 mask = 0;
+
+ for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
+ mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
+ return mask;
+}
+
+#ifdef CONFIG_SMP
+/* Get the mpic structure from the IPI number */
+static inline struct mpic * mpic_from_ipi(unsigned int ipi)
+{
+ return container_of(irq_desc[ipi].handler, struct mpic, hc_ipi);
+}
+#endif
+
+/* Get the mpic structure from the irq number */
+static inline struct mpic * mpic_from_irq(unsigned int irq)
+{
+ return container_of(irq_desc[irq].handler, struct mpic, hc_irq);
+}
+
+/* Send an EOI */
+static inline void mpic_eoi(struct mpic *mpic)
+{
+ mpic_cpu_write(MPIC_CPU_EOI, 0);
+ (void)mpic_cpu_read(MPIC_CPU_WHOAMI);
+}
+
+#ifdef CONFIG_SMP
+static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct cpu_user_regs
/* pt_regs */ *regs)
+{
+ struct mpic *mpic = dev_id;
+
+ smp_message_recv(irq - mpic->ipi_offset, regs);
+ return IRQ_HANDLED;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * Linux descriptor level callbacks
+ */
+
+
+static void mpic_enable_irq(unsigned int irq)
+{
+ unsigned int loops = 100000;
+ struct mpic *mpic = mpic_from_irq(irq);
+ unsigned int src = irq - mpic->irq_offset;
+
+ DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
+
+ mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
+ mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
+ ~MPIC_VECPRI_MASK);
+
+ /* make sure mask gets to controller before we return to user */
+ do {
+ if (!loops--) {
+ printk(KERN_ERR "mpic_enable_irq timeout\n");
+ break;
+ }
+ } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+ if (mpic->flags & MPIC_BROKEN_U3) {
+ unsigned int src = irq - mpic->irq_offset;
+ if (mpic_is_ht_interrupt(mpic, src) &&
+ (irq_desc[irq].status & IRQ_LEVEL))
+ mpic_ht_end_irq(mpic, src);
+ }
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+}
+
+static unsigned int mpic_startup_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+ struct mpic *mpic = mpic_from_irq(irq);
+ unsigned int src = irq - mpic->irq_offset;
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+ mpic_enable_irq(irq);
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+ if (mpic_is_ht_interrupt(mpic, src))
+ mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+ return 0;
+}
+
+static void mpic_disable_irq(unsigned int irq)
+{
+ unsigned int loops = 100000;
+ struct mpic *mpic = mpic_from_irq(irq);
+ unsigned int src = irq - mpic->irq_offset;
+
+ DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
+
+ mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
+ mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
+ MPIC_VECPRI_MASK);
+
+ /* make sure mask gets to controller before we return to user */
+ do {
+ if (!loops--) {
+ printk(KERN_ERR "mpic_enable_irq timeout\n");
+ break;
+ }
+ } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
+}
+
+static void mpic_shutdown_irq(unsigned int irq)
+{
+#ifdef CONFIG_MPIC_BROKEN_U3
+ struct mpic *mpic = mpic_from_irq(irq);
+ unsigned int src = irq - mpic->irq_offset;
+
+ if (mpic_is_ht_interrupt(mpic, src))
+ mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+ mpic_disable_irq(irq);
+}
+
+static void mpic_end_irq(unsigned int irq)
+{
+ struct mpic *mpic = mpic_from_irq(irq);
+
+#ifdef DEBUG_IRQ
+ DBG("%s: end_irq: %d\n", mpic->name, irq);
+#endif
+ /* We always EOI on end_irq() even for edge interrupts since that
+ * should only lower the priority, the MPIC should have properly
+ * latched another edge interrupt coming in anyway
+ */
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+ if (mpic->flags & MPIC_BROKEN_U3) {
+ unsigned int src = irq - mpic->irq_offset;
+ if (mpic_is_ht_interrupt(mpic, src) &&
+ (irq_desc[irq].status & IRQ_LEVEL))
+ mpic_ht_end_irq(mpic, src);
+ }
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+ mpic_eoi(mpic);
+}
+
+#ifdef CONFIG_SMP
+
+static void mpic_enable_ipi(unsigned int irq)
+{
+ struct mpic *mpic = mpic_from_ipi(irq);
+ unsigned int src = irq - mpic->ipi_offset;
+
+ DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
+ mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
+}
+
+static void mpic_disable_ipi(unsigned int irq)
+{
+ /* NEVER disable an IPI... that's just plain wrong! */
+}
+
+static void mpic_end_ipi(unsigned int irq)
+{
+ struct mpic *mpic = mpic_from_ipi(irq);
+
+ /*
+ * IPIs are marked IRQ_PER_CPU. This has the side effect of
+ * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
+ * applying to them. We EOI them late to avoid re-entering.
+ * We mark IPI's with SA_INTERRUPT as they must run with
+ * irqs disabled.
+ */
+ mpic_eoi(mpic);
+}
+
+#endif /* CONFIG_SMP */
+
+static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
+{
+ struct mpic *mpic = mpic_from_irq(irq);
+
+ cpumask_t tmp;
+
+ cpus_and(tmp, cpumask, cpu_online_map);
+
+ mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION,
+ mpic_physmask(cpus_addr(tmp)[0]));
+}
+
+
+/*
+ * Exported functions
+ */
+
+
+struct mpic * __init mpic_alloc(unsigned long phys_addr,
+ unsigned int flags,
+ unsigned int isu_size,
+ unsigned int irq_offset,
+ unsigned int irq_count,
+ unsigned int ipi_offset,
+ unsigned char *senses,
+ unsigned int senses_count,
+ const char *name)
+{
+ struct mpic *mpic;
+ u32 reg;
+ const char *vers;
+ int i;
+
+ mpic = alloc_bootmem(sizeof(struct mpic));
+ if (mpic == NULL)
+ return NULL;
+
+
+ memset(mpic, 0, sizeof(struct mpic));
+ mpic->name = name;
+
+ mpic->hc_irq.typename = name;
+ mpic->hc_irq.startup = mpic_startup_irq;
+ mpic->hc_irq.shutdown = mpic_shutdown_irq;
+ mpic->hc_irq.enable = mpic_enable_irq;
+ mpic->hc_irq.disable = mpic_disable_irq;
+ mpic->hc_irq.end = mpic_end_irq;
+ if (flags & MPIC_PRIMARY)
+ mpic->hc_irq.set_affinity = mpic_set_affinity;
+#ifdef CONFIG_SMP
+ mpic->hc_ipi.typename = name;
+ mpic->hc_ipi.enable = mpic_enable_ipi;
+ mpic->hc_ipi.disable = mpic_disable_ipi;
+ mpic->hc_ipi.end = mpic_end_ipi;
+#endif /* CONFIG_SMP */
+
+ mpic->flags = flags;
+ mpic->isu_size = isu_size;
+ mpic->irq_offset = irq_offset;
+ mpic->irq_count = irq_count;
+ mpic->ipi_offset = ipi_offset;
+ mpic->num_sources = 0; /* so far */
+ mpic->senses = senses;
+ mpic->senses_count = senses_count;
+
+ /* Map the global registers */
+ mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000);
+ mpic->tmregs = mpic->gregs + ((MPIC_TIMER_BASE - MPIC_GREG_BASE) >> 2);
+ BUG_ON(mpic->gregs == NULL);
+
+ /* Reset */
+ if (flags & MPIC_WANTS_RESET) {
+ mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
+ mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+ | MPIC_GREG_GCONF_RESET);
+ while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+ & MPIC_GREG_GCONF_RESET)
+ mb();
+ }
+
+ /* Read feature register, calculate num CPUs and, for non-ISU
+ * MPICs, num sources as well. On ISU MPICs, sources are counted
+ * as ISUs are added
+ */
+ reg = mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0);
+ mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK)
+ >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1;
+ if (isu_size == 0)
+ mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK)
+ >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
+
+ /* Map the per-CPU registers */
+ for (i = 0; i < mpic->num_cpus; i++) {
+ mpic->cpuregs[i] = ioremap(phys_addr + MPIC_CPU_BASE +
+ i * MPIC_CPU_STRIDE, 0x1000);
+ BUG_ON(mpic->cpuregs[i] == NULL);
+ }
+
+ /* Initialize main ISU if none provided */
+ if (mpic->isu_size == 0) {
+ mpic->isu_size = mpic->num_sources;
+ mpic->isus[0] = ioremap(phys_addr + MPIC_IRQ_BASE,
+ MPIC_IRQ_STRIDE * mpic->isu_size);
+ BUG_ON(mpic->isus[0] == NULL);
+ }
+ mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
+ mpic->isu_mask = (1 << mpic->isu_shift) - 1;
+
+ /* Display version */
+ switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) {
+ case 1:
+ vers = "1.0";
+ break;
+ case 2:
+ vers = "1.2";
+ break;
+ case 3:
+ vers = "1.3";
+ break;
+ default:
+ vers = "<unknown>";
+ break;
+ }
+ printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max
%d CPUs\n",
+ name, vers, phys_addr, mpic->num_cpus);
+ printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n",
mpic->isu_size,
+ mpic->isu_shift, mpic->isu_mask);
+
+ mpic->next = mpics;
+ mpics = mpic;
+
+ if (flags & MPIC_PRIMARY)
+ mpic_primary = mpic;
+
+ return mpic;
+}
+
+void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
+ unsigned long phys_addr)
+{
+ unsigned int isu_first = isu_num * mpic->isu_size;
+
+ BUG_ON(isu_num >= MPIC_MAX_ISU);
+
+ mpic->isus[isu_num] = ioremap(phys_addr, MPIC_IRQ_STRIDE *
mpic->isu_size);
+ if ((isu_first + mpic->isu_size) > mpic->num_sources)
+ mpic->num_sources = isu_first + mpic->isu_size;
+}
+
+void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler,
+ void *data)
+{
+ struct mpic *mpic = mpic_find(irq, NULL);
+ unsigned long flags;
+
+ /* Synchronization here is a bit dodgy, so don't try to replace cascade
+ * interrupts on the fly too often ... but normally it's set up at boot.
+ */
+ spin_lock_irqsave(&mpic_lock, flags);
+ if (mpic->cascade)
+ mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset);
+ mpic->cascade = NULL;
+ wmb();
+ mpic->cascade_vec = irq - mpic->irq_offset;
+ mpic->cascade_data = data;
+ wmb();
+ mpic->cascade = handler;
+ mpic_enable_irq(irq);
+ spin_unlock_irqrestore(&mpic_lock, flags);
+}
+
+void __init mpic_init(struct mpic *mpic)
+{
+ int i;
+
+ BUG_ON(mpic->num_sources == 0);
+
+ printk(KERN_INFO "mpic: Initializing for %d sources\n",
mpic->num_sources);
+
+ /* Set current processor priority to max */
+ mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+
+ /* Initialize timers: just disable them all */
+ for (i = 0; i < 4; i++) {
+ mpic_write(mpic->tmregs,
+ i * MPIC_TIMER_STRIDE + MPIC_TIMER_DESTINATION, 0);
+ mpic_write(mpic->tmregs,
+ i * MPIC_TIMER_STRIDE + MPIC_TIMER_VECTOR_PRI,
+ MPIC_VECPRI_MASK |
+ (MPIC_VEC_TIMER_0 + i));
+ }
+
+ /* Initialize IPIs to our reserved vectors and mark them disabled for
now */
+ mpic_test_broken_ipi(mpic);
+ for (i = 0; i < 4; i++) {
+ mpic_ipi_write(i,
+ MPIC_VECPRI_MASK |
+ (10 << MPIC_VECPRI_PRIORITY_SHIFT) |
+ (MPIC_VEC_IPI_0 + i));
+#ifdef CONFIG_SMP
+ if (!(mpic->flags & MPIC_PRIMARY))
+ continue;
+ irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU;
+ irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi;
+#endif /* CONFIG_SMP */
+ }
+
+ /* Initialize interrupt sources */
+ if (mpic->irq_count == 0)
+ mpic->irq_count = mpic->num_sources;
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+ /* Do the HT PIC fixups on U3 broken mpic */
+ DBG("MPIC flags: %x\n", mpic->flags);
+ if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
+ mpic_scan_ht_pics(mpic);
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+ for (i = 0; i < mpic->num_sources; i++) {
+ /* start with vector = source number, and masked */
+ u32 vecpri = MPIC_VECPRI_MASK | i | (8 <<
MPIC_VECPRI_PRIORITY_SHIFT);
+ int level = 0;
+
+ /* if it's an IPI, we skip it */
+ if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) &&
+ (mpic->irq_offset + i) < (mpic->ipi_offset + i + 4))
+ continue;
+
+ /* do senses munging */
+ if (mpic->senses && i < mpic->senses_count) {
+ if (mpic->senses[i] & IRQ_SENSE_LEVEL)
+ vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+ if (mpic->senses[i] & IRQ_POLARITY_POSITIVE)
+ vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+ } else
+ vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+
+ /* remember if it was a level interrupts */
+ level = (vecpri & MPIC_VECPRI_SENSE_LEVEL);
+
+ /* deal with broken U3 */
+ if (mpic->flags & MPIC_BROKEN_U3) {
+#ifdef CONFIG_MPIC_BROKEN_U3
+ if (mpic_is_ht_interrupt(mpic, i)) {
+ vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
+ MPIC_VECPRI_POLARITY_MASK);
+ vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+ }
+#else
+ printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG
doesn't match\n");
+#endif
+ }
+ DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri,
+ (level != 0));
+
+ /* init hw */
+ mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
+ mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+ 1 << hard_smp_processor_id());
+
+ /* init linux descriptors */
+ if (i < mpic->irq_count) {
+ irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL
: 0;
+ irq_desc[mpic->irq_offset+i].handler = &mpic->hc_irq;
+ }
+ }
+
+ /* Init spurrious vector */
+ mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS);
+
+ /* Disable 8259 passthrough */
+ mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
+ mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+ | MPIC_GREG_GCONF_8259_PTHROU_DIS);
+
+ /* Set current processor priority to 0 */
+ mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+}
+
+
+
+void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
+{
+ int is_ipi;
+ struct mpic *mpic = mpic_find(irq, &is_ipi);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&mpic_lock, flags);
+ if (is_ipi) {
+ reg = mpic_ipi_read(irq - mpic->ipi_offset) &
+ ~MPIC_VECPRI_PRIORITY_MASK;
+ mpic_ipi_write(irq - mpic->ipi_offset,
+ reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
+ } else {
+ reg = mpic_irq_read(irq - mpic->irq_offset,MPIC_IRQ_VECTOR_PRI)
+ & ~MPIC_VECPRI_PRIORITY_MASK;
+ mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI,
+ reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
+ }
+ spin_unlock_irqrestore(&mpic_lock, flags);
+}
+
+unsigned int mpic_irq_get_priority(unsigned int irq)
+{
+ int is_ipi;
+ struct mpic *mpic = mpic_find(irq, &is_ipi);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&mpic_lock, flags);
+ if (is_ipi)
+ reg = mpic_ipi_read(irq - mpic->ipi_offset);
+ else
+ reg = mpic_irq_read(irq - mpic->irq_offset,
MPIC_IRQ_VECTOR_PRI);
+ spin_unlock_irqrestore(&mpic_lock, flags);
+ return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT;
+}
+
+void mpic_setup_this_cpu(void)
+{
+#ifdef CONFIG_SMP
+ struct mpic *mpic = mpic_primary;
+ unsigned long flags;
+ u32 msk = 1 << hard_smp_processor_id();
+ unsigned int i;
+
+ BUG_ON(mpic == NULL);
+
+ DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id());
+
+ spin_lock_irqsave(&mpic_lock, flags);
+
+ /* let the mpic know we want intrs. default affinity is 0xffffffff
+ * until changed via /proc. That's how it's done on x86. If we want
+ * it differently, then we should make sure we also change the default
+ * values of irq_affinity in irq.c.
+ */
+ if (distribute_irqs) {
+ for (i = 0; i < mpic->num_sources ; i++)
+ mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+ mpic_irq_read(i, MPIC_IRQ_DESTINATION) | msk);
+ }
+
+ /* Set current processor priority to 0 */
+ mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+
+ spin_unlock_irqrestore(&mpic_lock, flags);
+#endif /* CONFIG_SMP */
+}
+
+int mpic_cpu_get_priority(void)
+{
+ struct mpic *mpic = mpic_primary;
+
+ return mpic_cpu_read(MPIC_CPU_CURRENT_TASK_PRI);
+}
+
+void mpic_cpu_set_priority(int prio)
+{
+ struct mpic *mpic = mpic_primary;
+
+ prio &= MPIC_CPU_TASKPRI_MASK;
+ mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, prio);
+}
+
+/*
+ * XXX: someone who knows mpic should check this.
+ * do we need to eoi the ipi including for kexec cpu here (see xics comments)?
+ * or can we reset the mpic in the new kernel?
+ */
+void mpic_teardown_this_cpu(int secondary)
+{
+ struct mpic *mpic = mpic_primary;
+ unsigned long flags;
+ u32 msk = 1 << hard_smp_processor_id();
+ unsigned int i;
+
+ BUG_ON(mpic == NULL);
+
+ DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id());
+ spin_lock_irqsave(&mpic_lock, flags);
+
+ /* let the mpic know we don't want intrs. */
+ for (i = 0; i < mpic->num_sources ; i++)
+ mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+ mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk);
+
+ /* Set current processor priority to max */
+ mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+
+ spin_unlock_irqrestore(&mpic_lock, flags);
+}
+
+
+void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
+{
+ struct mpic *mpic = mpic_primary;
+
+ BUG_ON(mpic == NULL);
+
+#ifdef DEBUG_IPI
+ DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
+#endif
+
+ mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
+ mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
+}
+
+int mpic_get_one_irq(struct mpic *mpic, struct cpu_user_regs /* pt_regs */
*regs)
+{
+ u32 irq;
+
+ irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
+#ifdef DEBUG_LOW
+ DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
+#endif
+ if (mpic->cascade && irq == mpic->cascade_vec) {
+#ifdef DEBUG_LOW
+ DBG("%s: cascading ...\n", mpic->name);
+#endif
+ irq = mpic->cascade(regs, mpic->cascade_data);
+ mpic_eoi(mpic);
+ return irq;
+ }
+ if (unlikely(irq == MPIC_VEC_SPURRIOUS))
+ return -1;
+ if (irq < MPIC_VEC_IPI_0) {
+#ifdef DEBUG_IRQ
+ DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset);
+#endif
+ return irq + mpic->irq_offset;
+ }
+#ifdef DEBUG_IPI
+ DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0);
+#endif
+ return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
+}
+
+int mpic_get_irq(struct cpu_user_regs /* pt_regs */ *regs)
+{
+ struct mpic *mpic = mpic_primary;
+
+ BUG_ON(mpic == NULL);
+
+ return mpic_get_one_irq(mpic, regs);
+}
+
+
+#ifdef CONFIG_SMP
+void mpic_request_ipis(void)
+{
+ struct mpic *mpic = mpic_primary;
+
+ BUG_ON(mpic == NULL);
+
+ printk("requesting IPIs ... \n");
+
+ /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
+ request_irq(mpic->ipi_offset+0, mpic_ipi_action, SA_INTERRUPT,
+ "IPI0 (call function)", mpic);
+ request_irq(mpic->ipi_offset+1, mpic_ipi_action, SA_INTERRUPT,
+ "IPI1 (reschedule)", mpic);
+ request_irq(mpic->ipi_offset+2, mpic_ipi_action, SA_INTERRUPT,
+ "IPI2 (unused)", mpic);
+ request_irq(mpic->ipi_offset+3, mpic_ipi_action, SA_INTERRUPT,
+ "IPI3 (debugger break)", mpic);
+
+ printk("IPIs requested... \n");
+}
+
+void smp_mpic_message_pass(int target, int msg)
+{
+ /* make sure we're sending something that translates to an IPI */
+ if ((unsigned int)msg > 3) {
+ printk("SMP %d: smp_message_pass: unknown msg %d\n",
+ smp_processor_id(), msg);
+ return;
+ }
+ switch (target) {
+ case MSG_ALL:
+ mpic_send_ipi(msg, 0xffffffff);
+ break;
+ case MSG_ALL_BUT_SELF:
+ mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id()));
+ break;
+ default:
+ mpic_send_ipi(msg, 1 << target);
+ break;
+ }
+}
+#endif /* CONFIG_SMP */
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/include/asm-ppc/mpic.h
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/xen/include/asm-ppc/mpic.h Fri Mar 24 17:50:52 2006 -0500
@@ -0,0 +1,292 @@
+#ifndef _ASM_POWERPC_MPIC_H
+#define _ASM_POWERPC_MPIC_H
+//#ifdef __KERNEL__
+
+//#include <linux/irq.h>
+#include <xen/irq.h>
+
+/*
+ * Global registers
+ */
+
+#define MPIC_GREG_BASE 0x01000
+
+#define MPIC_GREG_FEATURE_0 0x00000
+#define MPIC_GREG_FEATURE_LAST_SRC_MASK 0x07ff0000
+#define MPIC_GREG_FEATURE_LAST_SRC_SHIFT 16
+#define MPIC_GREG_FEATURE_LAST_CPU_MASK 0x00001f00
+#define MPIC_GREG_FEATURE_LAST_CPU_SHIFT 8
+#define MPIC_GREG_FEATURE_VERSION_MASK 0xff
+#define MPIC_GREG_FEATURE_1 0x00010
+#define MPIC_GREG_GLOBAL_CONF_0 0x00020
+#define MPIC_GREG_GCONF_RESET 0x80000000
+#define MPIC_GREG_GCONF_8259_PTHROU_DIS 0x20000000
+#define MPIC_GREG_GCONF_BASE_MASK 0x000fffff
+#define MPIC_GREG_GLOBAL_CONF_1 0x00030
+#define MPIC_GREG_VENDOR_0 0x00040
+#define MPIC_GREG_VENDOR_1 0x00050
+#define MPIC_GREG_VENDOR_2 0x00060
+#define MPIC_GREG_VENDOR_3 0x00070
+#define MPIC_GREG_VENDOR_ID 0x00080
+#define MPIC_GREG_VENDOR_ID_STEPPING_MASK 0x00ff0000
+#define MPIC_GREG_VENDOR_ID_STEPPING_SHIFT 16
+#define MPIC_GREG_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00
+#define MPIC_GREG_VENDOR_ID_DEVICE_ID_SHIFT 8
+#define MPIC_GREG_VENDOR_ID_VENDOR_ID_MASK 0x000000ff
+#define MPIC_GREG_PROCESSOR_INIT 0x00090
+#define MPIC_GREG_IPI_VECTOR_PRI_0 0x000a0
+#define MPIC_GREG_IPI_VECTOR_PRI_1 0x000b0
+#define MPIC_GREG_IPI_VECTOR_PRI_2 0x000c0
+#define MPIC_GREG_IPI_VECTOR_PRI_3 0x000d0
+#define MPIC_GREG_SPURIOUS 0x000e0
+#define MPIC_GREG_TIMER_FREQ 0x000f0
+
+/*
+ *
+ * Timer registers
+ */
+#define MPIC_TIMER_BASE 0x01100
+#define MPIC_TIMER_STRIDE 0x40
+
+#define MPIC_TIMER_CURRENT_CNT 0x00000
+#define MPIC_TIMER_BASE_CNT 0x00010
+#define MPIC_TIMER_VECTOR_PRI 0x00020
+#define MPIC_TIMER_DESTINATION 0x00030
+
+/*
+ * Per-Processor registers
+ */
+
+#define MPIC_CPU_THISBASE 0x00000
+#define MPIC_CPU_BASE 0x20000
+#define MPIC_CPU_STRIDE 0x01000
+
+#define MPIC_CPU_IPI_DISPATCH_0 0x00040
+#define MPIC_CPU_IPI_DISPATCH_1 0x00050
+#define MPIC_CPU_IPI_DISPATCH_2 0x00060
+#define MPIC_CPU_IPI_DISPATCH_3 0x00070
+#define MPIC_CPU_CURRENT_TASK_PRI 0x00080
+#define MPIC_CPU_TASKPRI_MASK 0x0000000f
+#define MPIC_CPU_WHOAMI 0x00090
+#define MPIC_CPU_WHOAMI_MASK 0x0000001f
+#define MPIC_CPU_INTACK 0x000a0
+#define MPIC_CPU_EOI 0x000b0
+
+/*
+ * Per-source registers
+ */
+
+#define MPIC_IRQ_BASE 0x10000
+#define MPIC_IRQ_STRIDE 0x00020
+#define MPIC_IRQ_VECTOR_PRI 0x00000
+#define MPIC_VECPRI_MASK 0x80000000
+#define MPIC_VECPRI_ACTIVITY 0x40000000 /* Read
Only */
+#define MPIC_VECPRI_PRIORITY_MASK 0x000f0000
+#define MPIC_VECPRI_PRIORITY_SHIFT 16
+#define MPIC_VECPRI_VECTOR_MASK 0x000007ff
+#define MPIC_VECPRI_POLARITY_POSITIVE 0x00800000
+#define MPIC_VECPRI_POLARITY_NEGATIVE 0x00000000
+#define MPIC_VECPRI_POLARITY_MASK 0x00800000
+#define MPIC_VECPRI_SENSE_LEVEL 0x00400000
+#define MPIC_VECPRI_SENSE_EDGE 0x00000000
+#define MPIC_VECPRI_SENSE_MASK 0x00400000
+#define MPIC_IRQ_DESTINATION 0x00010
+
+#define MPIC_MAX_IRQ_SOURCES 2048
+#define MPIC_MAX_CPUS 32
+#define MPIC_MAX_ISU 32
+
+/*
+ * Special vector numbers (internal use only)
+ */
+#define MPIC_VEC_SPURRIOUS 255
+#define MPIC_VEC_IPI_3 254
+#define MPIC_VEC_IPI_2 253
+#define MPIC_VEC_IPI_1 252
+#define MPIC_VEC_IPI_0 251
+
+/* unused */
+#define MPIC_VEC_TIMER_3 250
+#define MPIC_VEC_TIMER_2 249
+#define MPIC_VEC_TIMER_1 248
+#define MPIC_VEC_TIMER_0 247
+
+/* Type definition of the cascade handler */
+typedef int (*mpic_cascade_t)(struct cpu_user_regs /* pt_regs */ *regs, void
*data);
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+/* Fixup table entry */
+struct mpic_irq_fixup
+{
+ u8 __iomem *base;
+ u8 __iomem *applebase;
+ u32 data;
+ unsigned int index;
+};
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+
+/* The instance data of a given MPIC */
+struct mpic
+{
+ /* The "linux" controller struct */
+ hw_irq_controller hc_irq;
+#ifdef CONFIG_SMP
+ hw_irq_controller hc_ipi;
+#endif
+ const char *name;
+ /* Flags */
+ unsigned int flags;
+ /* How many irq sources in a given ISU */
+ unsigned int isu_size;
+ unsigned int isu_shift;
+ unsigned int isu_mask;
+ /* Offset of irq vector numbers */
+ unsigned int irq_offset;
+ unsigned int irq_count;
+ /* Offset of ipi vector numbers */
+ unsigned int ipi_offset;
+ /* Number of sources */
+ unsigned int num_sources;
+ /* Number of CPUs */
+ unsigned int num_cpus;
+ /* cascade handler */
+ mpic_cascade_t cascade;
+ void *cascade_data;
+ unsigned int cascade_vec;
+ /* senses array */
+ unsigned char *senses;
+ unsigned int senses_count;
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+ /* The fixup table */
+ struct mpic_irq_fixup *fixups;
+ spinlock_t fixup_lock;
+#endif
+
+ /* The various ioremap'ed bases */
+ volatile u32 __iomem *gregs;
+ volatile u32 __iomem *tmregs;
+ volatile u32 __iomem *cpuregs[MPIC_MAX_CPUS];
+ volatile u32 __iomem *isus[MPIC_MAX_ISU];
+
+ /* link */
+ struct mpic *next;
+};
+
+/* This is the primary controller, only that one has IPIs and
+ * has afinity control. A non-primary MPIC always uses CPU0
+ * registers only
+ */
+#define MPIC_PRIMARY 0x00000001
+/* Set this for a big-endian MPIC */
+#define MPIC_BIG_ENDIAN 0x00000002
+/* Broken U3 MPIC */
+#define MPIC_BROKEN_U3 0x00000004
+/* Broken IPI registers (autodetected) */
+#define MPIC_BROKEN_IPI 0x00000008
+/* MPIC wants a reset */
+#define MPIC_WANTS_RESET 0x00000010
+
+/* Allocate the controller structure and setup the linux irq descs
+ * for the range if interrupts passed in. No HW initialization is
+ * actually performed.
+ *
+ * @phys_addr: physial base address of the MPIC
+ * @flags: flags, see constants above
+ * @isu_size: number of interrupts in an ISU. Use 0 to use a
+ * standard ISU-less setup (aka powermac)
+ * @irq_offset: first irq number to assign to this mpic
+ * @irq_count: number of irqs to use with this mpic IRQ sources. Pass 0
+ * to match the number of sources
+ * @ipi_offset: first irq number to assign to this mpic IPI sources,
+ * used only on primary mpic
+ * @senses: array of sense values
+ * @senses_num: number of entries in the array
+ *
+ * Note about the sense array. If none is passed, all interrupts are
+ * setup to be level negative unless MPIC_BROKEN_U3 is set in which
+ * case they are edge positive (and the array is ignored anyway).
+ * The values in the array start at the first source of the MPIC,
+ * that is senses[0] correspond to linux irq "irq_offset".
+ */
+extern struct mpic *mpic_alloc(unsigned long phys_addr,
+ unsigned int flags,
+ unsigned int isu_size,
+ unsigned int irq_offset,
+ unsigned int irq_count,
+ unsigned int ipi_offset,
+ unsigned char *senses,
+ unsigned int senses_num,
+ const char *name);
+
+/* Assign ISUs, to call before mpic_init()
+ *
+ * @mpic: controller structure as returned by mpic_alloc()
+ * @isu_num: ISU number
+ * @phys_addr: physical address of the ISU
+ */
+extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
+ unsigned long phys_addr);
+
+/* Initialize the controller. After this has been called, none of the above
+ * should be called again for this mpic
+ */
+extern void mpic_init(struct mpic *mpic);
+
+/* Setup a cascade. Currently, only one cascade is supported this
+ * way, though you can always do a normal request_irq() and add
+ * other cascades this way. You should call this _after_ having
+ * added all the ISUs
+ *
+ * @irq_no: "linux" irq number of the cascade (that is offset'ed vector)
+ * @handler: cascade handler function
+ */
+extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder,
+ void *data);
+
+/*
+ * All of the following functions must only be used after the
+ * ISUs have been assigned and the controller fully initialized
+ * with mpic_init()
+ */
+
+
+/* Change/Read the priority of an interrupt. Default is 8 for irqs and
+ * 10 for IPIs. You can call this on both IPIs and IRQ numbers, but the
+ * IPI number is then the offset'ed (linux irq number mapped to the IPI)
+ */
+extern void mpic_irq_set_priority(unsigned int irq, unsigned int pri);
+extern unsigned int mpic_irq_get_priority(unsigned int irq);
+
+/* Setup a non-boot CPU */
+extern void mpic_setup_this_cpu(void);
+
+/* Clean up for kexec (or cpu offline or ...) */
+extern void mpic_teardown_this_cpu(int secondary);
+
+/* Get the current cpu priority for this cpu (0..15) */
+extern int mpic_cpu_get_priority(void);
+
+/* Set the current cpu priority for this cpu */
+extern void mpic_cpu_set_priority(int prio);
+
+/* Request IPIs on primary mpic */
+extern void mpic_request_ipis(void);
+
+/* Send an IPI (non offseted number 0..3) */
+extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask);
+
+/* Send a message (IPI) to a given target (cpu number or MSG_*) */
+void smp_mpic_message_pass(int target, int msg);
+
+/* Fetch interrupt from a given mpic */
+extern int mpic_get_one_irq(struct mpic *mpic, struct cpu_user_regs /* pt_regs
*/ *regs);
+/* This one gets to the primary mpic */
+extern int mpic_get_irq(struct cpu_user_regs /* pt_regs */ *regs);
+
+/* global mpic for pSeries */
+extern struct mpic *pSeries_mpic;
+
+//#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_MPIC_H */
diff -r 791d3b576ddf -r fd4dd4cdacbe xen/arch/ppc/external_mpic.c
--- a/xen/arch/ppc/external_mpic.c Thu Mar 23 16:19:12 2006 -0500
+++ /dev/null Thu Jan 1 00:00:00 1970 +0000
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2005 Jimi Xenidis <jimix@xxxxxxxxxxxxxx>, 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <xen/config.h>
-#include <xen/types.h>
-#include <xen/lib.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-
-#define MPIC_VEC_SPURRIOUS 0xff
-
-union emp_feature_reg {
- u32 word;
- struct {
- u32 reserved_31_27 :5;
- u32 num_IRQ :11;
- u32 reserved_16_13 :3;
- u32 num_cpu :5;
- u32 version :8;
- } bits;
-};
-
-union emp_global_config_reg {
- u32 word;
- struct {
- u32 reset :1;
- u32 reserved_30 :1;
- u32 pass_through :1;
- u32 reserved_29_20 :9;
- u32 base :20;
- } bits;
-};
-
-union emp_vendor_id_reg {
- u32 word;
- struct {
- u32 reserved_31_24 :8;
- u32 stepping :8;
- u32 device_id :8;
- u32 vendor_id :8;
- } bits;
-};
-
-union emp_int_ack {
- u32 word;
- struct {
- u32 reserved_31_16 :16;
- u32 reserved_16_11 :6;
- u32 vector :10;
- } bits;
-};
-
-static ulong emp_le = 0; /* 0 - BE, 1 - LE */
-
-static inline u32 read_reg(const u32 volatile *ptr)
-{
- if (emp_le) {
- return in_le32(ptr);
- } else {
- return in_32(ptr);
- }
-}
-
-static inline void write_reg(u32 volatile *ptr, u32 val)
-{
- if (emp_le) {
- out_le32(ptr, val);
- } else {
- out_32(ptr, val);
- }
-}
-
-struct openpic_global {
- const u32 features;
- const u8 __pad1[0x1c];
-
- u32 config;
- const u8 __pad2[0xc];
-
- const u8 __vendor_specific[0x80 - 0x30];
-
- u32 vendor_id;
- const u8 __pad3[0xc];
-
- u32 processor_init;
- const u8 __pad4[0xc];
-
- u32 ipi0_privec;
- const u8 __pad5[0xc];
-
- u32 ipi1_privec;
- const u8 __pad6[0xc];
-
- u32 ipi2_privec;
- const u8 __pad7[0xc];
-
- u32 ipi3_privec;
- const u8 __pad8[0xc];
-
- u32 spurious;
- const u8 __pad9[0xc];
-};
-
-struct openpic_cpu {
- const u8 __pad1[0x40];
- struct {
- u32 reg;
- const u32 __pad[3];
- } ipi_dispatch[4];
-
- u32 task_priority;
- const u8 __pad2[0xc];
-
- u32 who_am_i;
- const u8 __pad3[0xc];
-
- u32 intr_ack;
- const u8 __pad4[0xc];
-
- u32 eoi;
- const u8 __pad5[0xc];
-
- const u8 __pad6[0x1000 - 0xc0];
-};
-
-struct openpic {
- struct openpic_cpu local;
- struct openpic_global global;
- const u8 __pad1[0x20000 -
- sizeof (struct openpic_global) -
- sizeof (struct openpic_cpu)];
- struct openpic_cpu cpu_specific[0x20];
-};
-
-/*
- * If the external_init() is never called then we assume little-endian
- * and the following location
- */
-static struct openpic *openpic = (typeof(openpic)) 0xffc00000;
-
-void external_init(ulong base, int little_endian)
-{
- openpic = (typeof(openpic))base;
- emp_le = little_endian;
-}
-
-/*
- * this checks the exceptions from the OpenPIC controler
- */
-static int external_get_one_irq(void)
-{
- union emp_int_ack emp_vec;
- int cpu = 0;
- int port;
-
- emp_vec.word = read_reg(&openpic->cpu_specific[cpu].intr_ack);
- port = emp_vec.bits.vector;
-
- if (port == MPIC_VEC_SPURRIOUS) {
- port = -1;
- }
-
- return port;
-}
-
-/* fill in the bit for all external interrupts, if any port is
- * unmasked then return 1 */
-int external_get_irq(ulong *irqp, ulong *maskp, uint64_t *selp, int irqs)
-{
- int port;
- int pend = 0;
- int sel;
- int spurrious;
-
- /* not sure if this is optimal (or even correct) but we will
- * deliver even spurrious interrupts to dom0 */
- spurrious = 1;
- while((port = external_get_one_irq()) != -1) {
- spurrious = 0;
-
- if (port > irqs) {
- panic("OpenPIC interrupt too large for bitop\n");
- }
- /* Xen always uses sychronized bitops */
- set_bit(port, irqp);
-
- sel = port / 8 / sizeof(ulong);
- set_bit(sel, selp);
-
- pend += !test_bit(port, maskp);
- }
- return pend + spurrious;
-}
_______________________________________________
Xen-ppc-devel mailing list
Xen-ppc-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ppc-devel
|