[go: nahoru, domu]

1/*
2 * Meta internal (HWSTATMETA) interrupt code.
3 *
4 * Copyright (C) 2011-2012 Imagination Technologies Ltd.
5 *
6 * This code is based on the code in SoC/common/irq.c and SoC/comet/irq.c
7 * The code base could be generalised/merged as a lot of the functionality is
8 * similar. Until this is done, we try to keep the code simple here.
9 */
10
11#include <linux/interrupt.h>
12#include <linux/io.h>
13#include <linux/irqdomain.h>
14
15#include <asm/irq.h>
16#include <asm/hwthread.h>
17
18#define PERF0VECINT		0x04820580
19#define PERF1VECINT		0x04820588
20#define PERF0TRIG_OFFSET	16
21#define PERF1TRIG_OFFSET	17
22
23/**
24 * struct metag_internal_irq_priv - private meta internal interrupt data
25 * @domain:		IRQ domain for all internal Meta IRQs (HWSTATMETA)
26 * @unmasked:		Record of unmasked IRQs
27 */
28struct metag_internal_irq_priv {
29	struct irq_domain	*domain;
30
31	unsigned long		unmasked;
32};
33
34/* Private data for the one and only internal interrupt controller */
35static struct metag_internal_irq_priv metag_internal_irq_priv;
36
37static unsigned int metag_internal_irq_startup(struct irq_data *data);
38static void metag_internal_irq_shutdown(struct irq_data *data);
39static void metag_internal_irq_ack(struct irq_data *data);
40static void metag_internal_irq_mask(struct irq_data *data);
41static void metag_internal_irq_unmask(struct irq_data *data);
42#ifdef CONFIG_SMP
43static int metag_internal_irq_set_affinity(struct irq_data *data,
44			const struct cpumask *cpumask, bool force);
45#endif
46
47static struct irq_chip internal_irq_edge_chip = {
48	.name = "HWSTATMETA-IRQ",
49	.irq_startup = metag_internal_irq_startup,
50	.irq_shutdown = metag_internal_irq_shutdown,
51	.irq_ack = metag_internal_irq_ack,
52	.irq_mask = metag_internal_irq_mask,
53	.irq_unmask = metag_internal_irq_unmask,
54#ifdef CONFIG_SMP
55	.irq_set_affinity = metag_internal_irq_set_affinity,
56#endif
57};
58
59/*
60 *	metag_hwvec_addr - get the address of *VECINT regs of irq
61 *
62 *	This function is a table of supported triggers on HWSTATMETA
63 *	Could do with a structure, but better keep it simple. Changes
64 *	in this code should be rare.
65 */
66static inline void __iomem *metag_hwvec_addr(irq_hw_number_t hw)
67{
68	void __iomem *addr;
69
70	switch (hw) {
71	case PERF0TRIG_OFFSET:
72		addr = (void __iomem *)PERF0VECINT;
73		break;
74	case PERF1TRIG_OFFSET:
75		addr = (void __iomem *)PERF1VECINT;
76		break;
77	default:
78		addr = NULL;
79		break;
80	}
81	return addr;
82}
83
84/*
85 *	metag_internal_startup - setup an internal irq
86 *	@irq:	the irq to startup
87 *
88 *	Multiplex interrupts for @irq onto TR1. Clear any pending
89 *	interrupts.
90 */
91static unsigned int metag_internal_irq_startup(struct irq_data *data)
92{
93	/* Clear (toggle) the bit in HWSTATMETA for our interrupt. */
94	metag_internal_irq_ack(data);
95
96	/* Enable the interrupt by unmasking it */
97	metag_internal_irq_unmask(data);
98
99	return 0;
100}
101
102/*
103 *	metag_internal_irq_shutdown - turn off the irq
104 *	@irq:	the irq number to turn off
105 *
106 *	Mask @irq and clear any pending interrupts.
107 *	Stop muxing @irq onto TR1.
108 */
109static void metag_internal_irq_shutdown(struct irq_data *data)
110{
111	/* Disable the IRQ at the core by masking it. */
112	metag_internal_irq_mask(data);
113
114	/* Clear (toggle) the bit in HWSTATMETA for our interrupt. */
115	metag_internal_irq_ack(data);
116}
117
118/*
119 *	metag_internal_irq_ack - acknowledge irq
120 *	@irq:	the irq to ack
121 */
122static void metag_internal_irq_ack(struct irq_data *data)
123{
124	irq_hw_number_t hw = data->hwirq;
125	unsigned int bit = 1 << hw;
126
127	if (metag_in32(HWSTATMETA) & bit)
128		metag_out32(bit, HWSTATMETA);
129}
130
131/**
132 * metag_internal_irq_mask() - mask an internal irq by unvectoring
133 * @data:	data for the internal irq to mask
134 *
135 * HWSTATMETA has no mask register. Instead the IRQ is unvectored from the core
136 * and retriggered if necessary later.
137 */
138static void metag_internal_irq_mask(struct irq_data *data)
139{
140	struct metag_internal_irq_priv *priv = &metag_internal_irq_priv;
141	irq_hw_number_t hw = data->hwirq;
142	void __iomem *vec_addr = metag_hwvec_addr(hw);
143
144	clear_bit(hw, &priv->unmasked);
145
146	/* there is no interrupt mask, so unvector the interrupt */
147	metag_out32(0, vec_addr);
148}
149
150/**
151 * meta_intc_unmask_edge_irq_nomask() - unmask an edge irq by revectoring
152 * @data:	data for the internal irq to unmask
153 *
154 * HWSTATMETA has no mask register. Instead the IRQ is revectored back to the
155 * core and retriggered if necessary.
156 */
157static void metag_internal_irq_unmask(struct irq_data *data)
158{
159	struct metag_internal_irq_priv *priv = &metag_internal_irq_priv;
160	irq_hw_number_t hw = data->hwirq;
161	unsigned int bit = 1 << hw;
162	void __iomem *vec_addr = metag_hwvec_addr(hw);
163	unsigned int thread = hard_processor_id();
164
165	set_bit(hw, &priv->unmasked);
166
167	/* there is no interrupt mask, so revector the interrupt */
168	metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)), vec_addr);
169
170	/*
171	 * Re-trigger interrupt
172	 *
173	 * Writing a 1 toggles, and a 0->1 transition triggers. We only
174	 * retrigger if the status bit is already set, which means we
175	 * need to clear it first. Retriggering is fundamentally racy
176	 * because if the interrupt fires again after we clear it we
177	 * could end up clearing it again and the interrupt handler
178	 * thinking it hasn't fired. Therefore we need to keep trying to
179	 * retrigger until the bit is set.
180	 */
181	if (metag_in32(HWSTATMETA) & bit) {
182		metag_out32(bit, HWSTATMETA);
183		while (!(metag_in32(HWSTATMETA) & bit))
184			metag_out32(bit, HWSTATMETA);
185	}
186}
187
188#ifdef CONFIG_SMP
189/*
190 *	metag_internal_irq_set_affinity - set the affinity for an interrupt
191 */
192static int metag_internal_irq_set_affinity(struct irq_data *data,
193			const struct cpumask *cpumask, bool force)
194{
195	unsigned int cpu, thread;
196	irq_hw_number_t hw = data->hwirq;
197	/*
198	 * Wire up this interrupt from *VECINT to the Meta core.
199	 *
200	 * Note that we can't wire up *VECINT to interrupt more than
201	 * one cpu (the interrupt code doesn't support it), so we just
202	 * pick the first cpu we find in 'cpumask'.
203	 */
204	cpu = cpumask_any_and(cpumask, cpu_online_mask);
205	thread = cpu_2_hwthread_id[cpu];
206
207	metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)),
208		    metag_hwvec_addr(hw));
209
210	return 0;
211}
212#endif
213
214/*
215 *	metag_internal_irq_demux - irq de-multiplexer
216 *	@irq:	the interrupt number
217 *	@desc:	the interrupt description structure for this irq
218 *
219 *	The cpu receives an interrupt on TR1 when an interrupt has
220 *	occurred. It is this function's job to demux this irq and
221 *	figure out exactly which trigger needs servicing.
222 */
223static void metag_internal_irq_demux(unsigned int irq, struct irq_desc *desc)
224{
225	struct metag_internal_irq_priv *priv = irq_desc_get_handler_data(desc);
226	irq_hw_number_t hw;
227	unsigned int irq_no;
228	u32 status;
229
230recalculate:
231	status = metag_in32(HWSTATMETA) & priv->unmasked;
232
233	for (hw = 0; status != 0; status >>= 1, ++hw) {
234		if (status & 0x1) {
235			/*
236			 * Map the hardware IRQ number to a virtual Linux IRQ
237			 * number.
238			 */
239			irq_no = irq_linear_revmap(priv->domain, hw);
240
241			/*
242			 * Only fire off interrupts that are
243			 * registered to be handled by the kernel.
244			 * Other interrupts are probably being
245			 * handled by other Meta hardware threads.
246			 */
247			generic_handle_irq(irq_no);
248
249			/*
250			 * The handler may have re-enabled interrupts
251			 * which could have caused a nested invocation
252			 * of this code and make the copy of the
253			 * status register we are using invalid.
254			 */
255			goto recalculate;
256		}
257	}
258}
259
260/**
261 * internal_irq_map() - Map an internal meta IRQ to a virtual IRQ number.
262 * @hw:		Number of the internal IRQ. Must be in range.
263 *
264 * Returns:	The virtual IRQ number of the Meta internal IRQ specified by
265 *		@hw.
266 */
267int internal_irq_map(unsigned int hw)
268{
269	struct metag_internal_irq_priv *priv = &metag_internal_irq_priv;
270	if (!priv->domain)
271		return -ENODEV;
272	return irq_create_mapping(priv->domain, hw);
273}
274
275/**
276 *	metag_internal_irq_init_cpu - regsister with the Meta cpu
277 *	@cpu:	the CPU to register on
278 *
279 *	Configure @cpu's TR1 irq so that we can demux irqs.
280 */
281static void metag_internal_irq_init_cpu(struct metag_internal_irq_priv *priv,
282					int cpu)
283{
284	unsigned int thread = cpu_2_hwthread_id[cpu];
285	unsigned int signum = TBID_SIGNUM_TR1(thread);
286	int irq = tbisig_map(signum);
287
288	/* Register the multiplexed IRQ handler */
289	irq_set_handler_data(irq, priv);
290	irq_set_chained_handler(irq, metag_internal_irq_demux);
291	irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
292}
293
294/**
295 * metag_internal_intc_map() - map an internal irq
296 * @d:		irq domain of internal trigger block
297 * @irq:	virtual irq number
298 * @hw:		hardware irq number within internal trigger block
299 *
300 * This sets up a virtual irq for a specified hardware interrupt. The irq chip
301 * and handler is configured.
302 */
303static int metag_internal_intc_map(struct irq_domain *d, unsigned int irq,
304				   irq_hw_number_t hw)
305{
306	/* only register interrupt if it is mapped */
307	if (!metag_hwvec_addr(hw))
308		return -EINVAL;
309
310	irq_set_chip_and_handler(irq, &internal_irq_edge_chip,
311				 handle_edge_irq);
312	return 0;
313}
314
315static const struct irq_domain_ops metag_internal_intc_domain_ops = {
316	.map	= metag_internal_intc_map,
317};
318
319/**
320 *	metag_internal_irq_register - register internal IRQs
321 *
322 *	Register the irq chip and handler function for all internal IRQs
323 */
324int __init init_internal_IRQ(void)
325{
326	struct metag_internal_irq_priv *priv = &metag_internal_irq_priv;
327	unsigned int cpu;
328
329	/* Set up an IRQ domain */
330	priv->domain = irq_domain_add_linear(NULL, 32,
331					     &metag_internal_intc_domain_ops,
332					     priv);
333	if (unlikely(!priv->domain)) {
334		pr_err("meta-internal-intc: cannot add IRQ domain\n");
335		return -ENOMEM;
336	}
337
338	/* Setup TR1 for all cpus. */
339	for_each_possible_cpu(cpu)
340		metag_internal_irq_init_cpu(priv, cpu);
341
342	return 0;
343};
344