-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Michal Simek
committed
Mar 27, 2009
1 parent
ba1de6f
commit c81fc05
Showing
5 changed files
with
586 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 3be100114a352bb4b0eee5b6a847cf4f34ce28b1 | ||
refs/heads/master: eedbdab99fffb8ed71cac75a722088b8ace2583c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* Copyright (C) 2006 Atmark Techno, Inc. | ||
* | ||
* 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. | ||
*/ | ||
|
||
#ifndef _ASM_MICROBLAZE_IRQ_H | ||
#define _ASM_MICROBLAZE_IRQ_H | ||
|
||
#define NR_IRQS 32 | ||
|
||
#include <linux/interrupt.h> | ||
|
||
extern unsigned int nr_irq; | ||
|
||
#define NO_IRQ (-1) | ||
|
||
static inline int irq_canonicalize(int irq) | ||
{ | ||
return irq; | ||
} | ||
|
||
struct pt_regs; | ||
extern void do_IRQ(struct pt_regs *regs); | ||
|
||
/* irq_of_parse_and_map - Parse and Map an interrupt into linux virq space | ||
* @device: Device node of the device whose interrupt is to be mapped | ||
* @index: Index of the interrupt to map | ||
* | ||
* This function is a wrapper that chains of_irq_map_one() and | ||
* irq_create_of_mapping() to make things easier to callers | ||
*/ | ||
struct device_node; | ||
extern unsigned int irq_of_parse_and_map(struct device_node *dev, int index); | ||
|
||
/** FIXME - not implement | ||
* irq_dispose_mapping - Unmap an interrupt | ||
* @virq: linux virq number of the interrupt to unmap | ||
*/ | ||
static inline void irq_dispose_mapping(unsigned int virq) | ||
{ | ||
return; | ||
} | ||
|
||
#endif /* _ASM_MICROBLAZE_IRQ_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/* | ||
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> | ||
* Copyright (C) 2007-2009 PetaLogix | ||
* Copyright (C) 2006 Atmark Techno, Inc. | ||
* | ||
* 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. | ||
*/ | ||
|
||
#include <linux/init.h> | ||
#include <linux/irq.h> | ||
#include <asm/page.h> | ||
#include <linux/io.h> | ||
|
||
#include <asm/prom.h> | ||
#include <asm/irq.h> | ||
|
||
#ifdef CONFIG_SELFMOD_INTC | ||
#include <asm/selfmod.h> | ||
#define INTC_BASE BARRIER_BASE_ADDR | ||
#else | ||
static unsigned int intc_baseaddr; | ||
#define INTC_BASE intc_baseaddr | ||
#endif | ||
|
||
unsigned int nr_irq; | ||
|
||
/* No one else should require these constants, so define them locally here. */ | ||
#define ISR 0x00 /* Interrupt Status Register */ | ||
#define IPR 0x04 /* Interrupt Pending Register */ | ||
#define IER 0x08 /* Interrupt Enable Register */ | ||
#define IAR 0x0c /* Interrupt Acknowledge Register */ | ||
#define SIE 0x10 /* Set Interrupt Enable bits */ | ||
#define CIE 0x14 /* Clear Interrupt Enable bits */ | ||
#define IVR 0x18 /* Interrupt Vector Register */ | ||
#define MER 0x1c /* Master Enable Register */ | ||
|
||
#define MER_ME (1<<0) | ||
#define MER_HIE (1<<1) | ||
|
||
static void intc_enable_or_unmask(unsigned int irq) | ||
{ | ||
pr_debug("enable_or_unmask: %d\n", irq); | ||
out_be32(INTC_BASE + SIE, 1 << irq); | ||
} | ||
|
||
static void intc_disable_or_mask(unsigned int irq) | ||
{ | ||
pr_debug("disable: %d\n", irq); | ||
out_be32(INTC_BASE + CIE, 1 << irq); | ||
} | ||
|
||
static void intc_ack(unsigned int irq) | ||
{ | ||
pr_debug("ack: %d\n", irq); | ||
out_be32(INTC_BASE + IAR, 1 << irq); | ||
} | ||
|
||
static void intc_mask_ack(unsigned int irq) | ||
{ | ||
unsigned long mask = 1 << irq; | ||
pr_debug("disable_and_ack: %d\n", irq); | ||
out_be32(INTC_BASE + CIE, mask); | ||
out_be32(INTC_BASE + IAR, mask); | ||
} | ||
|
||
static void intc_end(unsigned int irq) | ||
{ | ||
unsigned long mask = 1 << irq; | ||
pr_debug("end: %d\n", irq); | ||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | ||
out_be32(INTC_BASE + SIE, mask); | ||
/* ack level sensitive intr */ | ||
if (irq_desc[irq].status & IRQ_LEVEL) | ||
out_be32(INTC_BASE + IAR, mask); | ||
} | ||
} | ||
|
||
static struct irq_chip intc_dev = { | ||
.name = "Xilinx INTC", | ||
.unmask = intc_enable_or_unmask, | ||
.mask = intc_disable_or_mask, | ||
.ack = intc_ack, | ||
.mask_ack = intc_mask_ack, | ||
.end = intc_end, | ||
}; | ||
|
||
unsigned int get_irq(struct pt_regs *regs) | ||
{ | ||
int irq; | ||
|
||
/* | ||
* NOTE: This function is the one that needs to be improved in | ||
* order to handle multiple interrupt controllers. It currently | ||
* is hardcoded to check for interrupts only on the first INTC. | ||
*/ | ||
irq = in_be32(INTC_BASE + IVR); | ||
pr_debug("get_irq: %d\n", irq); | ||
|
||
return irq; | ||
} | ||
|
||
void __init init_IRQ(void) | ||
{ | ||
u32 i, j, intr_type; | ||
struct device_node *intc = NULL; | ||
#ifdef CONFIG_SELFMOD_INTC | ||
unsigned int intc_baseaddr = 0; | ||
static int arr_func[] = { | ||
(int)&get_irq, | ||
(int)&intc_enable_or_unmask, | ||
(int)&intc_disable_or_mask, | ||
(int)&intc_mask_ack, | ||
(int)&intc_ack, | ||
(int)&intc_end, | ||
0 | ||
}; | ||
#endif | ||
static char *intc_list[] = { | ||
"xlnx,xps-intc-1.00.a", | ||
"xlnx,opb-intc-1.00.c", | ||
"xlnx,opb-intc-1.00.b", | ||
"xlnx,opb-intc-1.00.a", | ||
NULL | ||
}; | ||
|
||
for (j = 0; intc_list[j] != NULL; j++) { | ||
intc = of_find_compatible_node(NULL, NULL, intc_list[j]); | ||
if (intc) | ||
break; | ||
} | ||
|
||
intc_baseaddr = *(int *) of_get_property(intc, "reg", NULL); | ||
intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE); | ||
nr_irq = *(int *) of_get_property(intc, "xlnx,num-intr-inputs", NULL); | ||
|
||
intr_type = | ||
*(int *) of_get_property(intc, "xlnx,kind-of-intr", NULL); | ||
if (intr_type >= (1 << nr_irq)) | ||
printk(KERN_INFO " ERROR: Mishmash in king-of-intr param\n"); | ||
|
||
#ifdef CONFIG_SELFMOD_INTC | ||
selfmod_function((int *) arr_func, intc_baseaddr); | ||
#endif | ||
printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n", | ||
intc_list[j], intc_baseaddr, nr_irq, intr_type); | ||
|
||
/* | ||
* Disable all external interrupts until they are | ||
* explicity requested. | ||
*/ | ||
out_be32(intc_baseaddr + IER, 0); | ||
|
||
/* Acknowledge any pending interrupts just in case. */ | ||
out_be32(intc_baseaddr + IAR, 0xffffffff); | ||
|
||
/* Turn on the Master Enable. */ | ||
out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); | ||
|
||
for (i = 0; i < nr_irq; ++i) { | ||
if (intr_type & (0x00000001 << i)) { | ||
set_irq_chip_and_handler_name(i, &intc_dev, | ||
handle_edge_irq, intc_dev.name); | ||
irq_desc[i].status &= ~IRQ_LEVEL; | ||
} else { | ||
set_irq_chip_and_handler_name(i, &intc_dev, | ||
handle_level_irq, intc_dev.name); | ||
irq_desc[i].status |= IRQ_LEVEL; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> | ||
* Copyright (C) 2007-2009 PetaLogix | ||
* Copyright (C) 2006 Atmark Techno, Inc. | ||
* | ||
* 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. | ||
*/ | ||
|
||
#include <linux/init.h> | ||
#include <linux/kernel.h> | ||
#include <linux/hardirq.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/irqflags.h> | ||
#include <linux/seq_file.h> | ||
#include <linux/kernel_stat.h> | ||
#include <linux/irq.h> | ||
|
||
#include <asm/prom.h> | ||
|
||
unsigned int irq_of_parse_and_map(struct device_node *dev, int index) | ||
{ | ||
struct of_irq oirq; | ||
|
||
if (of_irq_map_one(dev, index, &oirq)) | ||
return NO_IRQ; | ||
|
||
return oirq.specifier[0]; | ||
} | ||
EXPORT_SYMBOL_GPL(irq_of_parse_and_map); | ||
|
||
/* | ||
* 'what should we do if we get a hw irq event on an illegal vector'. | ||
* each architecture has to answer this themselves. | ||
*/ | ||
void ack_bad_irq(unsigned int irq) | ||
{ | ||
printk(KERN_WARNING "unexpected IRQ trap at vector %02x\n", irq); | ||
} | ||
|
||
static u32 concurrent_irq; | ||
|
||
void do_IRQ(struct pt_regs *regs) | ||
{ | ||
unsigned int irq; | ||
struct pt_regs *old_regs = set_irq_regs(regs); | ||
|
||
irq_enter(); | ||
irq = get_irq(regs); | ||
next_irq: | ||
BUG_ON(irq == -1U); | ||
generic_handle_irq(irq); | ||
|
||
irq = get_irq(regs); | ||
if (irq != -1U) { | ||
pr_debug("next irq: %d\n", irq); | ||
++concurrent_irq; | ||
goto next_irq; | ||
} | ||
|
||
irq_exit(); | ||
set_irq_regs(old_regs); | ||
} | ||
|
||
int show_interrupts(struct seq_file *p, void *v) | ||
{ | ||
int i = *(loff_t *) v, j; | ||
struct irqaction *action; | ||
unsigned long flags; | ||
|
||
if (i == 0) { | ||
seq_printf(p, " "); | ||
for_each_online_cpu(j) | ||
seq_printf(p, "CPU%-8d", j); | ||
seq_putc(p, '\n'); | ||
} | ||
|
||
if (i < nr_irq) { | ||
spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
action = irq_desc[i].action; | ||
if (!action) | ||
goto skip; | ||
seq_printf(p, "%3d: ", i); | ||
#ifndef CONFIG_SMP | ||
seq_printf(p, "%10u ", kstat_irqs(i)); | ||
#else | ||
for_each_online_cpu(j) | ||
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | ||
#endif | ||
seq_printf(p, " %8s", irq_desc[i].status & | ||
IRQ_LEVEL ? "level" : "edge"); | ||
seq_printf(p, " %8s", irq_desc[i].chip->name); | ||
seq_printf(p, " %s", action->name); | ||
|
||
for (action = action->next; action; action = action->next) | ||
seq_printf(p, ", %s", action->name); | ||
|
||
seq_putc(p, '\n'); | ||
skip: | ||
spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
} | ||
return 0; | ||
} |
Oops, something went wrong.