PageRenderTime 28ms CodeModel.GetById 13ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/parisc/kernel/irq.c

https://bitbucket.org/evzijst/gittest
C | 343 lines | 213 code | 60 blank | 70 comment | 29 complexity | 8731531a7a199400e71b1740677de272 MD5 | raw file
  1/* 
  2 * Code to handle x86 style IRQs plus some generic interrupt stuff.
  3 *
  4 * Copyright (C) 1992 Linus Torvalds
  5 * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
  6 * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
  7 * Copyright (C) 1999-2000 Grant Grundler
  8 * Copyright (c) 2005 Matthew Wilcox
  9 *
 10 *    This program is free software; you can redistribute it and/or modify
 11 *    it under the terms of the GNU General Public License as published by
 12 *    the Free Software Foundation; either version 2, or (at your option)
 13 *    any later version.
 14 *
 15 *    This program is distributed in the hope that it will be useful,
 16 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 *    GNU General Public License for more details.
 19 *
 20 *    You should have received a copy of the GNU General Public License
 21 *    along with this program; if not, write to the Free Software
 22 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 23 */
 24#include <linux/bitops.h>
 25#include <linux/config.h>
 26#include <linux/errno.h>
 27#include <linux/init.h>
 28#include <linux/interrupt.h>
 29#include <linux/kernel_stat.h>
 30#include <linux/seq_file.h>
 31#include <linux/spinlock.h>
 32#include <linux/types.h>
 33
 34#undef PARISC_IRQ_CR16_COUNTS
 35
 36extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
 37extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
 38
 39#define EIEM_MASK(irq)       (1UL<<(CPU_IRQ_MAX - irq))
 40
 41/* Bits in EIEM correlate with cpu_irq_action[].
 42** Numbered *Big Endian*! (ie bit 0 is MSB)
 43*/
 44static volatile unsigned long cpu_eiem = 0;
 45
 46static void cpu_set_eiem(void *info)
 47{
 48	set_eiem((unsigned long) info);
 49}
 50
 51static inline void cpu_disable_irq(unsigned int irq)
 52{
 53	unsigned long eirr_bit = EIEM_MASK(irq);
 54
 55	cpu_eiem &= ~eirr_bit;
 56        on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
 57}
 58
 59static void cpu_enable_irq(unsigned int irq)
 60{
 61	unsigned long eirr_bit = EIEM_MASK(irq);
 62
 63	mtctl(eirr_bit, 23);	/* clear EIRR bit before unmasking */
 64	cpu_eiem |= eirr_bit;
 65        on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
 66}
 67
 68static unsigned int cpu_startup_irq(unsigned int irq)
 69{
 70	cpu_enable_irq(irq);
 71	return 0;
 72}
 73
 74void no_ack_irq(unsigned int irq) { }
 75void no_end_irq(unsigned int irq) { }
 76
 77static struct hw_interrupt_type cpu_interrupt_type = {
 78	.typename	= "CPU",
 79	.startup	= cpu_startup_irq,
 80	.shutdown	= cpu_disable_irq,
 81	.enable		= cpu_enable_irq,
 82	.disable	= cpu_disable_irq,
 83	.ack		= no_ack_irq,
 84	.end		= no_end_irq,
 85//	.set_affinity	= cpu_set_affinity_irq,
 86};
 87
 88int show_interrupts(struct seq_file *p, void *v)
 89{
 90	int i = *(loff_t *) v, j;
 91	unsigned long flags;
 92
 93	if (i == 0) {
 94		seq_puts(p, "    ");
 95		for_each_online_cpu(j)
 96			seq_printf(p, "       CPU%d", j);
 97
 98#ifdef PARISC_IRQ_CR16_COUNTS
 99		seq_printf(p, " [min/avg/max] (CPU cycle counts)");
100#endif
101		seq_putc(p, '\n');
102	}
103
104	if (i < NR_IRQS) {
105		struct irqaction *action;
106
107		spin_lock_irqsave(&irq_desc[i].lock, flags);
108		action = irq_desc[i].action;
109		if (!action)
110			goto skip;
111		seq_printf(p, "%3d: ", i);
112#ifdef CONFIG_SMP
113		for_each_online_cpu(j)
114			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
115#else
116		seq_printf(p, "%10u ", kstat_irqs(i));
117#endif
118
119		seq_printf(p, " %14s", irq_desc[i].handler->typename);
120#ifndef PARISC_IRQ_CR16_COUNTS
121		seq_printf(p, "  %s", action->name);
122
123		while ((action = action->next))
124			seq_printf(p, ", %s", action->name);
125#else
126		for ( ;action; action = action->next) {
127			unsigned int k, avg, min, max;
128
129			min = max = action->cr16_hist[0];
130
131			for (avg = k = 0; k < PARISC_CR16_HIST_SIZE; k++) {
132				int hist = action->cr16_hist[k];
133
134				if (hist) {
135					avg += hist;
136				} else
137					break;
138
139				if (hist > max) max = hist;
140				if (hist < min) min = hist;
141			}
142
143			avg /= k;
144			seq_printf(p, " %s[%d/%d/%d]", action->name,
145					min,avg,max);
146		}
147#endif
148
149		seq_putc(p, '\n');
150 skip:
151		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
152	}
153
154	return 0;
155}
156
157
158
159/*
160** The following form a "set": Virtual IRQ, Transaction Address, Trans Data.
161** Respectively, these map to IRQ region+EIRR, Processor HPA, EIRR bit.
162**
163** To use txn_XXX() interfaces, get a Virtual IRQ first.
164** Then use that to get the Transaction address and data.
165*/
166
167int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
168{
169	if (irq_desc[irq].action)
170		return -EBUSY;
171	if (irq_desc[irq].handler != &cpu_interrupt_type)
172		return -EBUSY;
173
174	if (type) {
175		irq_desc[irq].handler = type;
176		irq_desc[irq].handler_data = data;
177		cpu_interrupt_type.enable(irq);
178	}
179	return 0;
180}
181
182int txn_claim_irq(int irq)
183{
184	return cpu_claim_irq(irq, NULL, NULL) ? -1 : irq;
185}
186
187/*
188 * The bits_wide parameter accommodates the limitations of the HW/SW which
189 * use these bits:
190 * Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register)
191 * V-class (EPIC):          6 bits
192 * N/L/A-class (iosapic):   8 bits
193 * PCI 2.2 MSI:            16 bits
194 * Some PCI devices:       32 bits (Symbios SCSI/ATM/HyperFabric)
195 *
196 * On the service provider side:
197 * o PA 1.1 (and PA2.0 narrow mode)     5-bits (width of EIR register)
198 * o PA 2.0 wide mode                   6-bits (per processor)
199 * o IA64                               8-bits (0-256 total)
200 *
201 * So a Legacy PA I/O device on a PA 2.0 box can't use all the bits supported
202 * by the processor...and the N/L-class I/O subsystem supports more bits than
203 * PA2.0 has. The first case is the problem.
204 */
205int txn_alloc_irq(unsigned int bits_wide)
206{
207	int irq;
208
209	/* never return irq 0 cause that's the interval timer */
210	for (irq = CPU_IRQ_BASE + 1; irq <= CPU_IRQ_MAX; irq++) {
211		if (cpu_claim_irq(irq, NULL, NULL) < 0)
212			continue;
213		if ((irq - CPU_IRQ_BASE) >= (1 << bits_wide))
214			continue;
215		return irq;
216	}
217
218	/* unlikely, but be prepared */
219	return -1;
220}
221
222unsigned long txn_alloc_addr(unsigned int virt_irq)
223{
224	static int next_cpu = -1;
225
226	next_cpu++; /* assign to "next" CPU we want this bugger on */
227
228	/* validate entry */
229	while ((next_cpu < NR_CPUS) && (!cpu_data[next_cpu].txn_addr || 
230		!cpu_online(next_cpu)))
231		next_cpu++;
232
233	if (next_cpu >= NR_CPUS) 
234		next_cpu = 0;	/* nothing else, assign monarch */
235
236	return cpu_data[next_cpu].txn_addr;
237}
238
239
240unsigned int txn_alloc_data(unsigned int virt_irq)
241{
242	return virt_irq - CPU_IRQ_BASE;
243}
244
245/* ONLY called from entry.S:intr_extint() */
246void do_cpu_irq_mask(struct pt_regs *regs)
247{
248	unsigned long eirr_val;
249
250	irq_enter();
251
252	/*
253	 * Only allow interrupt processing to be interrupted by the
254	 * timer tick
255	 */
256	set_eiem(EIEM_MASK(TIMER_IRQ));
257
258	/* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
259	 * 2) We loop here on EIRR contents in order to avoid
260	 *    nested interrupts or having to take another interrupt
261	 *    when we could have just handled it right away.
262	 */
263	for (;;) {
264		unsigned long bit = (1UL << (BITS_PER_LONG - 1));
265		unsigned int irq;
266		eirr_val = mfctl(23) & cpu_eiem;
267		if (!eirr_val)
268			break;
269
270		if (eirr_val & EIEM_MASK(TIMER_IRQ))
271			set_eiem(0);
272
273		mtctl(eirr_val, 23); /* reset bits we are going to process */
274
275		/* Work our way from MSb to LSb...same order we alloc EIRs */
276		for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
277			if (!(bit & eirr_val))
278				continue;
279
280			/* clear bit in mask - can exit loop sooner */
281			eirr_val &= ~bit;
282
283			__do_IRQ(irq, regs);
284		}
285	}
286	set_eiem(cpu_eiem);
287	irq_exit();
288}
289
290
291static struct irqaction timer_action = {
292	.handler = timer_interrupt,
293	.name = "timer",
294};
295
296#ifdef CONFIG_SMP
297static struct irqaction ipi_action = {
298	.handler = ipi_interrupt,
299	.name = "IPI",
300};
301#endif
302
303static void claim_cpu_irqs(void)
304{
305	int i;
306	for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
307		irq_desc[i].handler = &cpu_interrupt_type;
308	}
309
310	irq_desc[TIMER_IRQ].action = &timer_action;
311	irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU;
312#ifdef CONFIG_SMP
313	irq_desc[IPI_IRQ].action = &ipi_action;
314	irq_desc[IPI_IRQ].status = IRQ_PER_CPU;
315#endif
316}
317
318void __init init_IRQ(void)
319{
320	local_irq_disable();	/* PARANOID - should already be disabled */
321	mtctl(~0UL, 23);	/* EIRR : clear all pending external intr */
322	claim_cpu_irqs();
323#ifdef CONFIG_SMP
324	if (!cpu_eiem)
325		cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
326#else
327	cpu_eiem = EIEM_MASK(TIMER_IRQ);
328#endif
329        set_eiem(cpu_eiem);	/* EIEM : enable all external intr */
330
331}
332
333void hw_resend_irq(struct hw_interrupt_type *type, unsigned int irq)
334{
335	/* XXX: Needs to be written.  We managed without it so far, but
336	 * we really ought to write it.
337	 */
338}
339
340void ack_bad_irq(unsigned int irq)
341{
342	printk("unexpected IRQ %d\n", irq);
343}