ppc64: Rewrite the openpic driver
PATCH 1/1 ppc64: Rewrite the openpic driver
Hi !
This patch replaces the open_pic IRQ controller driver with a new version rewritten from scratch, called "mpic" (this is the name of IBM's open_pic implementation and also the only one actually used on any platform).
It is smaller, hopefully more readable, supports the various variants of the cell in a single driver (open_pic_u3.c is gone), and adds optional support for the workaround of U3 mpic beeing used along with IO-APICs on HyperTransport (the eval board will uses that, among others).
arch/ppc64/kernel/mpic.h new file +267 -0
@@ -0,0 +1,267 @@ +#include <linux/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 pt_regs *regs,void *data); + +#ifdef CONFIG_MPIC_BROKEN_U3 +/* Fixup table entry */ +struct mpic_irq_fixup +{ +u8 __iomem *base; +unsigned int irq; +}; +#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 ); + +/* 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); + +/* Fetch interrupt from a given mpic */ +extern int mpic_get_one_irq (struct mpic *mpic,struct pt_regs *regs); +/* This one gets to the primary mpic */ +extern int mpic_get_irq (struct pt_regs *regs);
arch/ppc64/kernel/mpic.c new file +859 -0
859 lines not on this page · raw message
include/asm-ppc64/irq.h +13 -0
@@ -20,6 +20,19 @@/* this number is used when no interrupt has been assigned */ #define NO_IRQ (-1) +/* +* These constants are used for passing information about interrupt +* signal polarity and level/edge sensing to the low-level PIC chip +* drivers. +*/ +#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 get_irq_desc (irq) (&irq_desc[(irq)])/* Define a way to iterate across irqs. */
arch/ppc64/kernel/Makefile +3 -3
@@ -28,7 +28,7 @@ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o -obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o open_pic.o i8259.o prom_init.o prom.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o mpic.o obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ eeh.o pSeries_nvram.o rtasd.o ras.o \
@@ -47,8 +47,8 @@ obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ - pmac_time.o pmac_nvram.o pmac_low_i2c.o \ - open_pic_u3.o + pmac_time.o pmac_nvram.o pmac_low_i2c.o + obj-$(CONFIG_U3_DART) += u3_iommu.o ifdef CONFIG_SMP
dev/null1970-01-01 00:00:00.000000000 +0000 renamed from arch/ppc64/kernel/open_pic_defs.h +0 -283
283 lines not on this page · raw message
dev/null1970-01-01 00:00:00.000000000 +0000 renamed from arch/ppc64/kernel/open_pic.c +0 -886
886 lines not on this page · raw message
dev/null1970-01-01 00:00:00.000000000 +0000 renamed from arch/ppc64/kernel/open_pic_u3.c +0 -348
348 lines not on this page · raw message
dev/null1970-01-01 00:00:00.000000000 +0000 renamed from arch/ppc64/kernel/open_pic.h +0 -42
42 lines not on this page · raw message
include/asm-ppc64/smp.h +4 -0
@@ -67,6 +67,10 @@extern int smt_enabled_at_boot; +extern int smp_mpic_probe (void ); +extern void smp_mpic_setup_cpu (int cpu); +extern void smp_mpic_message_pass (int target,int msg); +#endif /* __ASSEMBLY__ */ #endif /* !(_PPC64_SMP_H) */
arch/ppc64/kernel/pSeries_pci.c +4 -3
@@ -42,7 +42,7 @@#include <asm/iommu.h> #include <asm/rtas.h> -#include "open_pic.h" +#include "mpic.h" #include "pci.h" /* RTAS tokens */
@@ -54,6 +54,7 @@static int s7a_workaround;extern unsigned long pci_probe_only; +extern struct mpic *pSeries_mpic;static int rtas_read_config (struct device_node *dn,int where,int size,u32 *val) {
@@ -399,9 +400,9 @@pci_process_bridge_OF_ranges (phb, node);pci_setup_phb_io (phb, index ==0 ); -if (naca->interrupt_controller ==IC_OPEN_PIC ) { +if (naca->interrupt_controller ==IC_OPEN_PIC && pSeries_mpic) {int addr = root_size_cells * (index +2 ) -1 ; -openpic_setup_ISU (index, opprop[addr]); +mpic_assign_isu (pSeries_mpic, index, opprop[addr]); } index++;
arch/ppc64/kernel/prom_init.c +0 -1
@@ -51,7 +51,6 @@#include <asm/btext.h> #include <asm/sections.h> #include <asm/machdep.h> -#include "open_pic.h" #ifdef CONFIG_LOGO_LINUX_CLUT224 #include <linux/linux_logo.h>
arch/ppc64/kernel/pSeries_setup.c +80 -22
141 lines not on this page · raw message
arch/ppc64/kernel/pmac_smp.c +7 -7
@@ -32,6 +32,7 @@#include <linux/init.h> #include <linux/spinlock.h> #include <linux/errno.h> +#include <linux/irq.h> #include <asm/ptrace.h> #include <asm/atomic.h>
@@ -48,14 +49,13 @@#include <asm/cacheflush.h> #include <asm/keylargo.h> -#include "open_pic.h" +#include "mpic.h" +extern void pmac_secondary_start_1 (void );extern void pmac_secondary_start_2 (void );extern void pmac_secondary_start_3 (void ); -extern void smp_openpic_message_pass (int target,int msg); -extern struct smp_ops_t *smp_ops;static int __init smp_core99_probe (void )
@@ -75,7 +75,7 @@printk (KERN_INFO "PowerMac SMP probe found %d cpus\n" , ncpus);if (ncpus >1 ) -openpic_request_IPIs (); +mpic_request_ipis ();return ncpus; }
@@ -138,8 +138,8 @@static void __init smp_core99_setup_cpu (int cpu_nr) { -/* Setup openpic */ -do_openpic_setup_cpu (); +/* Setup MPIC */ +mpic_setup_this_cpu ();if (cpu_nr ==0 ) {extern void g5_phy_disable_cpu1 (void );
@@ -157,7 +157,7 @@extern void smp_generic_take_timebase (void ); struct smp_ops_t core99_smp_ops __pmacdata = { - .message_pass = smp_openpic_message_pass, + .message_pass = smp_mpic_message_pass, .probe = smp_core99_probe, .kick_cpu = smp_core99_kick_cpu, .setup_cpu = smp_core99_setup_cpu,
arch/ppc64/kernel/prom.c +4 -4
@@ -52,7 +52,6 @@#include <asm/btext.h> #include <asm/sections.h> #include <asm/machdep.h> -#include "open_pic.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt)
@@ -1092,8 +1091,7 @@* Work out the sense (active-low level / active-high edge) * of each interrupt from the device tree. */ -void __init -prom_get_irq_senses (unsigned char *senses,int off,int max) +void __init prom_get_irq_senses (unsigned char *senses,int off,int max) {struct device_node *np;int i, j;
@@ -1105,7 +1103,9 @@for (j =0 ; j < np->n_intrs; j++) { i = np->intrs[j].line;if (i >= off && i < max) - senses[i-off] = np->intrs[j].sense; + senses[i-off] = np->intrs[j].sense ? +IRQ_SENSE_LEVEL |IRQ_POLARITY_NEGATIVE : +IRQ_SENSE_EDGE |IRQ_POLARITY_POSITIVE ; } } }
arch/ppc64/kernel/pmac_setup.c +23 -48
19 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.