aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/include
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-04-03 23:46:58 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-04-19 21:02:35 -0400
commit0b05ac6e24807f0c26f763b3a546c0bcbf84125f (patch)
tree9c1a113a050583e564dcd78a7aa80fde6320d8e1 /arch/powerpc/include
parentf0e615c3cb72b42191b558c130409335812621d8 (diff)
powerpc/xics: Rewrite XICS driver
This is a significant rework of the XICS driver, too significant to conveniently break it up into a series of smaller patches to be honest. The driver is moved to a more generic location to allow new platforms to use it, and is broken up into separate ICP and ICS "backends". For now we have the native and "hypervisor" ICP backends and one common RTAS ICS backend. The driver supports one ICP backend instanciation, and many ICS ones, in order to accomodate future platforms with multiple possibly different interrupt "sources" mechanisms. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/include')
-rw-r--r--arch/powerpc/include/asm/irq.h6
-rw-r--r--arch/powerpc/include/asm/xics.h139
2 files changed, 145 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index 67ab5fb7d153..47b7905a6369 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -142,6 +142,12 @@ extern struct irq_map_entry irq_map[NR_IRQS];
142 142
143extern irq_hw_number_t virq_to_hw(unsigned int virq); 143extern irq_hw_number_t virq_to_hw(unsigned int virq);
144 144
145/* This will eventually -replace- virq_to_hw if/when we stash the
146 * HW number in the irq_data itself. We use a macro so we can inline
147 * it as irq_data isn't defined yet
148 */
149#define irq_data_to_hw(d) (irq_map[(d)->irq].hwirq)
150
145/** 151/**
146 * irq_alloc_host - Allocate a new irq_host data structure 152 * irq_alloc_host - Allocate a new irq_host data structure
147 * @of_node: optional device-tree node of the interrupt controller 153 * @of_node: optional device-tree node of the interrupt controller
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h
new file mode 100644
index 000000000000..146aad8534de
--- /dev/null
+++ b/arch/powerpc/include/asm/xics.h
@@ -0,0 +1,139 @@
1/*
2 * Common definitions accross all variants of ICP and ICS interrupt
3 * controllers.
4 */
5
6#ifndef _XICS_H
7#define _XICS_H
8
9#define XICS_IPI 2
10#define XICS_IRQ_SPURIOUS 0
11
12/* Want a priority other than 0. Various HW issues require this. */
13#define DEFAULT_PRIORITY 5
14
15/*
16 * Mark IPIs as higher priority so we can take them inside interrupts that
17 * arent marked IRQF_DISABLED
18 */
19#define IPI_PRIORITY 4
20
21/* The least favored priority */
22#define LOWEST_PRIORITY 0xFF
23
24/* The number of priorities defined above */
25#define MAX_NUM_PRIORITIES 3
26
27/* Native ICP */
28extern int icp_native_init(void);
29
30/* PAPR ICP */
31extern int icp_hv_init(void);
32
33/* ICP ops */
34struct icp_ops {
35 unsigned int (*get_irq)(void);
36 void (*eoi)(struct irq_data *d);
37 void (*set_priority)(unsigned char prio);
38 void (*teardown_cpu)(void);
39 void (*flush_ipi)(void);
40#ifdef CONFIG_SMP
41 void (*message_pass)(int target, int msg);
42 irq_handler_t ipi_action;
43#endif
44};
45
46extern const struct icp_ops *icp_ops;
47
48/* Native ICS */
49extern int ics_native_init(void);
50
51/* RTAS ICS */
52extern int ics_rtas_init(void);
53
54/* ICS instance, hooked up to chip_data of an irq */
55struct ics {
56 struct list_head link;
57 int (*map)(struct ics *ics, unsigned int virq);
58 void (*mask_unknown)(struct ics *ics, unsigned long vec);
59 long (*get_server)(struct ics *ics, unsigned long vec);
60 char data[];
61};
62
63/* Commons */
64extern unsigned int xics_default_server;
65extern unsigned int xics_default_distrib_server;
66extern unsigned int xics_interrupt_server_size;
67extern struct irq_host *xics_host;
68
69struct xics_cppr {
70 unsigned char stack[MAX_NUM_PRIORITIES];
71 int index;
72};
73
74DECLARE_PER_CPU(struct xics_cppr, xics_cppr);
75
76static inline void xics_push_cppr(unsigned int vec)
77{
78 struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
79
80 if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1))
81 return;
82
83 if (vec == XICS_IPI)
84 os_cppr->stack[++os_cppr->index] = IPI_PRIORITY;
85 else
86 os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY;
87}
88
89static inline unsigned char xics_pop_cppr(void)
90{
91 struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
92
93 if (WARN_ON(os_cppr->index < 1))
94 return LOWEST_PRIORITY;
95
96 return os_cppr->stack[--os_cppr->index];
97}
98
99static inline void xics_set_base_cppr(unsigned char cppr)
100{
101 struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
102
103 /* we only really want to set the priority when there's
104 * just one cppr value on the stack
105 */
106 WARN_ON(os_cppr->index != 0);
107
108 os_cppr->stack[0] = cppr;
109}
110
111static inline unsigned char xics_cppr_top(void)
112{
113 struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
114
115 return os_cppr->stack[os_cppr->index];
116}
117
118DECLARE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
119
120extern void xics_init(void);
121extern void xics_setup_cpu(void);
122extern void xics_update_irq_servers(void);
123extern void xics_set_cpu_giq(unsigned int gserver, unsigned int join);
124extern void xics_mask_unknown_vec(unsigned int vec);
125extern irqreturn_t xics_ipi_dispatch(int cpu);
126extern int xics_smp_probe(void);
127extern void xics_register_ics(struct ics *ics);
128extern void xics_teardown_cpu(void);
129extern void xics_kexec_teardown_cpu(int secondary);
130extern void xics_migrate_irqs_away(void);
131#ifdef CONFIG_SMP
132extern int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
133 unsigned int strict_check);
134#else
135#define xics_get_irq_server(virq, cpumask, strict_check) (xics_default_server)
136#endif
137
138
139#endif /* _XICS_H */