Commit 3991853c authored by Russell King's avatar Russell King

Rationalise interrupt handling on ARM. With the old code, we had

loops within loops within loops checking until each IRQ level didn't
have any more interrupts for us.  This caused both latency problems,
and locked out any chance of handling a second interrupt from down
the chain while one on that chain was already in progress.

The new structure splits out the machine specific IRQ handlers from
the Linux driver specific IRQ handlers, giving the machine specific
handlers much greater flexibility in handling the interrupt.  We
also suck the SA1100 IRQ edge selection function into the IRQ core.
parent 1ea95bdc
2.5.2-rmk5
----------
This is the first kernel that contains a major shake up of some of the
major architecture-specific subsystems.
Firstly, it contains some pretty major changes to the way we handle the
MMU TLB. Each MMU TLB variant is now handled completely separately -
we have TLB v3, TLB v4 (without write buffer), TLB v4 (with write buffer),
and finally TLB v4 (with write buffer, with I TLB invalidate entry).
There is more assembly code inside each of these functions, mainly to
allow more flexible TLB handling for the future.
Secondly, the IRQ subsystem.
The 2.5 kernels will be having major changes to the way IRQs are handled.
Unfortunately, this means that machine types that touch the irq_desc[]
array (basically all machine types) will break, and this means every
machine type that we currently have.
Lets take an example. On the Assabet with Neponset, we have:
GPIO25 IRR:2
SA1100 ------------> Neponset -----------> SA1111
IIR:1
-----------> USAR
IIR:0
-----------> SMC9196
The way stuff currently works, all SA1111 interrupts are mutually
exclusive of each other - if you're processing one interrupt from the
SA1111 and another comes in, you have to wait for that interrupt to
finish processing before you can service the new interrupt. Eg, an
IDE PIO-based interrupt on the SA1111 excludes all other SA1111 and
SMC9196 interrupts until it has finished transferring its multi-sector
data, which can be a long time. Note also that since we loop in the
SA1111 IRQ handler, SA1111 IRQs can hold off SMC9196 IRQs indefinitely.
The new approach brings several new ideas...
We introduce the concept of a "parent" and a "child". For example,
to the Neponset handler, the "parent" is GPIO25, and the "children"d
are SA1111, SMC9196 and USAR.
We also bring the idea of an IRQ "chip" (mainly to reduce the size of
the irqdesc array). This doesn't have to be a real "IC"; indeed the
SA11x0 IRQs are handled by two separate "chip" structures, one for
GPIO0-10, and another for all the rest. It is just a container for
the various operations (maybe this'll change to a better name).
This structure has the following operations:
struct irqchip {
/*
* Acknowledge the IRQ.
* If this is a level-based IRQ, then it is expected to mask the IRQ
* as well.
*/
void (*ack)(unsigned int irq);
/*
* Mask the IRQ in hardware.
*/
void (*mask)(unsigned int irq);
/*
* Unmask the IRQ in hardware.
*/
void (*unmask)(unsigned int irq);
/*
* Re-run the IRQ
*/
void (*rerun)(unsigned int irq);
/*
* Set the type of the IRQ.
*/
int (*type)(unsigned int irq, unsigned int, type);
};
ack - required. May be the same function as mask for IRQs
handled by do_level_IRQ.
mask - required.
unmask - required.
rerun - optional. Not required if you're using do_level_IRQ for all
IRQs that use this 'irqchip'. Generally expected to re-trigger
the hardware IRQ if possible. If not, may call the handler
directly.
type - optional. If you don't support changing the type of an IRQ,
it should be null so people can detect if they are unable to
set the IRQ type.
For each IRQ, we keep the following information:
- "disable" depth (number of disable_irq()s without enable_irq()s)
- flags indicating what we can do with this IRQ (valid, probe,
noautounmask) as before
- status of the IRQ (probing, enable, etc)
- chip
- per-IRQ handler
- irqaction structure list
The handler can be one of the 3 standard handlers - "level", "edge" and
"simple", or your own specific handler if you need to do something special.
The "level" handler is what we currently have - its pretty simple.
"edge" knows about the brokenness of such IRQ implementations - that you
need to leave the hardware IRQ enabled while processing it, and queueing
further IRQ events should the IRQ happen again while processing. The
"simple" handler is very basic, and does not perform any hardware
manipulation, nor state tracking. This is useful for things like the
SMC9196 and USAR above.
So, what's changed?
1. Machine implementations must not write to the irqdesc array.
2. New functions to manipulate the irqdesc array. The first 4 are expected
to be useful only to machine specific code. The last is recommended to
only be used by machine specific code, but may be used in drivers if
absolutely necessary.
set_irq_chip(irq,chip)
Set the mask/unmask methods for handling this IRQ
set_irq_handler(irq,handler)
Set the handler for this IRQ (level, edge, simple)
set_irq_chained_handler(irq,handler)
Set a "chained" handler for this IRQ - automatically
enables this IRQ (eg, Neponset and SA1111 handlers).
set_irq_flags(irq,flags)
Set the valid/probe/noautoenable flags.
set_irq_type(irq,type)
Set active the IRQ edge(s)/level. This replaces the
SA1111 INTPOL manipulation, and the set_GPIO_IRQ_edge()
function. Type should be one of the following:
#define IRQT_NOEDGE (0)
#define IRQT_RISING (__IRQT_RISEDGE)
#define IRQT_FALLING (__IRQT_FALEDGE)
#define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE)
#define IRQT_LOW (__IRQT_LOWLVL)
#define IRQT_HIGH (__IRQT_HIGHLVL)
3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
4. Direct access to SA1111 INTPOL is depreciated. Use set_irq_type instead.
5. A handler is expected to perform any necessary acknowledgement of the
parent IRQ via the correct chip specific function. For instance, if
the SA1111 is directly connected to a SA1110 GPIO, then you should
acknowledge the SA1110 IRQ each time you re-read the SA1111 IRQ status.
6. For any child which doesn't have its own IRQ enable/disable controls
(eg, SMC9196), the handler must mask or acknowledge the parent IRQ
while the child handler is called, and the child handler should be the
"simple" handler (not "edge" nor "level"). After the handler completes,
the parent IRQ should be unmasked, and the status of all children must
be re-checked for pending events. (see the Neponset IRQ handler for
details).
7. fixup_irq() is gone, as is include/asm-arm/arch-*/irq.h
Please note that this will not solve all problems - some of them are
hardware based. Mixing level-based and edge-based IRQs on the same
parent signal (eg neponset) is one such area where a software based
solution can't provide the full answer to low IRQ latency.
...@@ -124,6 +124,7 @@ EXPORT_SYMBOL(__bad_xchg); ...@@ -124,6 +124,7 @@ EXPORT_SYMBOL(__bad_xchg);
EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(__readwrite_bug);
EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(set_irq_type);
EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_idle);
EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(pm_power_off);
......
...@@ -91,17 +91,8 @@ asmlinkage extern int ...@@ -91,17 +91,8 @@ asmlinkage extern int
ecard_loader_reset(volatile unsigned char *pa, loader_t loader); ecard_loader_reset(volatile unsigned char *pa, loader_t loader);
asmlinkage extern int asmlinkage extern int
ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
extern int setup_arm_irq(int, struct irqaction *);
extern void do_ecard_IRQ(int, struct pt_regs *);
static void
ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs);
static struct irqaction irqexpansioncard = {
ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL
};
static inline unsigned short static inline unsigned short
ecard_getu16(unsigned char *v) ecard_getu16(unsigned char *v)
{ {
...@@ -558,7 +549,7 @@ static expansioncard_ops_t ecard_default_ops = { ...@@ -558,7 +549,7 @@ static expansioncard_ops_t ecard_default_ops = {
* *
* They are not meant to be called directly, but via enable/disable_irq. * They are not meant to be called directly, but via enable/disable_irq.
*/ */
static void ecard_enableirq(unsigned int irqnr) static void ecard_irq_mask(unsigned int irqnr)
{ {
ecard_t *ec = slot_to_ecard(irqnr - 32); ecard_t *ec = slot_to_ecard(irqnr - 32);
...@@ -574,7 +565,7 @@ static void ecard_enableirq(unsigned int irqnr) ...@@ -574,7 +565,7 @@ static void ecard_enableirq(unsigned int irqnr)
} }
} }
static void ecard_disableirq(unsigned int irqnr) static void ecard_irq_unmask(unsigned int irqnr)
{ {
ecard_t *ec = slot_to_ecard(irqnr - 32); ecard_t *ec = slot_to_ecard(irqnr - 32);
...@@ -587,6 +578,12 @@ static void ecard_disableirq(unsigned int irqnr) ...@@ -587,6 +578,12 @@ static void ecard_disableirq(unsigned int irqnr)
} }
} }
static struct irqchip ecard_chip = {
ack: ecard_irq_mask,
mask: ecard_irq_mask,
unmask: ecard_irq_unmask,
};
void ecard_enablefiq(unsigned int fiqnr) void ecard_enablefiq(unsigned int fiqnr)
{ {
ecard_t *ec = slot_to_ecard(fiqnr); ecard_t *ec = slot_to_ecard(fiqnr);
...@@ -632,8 +629,7 @@ ecard_dump_irq_state(ecard_t *ec) ...@@ -632,8 +629,7 @@ ecard_dump_irq_state(ecard_t *ec)
ec->irqaddr, ec->irqmask, *ec->irqaddr); ec->irqaddr, ec->irqmask, *ec->irqaddr);
} }
static void static void ecard_check_lockup(struct irqdesc *desc)
ecard_check_lockup(void)
{ {
static int last, lockup; static int last, lockup;
ecard_t *ec; ecard_t *ec;
...@@ -653,7 +649,7 @@ ecard_check_lockup(void) ...@@ -653,7 +649,7 @@ ecard_check_lockup(void)
printk(KERN_ERR "\nInterrupt lockup detected - " printk(KERN_ERR "\nInterrupt lockup detected - "
"disabling all expansion card interrupts\n"); "disabling all expansion card interrupts\n");
disable_irq(IRQ_EXPANSIONCARD); desc->chip->mask(IRQ_EXPANSIONCARD);
printk("Expansion card IRQ state:\n"); printk("Expansion card IRQ state:\n");
...@@ -674,11 +670,12 @@ ecard_check_lockup(void) ...@@ -674,11 +670,12 @@ ecard_check_lockup(void)
} }
static void static void
ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
ecard_t *ec; ecard_t *ec;
int called = 0; int called = 0;
desc->chip->mask(irq);
for (ec = cards; ec; ec = ec->next) { for (ec = cards; ec; ec = ec->next) {
int pending; int pending;
...@@ -691,14 +688,15 @@ ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) ...@@ -691,14 +688,15 @@ ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
pending = ecard_default_ops.irqpending(ec); pending = ecard_default_ops.irqpending(ec);
if (pending) { if (pending) {
do_ecard_IRQ(ec->irq, regs); struct irqdesc *d = irq_desc + ec->irq;
d->handle(ec->irq, d, regs);
called ++; called ++;
} }
} }
cli(); desc->chip->unmask(irq);
if (called == 0) if (called == 0)
ecard_check_lockup(); ecard_check_lockup(desc);
} }
#ifdef HAS_EXPMASK #ifdef HAS_EXPMASK
...@@ -714,20 +712,18 @@ static unsigned char first_set[] = ...@@ -714,20 +712,18 @@ static unsigned char first_set[] =
}; };
static void static void
ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
const unsigned int statusmask = 15; const unsigned int statusmask = 15;
unsigned int status; unsigned int status;
status = __raw_readb(EXPMASK_STATUS) & statusmask; status = __raw_readb(EXPMASK_STATUS) & statusmask;
if (status) { if (status) {
unsigned int slot; unsigned int slot = first_set[status];
ecard_t *ec; ecard_t *ec = slot_to_ecard(slot);
again:
slot = first_set[status];
ec = slot_to_ecard(slot);
if (ec->claimed) { if (ec->claimed) {
unsigned int oldexpmask; struct irqdesc *d = irqdesc + ec->irq;
/* /*
* this ugly code is so that we can operate a * this ugly code is so that we can operate a
* prioritorising system: * prioritorising system:
...@@ -740,17 +736,7 @@ ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) ...@@ -740,17 +736,7 @@ ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
* Serial cards should go in 0/1, ethernet/scsi in 2/3 * Serial cards should go in 0/1, ethernet/scsi in 2/3
* otherwise you will lose serial data at high speeds! * otherwise you will lose serial data at high speeds!
*/ */
oldexpmask = have_expmask; d->handle(ec->irq, d, regs);
have_expmask &= priority_masks[slot];
__raw_writeb(have_expmask, EXPMASK_ENABLE);
sti();
do_ecard_IRQ(ec->irq, regs);
cli();
have_expmask = oldexpmask;
__raw_writeb(have_expmask, EXPMASK_ENABLE);
status = __raw_readb(EXPMASK_STATUS) & statusmask;
if (status)
goto again;
} else { } else {
printk(KERN_WARNING "card%d: interrupt from unclaimed " printk(KERN_WARNING "card%d: interrupt from unclaimed "
"card???\n", slot); "card???\n", slot);
...@@ -761,8 +747,7 @@ ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) ...@@ -761,8 +747,7 @@ ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
} }
static void __init static int __init ecard_probeirqhw(void)
ecard_probeirqhw(void)
{ {
ecard_t *ec; ecard_t *ec;
int found; int found;
...@@ -772,14 +757,10 @@ ecard_probeirqhw(void) ...@@ -772,14 +757,10 @@ ecard_probeirqhw(void)
found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; found = (__raw_readb(EXPMASK_STATUS) & 15) == 0;
__raw_writeb(0xff, EXPMASK_ENABLE); __raw_writeb(0xff, EXPMASK_ENABLE);
if (!found) if (found) {
return;
printk(KERN_DEBUG "Expansion card interrupt " printk(KERN_DEBUG "Expansion card interrupt "
"management hardware found\n"); "management hardware found\n");
irqexpansioncard.handler = ecard_irq_expmask;
/* for each card present, set a bit to '1' */ /* for each card present, set a bit to '1' */
have_expmask = 0x80000000; have_expmask = 0x80000000;
...@@ -787,9 +768,13 @@ ecard_probeirqhw(void) ...@@ -787,9 +768,13 @@ ecard_probeirqhw(void)
have_expmask |= 1 << ec->slot_no; have_expmask |= 1 << ec->slot_no;
__raw_writeb(have_expmask, EXPMASK_ENABLE); __raw_writeb(have_expmask, EXPMASK_ENABLE);
}
return found;
} }
#else #else
#define ecard_probeirqhw() #define ecard_irqexp_handler NULL
#define ecard_probeirqhw() (0)
#endif #endif
#ifndef IO_EC_MEMC8_BASE #ifndef IO_EC_MEMC8_BASE
...@@ -977,10 +962,9 @@ ecard_probe(int slot, card_type_t type) ...@@ -977,10 +962,9 @@ ecard_probe(int slot, card_type_t type)
* hook the interrupt handlers * hook the interrupt handlers
*/ */
if (ec->irq != 0 && ec->irq >= 32) { if (ec->irq != 0 && ec->irq >= 32) {
irq_desc[ec->irq].mask_ack = ecard_disableirq; set_irq_chip(ec->irq, &ecard_chip);
irq_desc[ec->irq].mask = ecard_disableirq; set_irq_handler(ec->irq, do_level_IRQ);
irq_desc[ec->irq].unmask = ecard_enableirq; set_irq_flags(ec->irq, IRQF_VALID);
irq_desc[ec->irq].valid = 1;
} }
#ifdef CONFIG_ARCH_RPC #ifdef CONFIG_ARCH_RPC
...@@ -1042,21 +1026,6 @@ ecard_t *ecard_find(int cid, const card_ids *cids) ...@@ -1042,21 +1026,6 @@ ecard_t *ecard_find(int cid, const card_ids *cids)
return finding_pos; return finding_pos;
} }
static void __init ecard_free_all(void)
{
ecard_t *ec, *ecn;
for (ec = cards; ec; ec = ecn) {
ecn = ec->next;
kfree(ec);
}
cards = NULL;
memset(slot_to_expcard, 0, sizeof(slot_to_expcard));
}
/* /*
* Initialise the expansion card system. * Initialise the expansion card system.
* Locate all hardware - interrupt management and * Locate all hardware - interrupt management and
...@@ -1064,7 +1033,7 @@ static void __init ecard_free_all(void) ...@@ -1064,7 +1033,7 @@ static void __init ecard_free_all(void)
*/ */
void __init ecard_init(void) void __init ecard_init(void)
{ {
int slot; int slot, irqhw;
/* /*
* Register our reboot notifier * Register our reboot notifier
...@@ -1086,13 +1055,10 @@ void __init ecard_init(void) ...@@ -1086,13 +1055,10 @@ void __init ecard_init(void)
ecard_probe(8, ECARD_IOC); ecard_probe(8, ECARD_IOC);
#endif #endif
ecard_probeirqhw(); irqhw = ecard_probeirqhw();
if (setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) { set_irq_chained_handler(IRQ_EXPANSIONCARD,
printk(KERN_ERR "Unable to claim IRQ%d for expansion cards\n", irqhw ? ecard_irqexp_handler : ecard_irq_handler);
IRQ_EXPANSIONCARD);
ecard_free_all();
}
ecard_proc_init(); ecard_proc_init();
} }
......
...@@ -354,7 +354,7 @@ vector_IRQ: ldr r13, .LCirq @ I will leave this one in just in case... ...@@ -354,7 +354,7 @@ vector_IRQ: ldr r13, .LCirq @ I will leave this one in just in case...
@ @
adr lr, 1b adr lr, 1b
orr lr, lr, #0x08000003 @ Force SVC orr lr, lr, #0x08000003 @ Force SVC
bne do_IRQ bne asm_do_IRQ
mov why, #0 mov why, #0
get_current_task r5 get_current_task r5
...@@ -377,7 +377,7 @@ __irq_svc: teqp pc, #0x08000003 ...@@ -377,7 +377,7 @@ __irq_svc: teqp pc, #0x08000003
@ @
adr lr, 1b adr lr, 1b
orr lr, lr, #0x08000003 @ Force SVC orr lr, lr, #0x08000003 @ Force SVC
bne do_IRQ @ Returns to 1b bne asm_do_IRQ @ Returns to 1b
SVC_RESTORE_ALL SVC_RESTORE_ALL
__irq_invalid: mov r0, sp __irq_invalid: mov r0, sp
......
...@@ -34,8 +34,6 @@ ...@@ -34,8 +34,6 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/arch/irq.h> /* pick up fixup_irq definition */
/* /*
* Maximum IRQ count. Currently, this is arbitary. However, it should * Maximum IRQ count. Currently, this is arbitary. However, it should
* not be set too low to prevent false triggering. Conversely, if it * not be set too low to prevent false triggering. Conversely, if it
...@@ -54,25 +52,44 @@ void (*init_arch_irq)(void) __initdata = NULL; ...@@ -54,25 +52,44 @@ void (*init_arch_irq)(void) __initdata = NULL;
/* /*
* Dummy mask/unmask handler * Dummy mask/unmask handler
*/ */
static void dummy_mask_unmask_irq(unsigned int irq) void dummy_mask_unmask_irq(unsigned int irq)
{
}
void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
irq_err_count += 1;
printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
} }
static struct irqchip bad_chip = {
ack: dummy_mask_unmask_irq,
mask: dummy_mask_unmask_irq,
unmask: dummy_mask_unmask_irq,
};
static struct irqdesc bad_irq_desc = {
chip: &bad_chip,
handle: do_bad_IRQ,
depth: 1,
};
/** /**
* disable_irq - disable an irq and wait for completion * disable_irq - disable an irq and wait for completion
* @irq: Interrupt to disable * @irq: Interrupt to disable
* *
* Disable the selected interrupt line. * Disable the selected interrupt line. We do this lazily.
* *
* This function may be called - with care - from IRQ context. * This function may be called from IRQ context.
*/ */
void disable_irq(unsigned int irq) void disable_irq(unsigned int irq)
{ {
struct irqdesc *desc = irq_desc + irq;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags); spin_lock_irqsave(&irq_controller_lock, flags);
irq_desc[irq].enabled = 0; if (!desc->depth++)
irq_desc[irq].mask(irq); desc->enabled = 0;
spin_unlock_irqrestore(&irq_controller_lock, flags); spin_unlock_irqrestore(&irq_controller_lock, flags);
} }
...@@ -80,19 +97,35 @@ void disable_irq(unsigned int irq) ...@@ -80,19 +97,35 @@ void disable_irq(unsigned int irq)
* enable_irq - enable interrupt handling on an irq * enable_irq - enable interrupt handling on an irq
* @irq: Interrupt to enable * @irq: Interrupt to enable
* *
* Re-enables the processing of interrupts on this IRQ line * Re-enables the processing of interrupts on this IRQ line.
* Note that this may call the interrupt handler, so you may
* get unexpected results if you hold IRQs disabled.
* *
* This function may be called from IRQ context. * This function may be called from IRQ context.
*/ */
void enable_irq(unsigned int irq) void enable_irq(unsigned int irq)
{ {
struct irqdesc *desc = irq_desc + irq;
unsigned long flags; unsigned long flags;
int pending = 0;
spin_lock_irqsave(&irq_controller_lock, flags); spin_lock_irqsave(&irq_controller_lock, flags);
irq_desc[irq].probing = 0; if (unlikely(!desc->depth)) {
irq_desc[irq].triggered = 0; printk("enable_irq(%u) unbalanced from %p\n", irq,
irq_desc[irq].enabled = 1; __builtin_return_address(0));
irq_desc[irq].unmask(irq); } else if (!--desc->depth) {
desc->probing = 0;
desc->enabled = 1;
desc->chip->unmask(irq);
pending = desc->pending;
desc->pending = 0;
/*
* If the interrupt was waiting to be processed,
* retrigger it.
*/
if (pending)
desc->chip->rerun(irq);
}
spin_unlock_irqrestore(&irq_controller_lock, flags); spin_unlock_irqrestore(&irq_controller_lock, flags);
} }
...@@ -128,7 +161,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -128,7 +161,7 @@ int show_interrupts(struct seq_file *p, void *v)
* a large number if IRQs to appear in the same jiffie with the * a large number if IRQs to appear in the same jiffie with the
* same instruction pointer (or within 2 instructions). * same instruction pointer (or within 2 instructions).
*/ */
static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs)
{ {
unsigned long instr_ptr = instruction_pointer(regs); unsigned long instr_ptr = instruction_pointer(regs);
...@@ -138,123 +171,283 @@ static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) ...@@ -138,123 +171,283 @@ static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs)
if (desc->lck_cnt > MAX_IRQ_CNT) { if (desc->lck_cnt > MAX_IRQ_CNT) {
printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq);
disable_irq(irq); return 1;
} }
} else { } else {
desc->lck_cnt = 0; desc->lck_cnt = 0;
desc->lck_pc = instruction_pointer(regs); desc->lck_pc = instruction_pointer(regs);
desc->lck_jif = jiffies; desc->lck_jif = jiffies;
} }
return 0;
}
static void
__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
{
unsigned int status;
spin_unlock(&irq_controller_lock);
if (!(action->flags & SA_INTERRUPT))
__sti();
status = 0;
do {
status |= action->flags;
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
__cli();
spin_lock(&irq_controller_lock);
} }
/* /*
* do_IRQ handles all normal device IRQ's * This is for software-decoded IRQs. The caller is expected to
* handle the ack, clear, mask and unmask issues.
*/ */
asmlinkage void do_IRQ(int irq, struct pt_regs * regs) void
do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
struct irqdesc * desc; struct irqaction *action;
struct irqaction * action; const int cpu = smp_processor_id();
int cpu;
desc->triggered = 1;
irq = fixup_irq(irq); irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
action = desc->action;
if (action)
__do_irq(irq, desc->action, regs);
irq_exit(cpu, irq);
}
/*
* Most edge-triggered IRQ implementations seem to take a broken
* approach to this. Hence the complexity.
*/
void
do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{
const int cpu = smp_processor_id();
desc->triggered = 1;
/* /*
* Some hardware gives randomly wrong interrupts. Rather * If we're currently running this IRQ, or its disabled,
* than crashing, do something sensible. * we shouldn't process the IRQ. Instead, turn on the
* hardware masks.
*/ */
if (irq >= NR_IRQS) if (unlikely(desc->running || !desc->enabled))
goto bad_irq; goto running;
desc = irq_desc + irq; /*
* Acknowledge and clear the IRQ, but don't mask it.
*/
desc->chip->ack(irq);
spin_lock(&irq_controller_lock); /*
desc->mask_ack(irq); * Mark the IRQ currently in progress.
spin_unlock(&irq_controller_lock); */
desc->running = 1;
cpu = smp_processor_id();
irq_enter(cpu, irq); irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++; kstat.irqs[cpu][irq]++;
desc->triggered = 1;
/* Return with this interrupt masked if no action */ do {
action = desc->action; struct irqaction *action;
if (action) { action = desc->action;
int status = 0; if (!action)
break;
if (desc->nomask) { if (desc->pending && desc->enabled) {
spin_lock(&irq_controller_lock); desc->pending = 0;
desc->unmask(irq); desc->chip->unmask(irq);
spin_unlock(&irq_controller_lock);
} }
if (!(action->flags & SA_INTERRUPT)) __do_irq(irq, action, regs);
__sti(); } while (desc->pending);
do { irq_exit(cpu, irq);
status |= action->flags;
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
if (status & SA_SAMPLE_RANDOM) desc->running = 0;
add_interrupt_randomness(irq);
__cli();
if (!desc->nomask && desc->enabled) { /*
spin_lock(&irq_controller_lock); * If we were disabled or freed, shut down the handler.
desc->unmask(irq); */
spin_unlock(&irq_controller_lock); if (likely(desc->action && !check_irq_lock(desc, irq, regs)))
return;
running:
/*
* We got another IRQ while this one was masked or
* currently running. Delay it.
*/
desc->pending = 1;
desc->chip->mask(irq);
desc->chip->ack(irq);
}
/*
* Level-based IRQ handler. Nice and simple.
*/
void
do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{
struct irqaction *action;
const int cpu = smp_processor_id();
desc->triggered = 1;
/*
* Acknowledge, clear _AND_ disable the interrupt.
*/
desc->chip->ack(irq);
if (likely(desc->enabled)) {
irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
/*
* Return with this interrupt masked if no action
*/
action = desc->action;
if (action) {
__do_irq(irq, desc->action, regs);
if (likely(desc->enabled &&
!check_irq_lock(desc, irq, regs)))
desc->chip->unmask(irq);
} }
} }
irq_exit(cpu, irq);
}
/*
* do_IRQ handles all hardware IRQ's. Decoded IRQs should not
* come via this function. Instead, they should provide their
* own 'handler'
*/
asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs)
{
struct irqdesc *desc = irq_desc + irq;
/* /*
* Debug measure - hopefully we can continue if an * Some hardware gives randomly wrong interrupts. Rather
* IRQ lockup problem occurs... * than crashing, do something sensible.
*/ */
check_irq_lock(desc, irq, regs); if (irq >= NR_IRQS)
desc = &bad_irq_desc;
irq_exit(cpu, irq); spin_lock(&irq_controller_lock);
desc->handle(irq, desc, regs);
spin_unlock(&irq_controller_lock);
if (softirq_pending(cpu)) if (softirq_pending(smp_processor_id()))
do_softirq(); do_softirq();
}
void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained)
{
struct irqdesc *desc;
unsigned long flags;
if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq);
return; return;
}
bad_irq: if (handle == NULL)
irq_err_count += 1; handle = do_bad_IRQ;
printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
desc = irq_desc + irq;
if (is_chained && desc->chip == &bad_chip)
printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq);
spin_lock_irqsave(&irq_controller_lock, flags);
if (handle == do_bad_IRQ) {
desc->chip->mask(irq);
desc->chip->ack(irq);
desc->depth = 1;
desc->enabled = 0;
}
desc->handle = handle;
if (handle != do_bad_IRQ && is_chained) {
desc->valid = 0;
desc->probe_ok = 0;
desc->depth = 0;
desc->chip->unmask(irq);
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
void set_irq_chip(unsigned int irq, struct irqchip *chip)
{
struct irqdesc *desc;
unsigned long flags;
if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
return; return;
}
if (chip == NULL)
chip = &bad_chip;
desc = irq_desc + irq;
spin_lock_irqsave(&irq_controller_lock, flags);
desc->chip = chip;
spin_unlock_irqrestore(&irq_controller_lock, flags);
} }
#ifdef CONFIG_ARCH_ACORN int set_irq_type(unsigned int irq, unsigned int type)
void do_ecard_IRQ(int irq, struct pt_regs *regs)
{ {
struct irqdesc * desc; struct irqdesc *desc;
struct irqaction * action; unsigned long flags;
int cpu; int ret = -ENXIO;
if (irq >= NR_IRQS) {
printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
return -ENODEV;
}
desc = irq_desc + irq; desc = irq_desc + irq;
if (desc->chip->type) {
spin_lock_irqsave(&irq_controller_lock, flags);
ret = desc->chip->type(irq, type);
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
cpu = smp_processor_id(); return ret;
kstat.irqs[cpu][irq]++; }
desc->triggered = 1;
action = desc->action; void set_irq_flags(unsigned int irq, unsigned int iflags)
{
struct irqdesc *desc;
unsigned long flags;
if (action) { if (irq >= NR_IRQS) {
do { printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
action->handler(irq, action->dev_id, regs); return;
action = action->next;
} while (action);
} else {
spin_lock(&irq_controller_lock);
desc->mask(irq);
spin_unlock(&irq_controller_lock);
} }
desc = irq_desc + irq;
spin_lock_irqsave(&irq_controller_lock, flags);
desc->valid = (iflags & IRQF_VALID) != 0;
desc->probe_ok = (iflags & IRQF_PROBE) != 0;
desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0;
spin_unlock_irqrestore(&irq_controller_lock, flags);
} }
#endif
int setup_arm_irq(int irq, struct irqaction * new) int setup_irq(unsigned int irq, struct irqaction *new)
{ {
int shared = 0; int shared = 0;
struct irqaction *old, **p; struct irqaction *old, **p;
...@@ -302,11 +495,14 @@ int setup_arm_irq(int irq, struct irqaction * new) ...@@ -302,11 +495,14 @@ int setup_arm_irq(int irq, struct irqaction * new)
*p = new; *p = new;
if (!shared) { if (!shared) {
desc->nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0;
desc->probing = 0; desc->probing = 0;
desc->running = 0;
desc->pending = 0;
desc->depth = 1;
if (!desc->noautoenable) { if (!desc->noautoenable) {
desc->depth = 0;
desc->enabled = 1; desc->enabled = 1;
desc->unmask(irq); desc->chip->unmask(irq);
} }
} }
...@@ -366,7 +562,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) ...@@ -366,7 +562,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
action->next = NULL; action->next = NULL;
action->dev_id = dev_id; action->dev_id = dev_id;
retval = setup_arm_irq(irq, action); retval = setup_irq(irq, action);
if (retval) if (retval)
kfree(action); kfree(action);
...@@ -433,14 +629,12 @@ unsigned long probe_irq_on(void) ...@@ -433,14 +629,12 @@ unsigned long probe_irq_on(void)
*/ */
spin_lock_irq(&irq_controller_lock); spin_lock_irq(&irq_controller_lock);
for (i = 0; i < NR_IRQS; i++) { for (i = 0; i < NR_IRQS; i++) {
if (!irq_desc[i].valid || if (!irq_desc[i].probe_ok || irq_desc[i].action)
!irq_desc[i].probe_ok ||
irq_desc[i].action)
continue; continue;
irq_desc[i].probing = 1; irq_desc[i].probing = 1;
irq_desc[i].triggered = 0; irq_desc[i].triggered = 0;
irq_desc[i].unmask(i); irq_desc[i].chip->unmask(i);
irqs += 1; irqs += 1;
} }
spin_unlock_irq(&irq_controller_lock); spin_unlock_irq(&irq_controller_lock);
...@@ -456,15 +650,13 @@ unsigned long probe_irq_on(void) ...@@ -456,15 +650,13 @@ unsigned long probe_irq_on(void)
*/ */
spin_lock_irq(&irq_controller_lock); spin_lock_irq(&irq_controller_lock);
for (i = 0; i < NR_IRQS; i++) { for (i = 0; i < NR_IRQS; i++) {
if (irq_desc[i].probing && if (irq_desc[i].probing && irq_desc[i].triggered) {
irq_desc[i].triggered) {
irq_desc[i].probing = 0; irq_desc[i].probing = 0;
irqs -= 1; irqs -= 1;
} }
} }
spin_unlock_irq(&irq_controller_lock); spin_unlock_irq(&irq_controller_lock);
/* now filter out any obviously spurious interrupts */
return irqs; return irqs;
} }
...@@ -508,17 +700,12 @@ void __init init_irq_proc(void) ...@@ -508,17 +700,12 @@ void __init init_irq_proc(void)
void __init init_IRQ(void) void __init init_IRQ(void)
{ {
struct irqdesc *desc;
extern void init_dma(void); extern void init_dma(void);
int irq; int irq;
for (irq = 0; irq < NR_IRQS; irq++) { for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++)
irq_desc[irq].probe_ok = 0; *desc = bad_irq_desc;
irq_desc[irq].valid = 0;
irq_desc[irq].noautoenable = 0;
irq_desc[irq].mask_ack = dummy_mask_unmask_irq;
irq_desc[irq].mask = dummy_mask_unmask_irq;
irq_desc[irq].unmask = dummy_mask_unmask_irq;
}
init_arch_irq(); init_arch_irq();
init_dma(); init_dma();
......
...@@ -31,10 +31,16 @@ ...@@ -31,10 +31,16 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/leds.h> #include <asm/leds.h>
extern int setup_arm_irq(int, struct irqaction *);
extern rwlock_t xtime_lock; extern rwlock_t xtime_lock;
extern unsigned long wall_jiffies; extern unsigned long wall_jiffies;
/* this needs a better home */
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_SA1100_RTC_MODULE
EXPORT_SYMBOL(rtc_lock);
#endif
/* change this if you have some constant time drift */ /* change this if you have some constant time drift */
#define USECS_PER_JIFFY (1000000/HZ) #define USECS_PER_JIFFY (1000000/HZ)
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <asm/hardware/clps7111.h> #include <asm/hardware/clps7111.h>
static void mask_irq_int1(unsigned int irq) static void int1_mask(unsigned int irq)
{ {
u32 intmr1; u32 intmr1;
...@@ -35,7 +35,7 @@ static void mask_irq_int1(unsigned int irq) ...@@ -35,7 +35,7 @@ static void mask_irq_int1(unsigned int irq)
clps_writel(intmr1, INTMR1); clps_writel(intmr1, INTMR1);
} }
static void mask_ack_irq_int1(unsigned int irq) static void int1_ack(unsigned int irq)
{ {
u32 intmr1; u32 intmr1;
...@@ -53,7 +53,7 @@ static void mask_ack_irq_int1(unsigned int irq) ...@@ -53,7 +53,7 @@ static void mask_ack_irq_int1(unsigned int irq)
} }
} }
static void unmask_irq_int1(unsigned int irq) static void int1_unmask(unsigned int irq)
{ {
u32 intmr1; u32 intmr1;
...@@ -62,7 +62,13 @@ static void unmask_irq_int1(unsigned int irq) ...@@ -62,7 +62,13 @@ static void unmask_irq_int1(unsigned int irq)
clps_writel(intmr1, INTMR1); clps_writel(intmr1, INTMR1);
} }
static void mask_irq_int2(unsigned int irq) static struct irqchip int1_chip = {
ack: int1_ack,
mask: int1_mask,
unmask: int1_unmask,
};
static void int2_mask(unsigned int irq)
{ {
u32 intmr2; u32 intmr2;
...@@ -71,7 +77,7 @@ static void mask_irq_int2(unsigned int irq) ...@@ -71,7 +77,7 @@ static void mask_irq_int2(unsigned int irq)
clps_writel(intmr2, INTMR2); clps_writel(intmr2, INTMR2);
} }
static void mask_ack_irq_int2(unsigned int irq) static void int2_ack(unsigned int irq)
{ {
u32 intmr2; u32 intmr2;
...@@ -84,7 +90,7 @@ static void mask_ack_irq_int2(unsigned int irq) ...@@ -84,7 +90,7 @@ static void mask_ack_irq_int2(unsigned int irq)
} }
} }
static void unmask_irq_int2(unsigned int irq) static void int2_unmask(unsigned int irq)
{ {
u32 intmr2; u32 intmr2;
...@@ -93,28 +99,26 @@ static void unmask_irq_int2(unsigned int irq) ...@@ -93,28 +99,26 @@ static void unmask_irq_int2(unsigned int irq)
clps_writel(intmr2, INTMR2); clps_writel(intmr2, INTMR2);
} }
static struct irqchip int2_chip = {
ack: int2_ack,
mask: int2_mask,
unmask: int2_unmask,
};
void __init clps711x_init_irq(void) void __init clps711x_init_irq(void)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < NR_IRQS; i++) { for (i = 0; i < NR_IRQS; i++) {
if (INT1_IRQS & (1 << i)) { if (INT1_IRQS & (1 << i)) {
irq_desc[i].valid = 1; set_irq_handler(i, do_level_IRQ);
irq_desc[i].probe_ok = 1; set_irq_chip(i, &int1_chip);
irq_desc[i].mask_ack = (INT1_ACK_IRQS & (1 << i)) ? set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
mask_ack_irq_int1 :
mask_irq_int1;
irq_desc[i].mask = mask_irq_int1;
irq_desc[i].unmask = unmask_irq_int1;
} }
if (INT2_IRQS & (1 << i)) { if (INT2_IRQS & (1 << i)) {
irq_desc[i].valid = 1; set_irq_handler(i, do_level_IRQ);
irq_desc[i].probe_ok = 1; set_irq_chip(i, &int2_chip);
irq_desc[i].mask_ack = (INT2_ACK_IRQS & (1 << i)) ? set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
mask_ack_irq_int2 :
mask_irq_int2;
irq_desc[i].mask = mask_irq_int2;
irq_desc[i].unmask = unmask_irq_int2;
} }
} }
......
...@@ -40,26 +40,30 @@ static void ebsa110_unmask_irq(unsigned int irq) ...@@ -40,26 +40,30 @@ static void ebsa110_unmask_irq(unsigned int irq)
__raw_writeb(1 << irq, IRQ_MSET); __raw_writeb(1 << irq, IRQ_MSET);
} }
static struct irqchip ebsa110_irq_chip = {
ack: ebsa110_mask_irq,
mask: ebsa110_mask_irq,
unmask: ebsa110_unmask_irq,
};
static void __init ebsa110_init_irq(void) static void __init ebsa110_init_irq(void)
{ {
unsigned long flags; unsigned long flags;
int irq; unsigned int irq;
save_flags_cli (flags); local_irq_save(flags);
__raw_writeb(0xff, IRQ_MCLR); __raw_writeb(0xff, IRQ_MCLR);
__raw_writeb(0x55, IRQ_MSET); __raw_writeb(0x55, IRQ_MSET);
__raw_writeb(0x00, IRQ_MSET); __raw_writeb(0x00, IRQ_MSET);
if (__raw_readb(IRQ_MASK) != 0x55) if (__raw_readb(IRQ_MASK) != 0x55)
while (1); while (1);
__raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */ __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */
restore_flags (flags); local_irq_restore(flags);
for (irq = 0; irq < NR_IRQS; irq++) { for (irq = 0; irq < NR_IRQS; irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &ebsa110_irq_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].mask_ack = ebsa110_mask_irq; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = ebsa110_mask_irq;
irq_desc[irq].unmask = ebsa110_unmask_irq;
} }
} }
......
...@@ -18,28 +18,44 @@ ...@@ -18,28 +18,44 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/arch/platform.h> #include <asm/arch/platform.h>
#include <asm/arch/int_ctrl00.h> #include <asm/arch/int_ctrl00.h>
static void mask_irq(unsigned int irq) static void epxa_mask_irq(unsigned int irq)
{ {
__raw_writel(1 << irq, INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); writel(1 << irq, INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
} }
static void unmask_irq(unsigned int irq) static void epxa_unmask_irq(unsigned int irq)
{ {
__raw_writel(1 << irq, INT_MS(IO_ADDRESS(EXC_INT_CTRL00_BASE))); writel(1 << irq, INT_MS(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
} }
static struct irqchip epxa_irq_chip = {
ack: epxa_mask_irq,
mask: epxa_mask_irq,
unmask: epxa_unmask_irq,
};
static struct resource irq_resource = {
name: "irq_handler",
start: IO_ADDRESS(EXC_INT_CTRL00_BASE),
end: IO_ADDRESS(INT_PRIORITY_FC(EXC_INT_CTRL00_BASE))+4,
};
void __init epxa10db_init_irq(void) void __init epxa10db_init_irq(void)
{ {
unsigned int i; unsigned int i;
request_resource(&iomem_resource, &irq_resource);
/* /*
* This bit sets up the interrupt controller using * This bit sets up the interrupt controller using
* the 6 PLD interrupts mode (the default) each * the 6 PLD interrupts mode (the default) each
...@@ -49,22 +65,15 @@ void __init epxa10db_init_irq(void) ...@@ -49,22 +65,15 @@ void __init epxa10db_init_irq(void)
* on the contents of your PLD * on the contents of your PLD
*/ */
__raw_writel(3,INT_MODE(IO_ADDRESS(EXC_INT_CTRL00_BASE))); writel(3,INT_MODE(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
for (i = 0; i < NR_IRQS; i++){ for (i = 0; i < NR_IRQS; i++){
__raw_writel(i+1, INT_PRIORITY_P0(IO_ADDRESS(EXC_INT_CTRL00_BASE)) + (4*i)); writel(i+1, INT_PRIORITY_P0(IO_ADDRESS(EXC_INT_CTRL00_BASE)) + (4*i));
} set_irq_chip(i,&epxa_irq_chip);
set_irq_handler(i,do_level_IRQ);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
for (i = 0; i < NR_IRQS; i++) {
irq_desc[i].valid = 1;
irq_desc[i].probe_ok = 1;
irq_desc[i].mask_ack = mask_irq;
irq_desc[i].mask = mask_irq;
irq_desc[i].unmask = unmask_irq;
} }
/* Disable all interrupt */ /* Disable all interrupts */
__raw_writel(-1,INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); writel(-1,INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
} }
...@@ -11,7 +11,7 @@ O_TARGET := footbridge.o ...@@ -11,7 +11,7 @@ O_TARGET := footbridge.o
# Object file lists. # Object file lists.
obj-y := arch.o dc21285.o dma.o irq.o mm.o obj-y := arch.o dc21285.o dma.o irq.o isa-irq.o mm.o
obj-m := obj-m :=
obj-n := obj-n :=
obj- := obj- :=
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
extern void __init isa_init_irq(unsigned int irq);
/* /*
* Footbridge IRQ translation table * Footbridge IRQ translation table
* Converts from our IRQ numbers into FootBridge masks * Converts from our IRQ numbers into FootBridge masks
...@@ -64,9 +66,15 @@ static void fb_unmask_irq(unsigned int irq) ...@@ -64,9 +66,15 @@ static void fb_unmask_irq(unsigned int irq)
*CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)]; *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)];
} }
static struct irqchip fb_chip = {
ack: fb_mask_irq,
mask: fb_mask_irq,
unmask: fb_unmask_irq,
};
static void __init __fb_init_irq(void) static void __init __fb_init_irq(void)
{ {
int irq; unsigned int irq;
/* /*
* setup DC21285 IRQs * setup DC21285 IRQs
...@@ -75,128 +83,9 @@ static void __init __fb_init_irq(void) ...@@ -75,128 +83,9 @@ static void __init __fb_init_irq(void)
*CSR_FIQ_DISABLE = -1; *CSR_FIQ_DISABLE = -1;
for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &fb_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].mask_ack = fb_mask_irq; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = fb_mask_irq;
irq_desc[irq].unmask = fb_unmask_irq;
}
}
extern int isa_irq;
static void isa_mask_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
}
static void isa_mask_ack_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
outb(0x20, PIC_LO);
}
static void isa_unmask_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
}
static void isa_mask_pic_hi_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
}
static void isa_mask_ack_pic_hi_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
outb(0x62, PIC_LO);
outb(0x20, PIC_HI);
}
static void isa_unmask_pic_hi_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
}
static void no_action(int irq, void *dev_id, struct pt_regs *regs)
{
}
static struct irqaction irq_cascade = { handler: no_action, name: "cascade", };
static struct resource pic1_resource = { "pic1", 0x20, 0x3f };
static struct resource pic2_resource = { "pic2", 0xa0, 0xbf };
static void __init isa_init_irq(int irq)
{
/*
* Setup, and then probe for an ISA PIC
* If the PIC is not there, then we
* ignore the PIC.
*/
outb(0x11, PIC_LO);
outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */
outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */
outb(0x01, PIC_MASK_LO); /* x86 */
outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */
outb(0x11, PIC_HI);
outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */
outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */
outb(0x01, PIC_MASK_HI); /* x86 */
outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */
outb(0x0b, PIC_LO);
outb(0x0b, PIC_HI);
if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
outb(0xff, PIC_MASK_LO);/* mask all IRQs */
outb(0xff, PIC_MASK_HI);/* mask all IRQs */
isa_irq = irq;
} else
isa_irq = -1;
if (isa_irq != -1) {
for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
irq_desc[irq].mask_ack = isa_mask_ack_pic_lo_irq;
irq_desc[irq].mask = isa_mask_pic_lo_irq;
irq_desc[irq].unmask = isa_unmask_pic_lo_irq;
}
for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
irq_desc[irq].mask_ack = isa_mask_ack_pic_hi_irq;
irq_desc[irq].mask = isa_mask_pic_hi_irq;
irq_desc[irq].unmask = isa_unmask_pic_hi_irq;
}
request_resource(&ioport_resource, &pic1_resource);
request_resource(&ioport_resource, &pic2_resource);
setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
setup_arm_irq(isa_irq, &irq_cascade);
/*
* On the NetWinder, don't automatically
* enable ISA IRQ11 when it is requested.
* There appears to be a missing pull-up
* resistor on this line.
*/
if (machine_is_netwinder())
irq_desc[_ISA_IRQ(11)].noautoenable = 1;
} }
} }
......
/*
* linux/arch/arm/mach-footbridge/irq.c
*
* Copyright (C) 1996-2000 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Changelog:
* 22-Aug-1998 RMK Restructured IRQ routines
* 03-Sep-1998 PJB Merged CATS support
* 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder
* 26-Jan-1999 PJB Don't use IACK on CATS
* 16-Mar-1999 RMK Added autodetect of ISA PICs
*/
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/mach/irq.h>
#include <asm/hardware.h>
#include <asm/hardware/dec21285.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/mach-types.h>
static void isa_mask_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
}
static void isa_ack_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
outb(0x20, PIC_LO);
}
static void isa_unmask_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
}
static struct irqchip isa_lo_chip = {
ack: isa_ack_pic_lo_irq,
mask: isa_mask_pic_lo_irq,
unmask: isa_unmask_pic_lo_irq,
};
static void isa_mask_pic_hi_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
}
static void isa_ack_pic_hi_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
outb(0x62, PIC_LO);
outb(0x20, PIC_HI);
}
static void isa_unmask_pic_hi_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
}
static struct irqchip isa_hi_chip = {
ack: isa_ack_pic_hi_irq,
mask: isa_mask_pic_hi_irq,
unmask: isa_unmask_pic_hi_irq,
};
static void no_action(int irq, void *dev_id, struct pt_regs *regs)
{
}
static void
isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{
unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE;
if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) {
do_bad_IRQ(isa_irq, desc, regs);
return;
}
desc = irq_desc + isa_irq;
desc->handle(isa_irq, desc, regs);
}
static struct irqaction irq_cascade = { handler: no_action, name: "cascade", };
static struct resource pic1_resource = { "pic1", 0x20, 0x3f };
static struct resource pic2_resource = { "pic2", 0xa0, 0xbf };
void __init isa_init_irq(unsigned int irq)
{
/*
* Setup, and then probe for an ISA PIC
* If the PIC is not there, then we
* ignore the PIC.
*/
outb(0x11, PIC_LO);
outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */
outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */
outb(0x01, PIC_MASK_LO); /* x86 */
outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */
outb(0x11, PIC_HI);
outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */
outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */
outb(0x01, PIC_MASK_HI); /* x86 */
outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */
outb(0x0b, PIC_LO);
outb(0x0b, PIC_HI);
if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
outb(0xff, PIC_MASK_LO);/* mask all IRQs */
outb(0xff, PIC_MASK_HI);/* mask all IRQs */
} else {
printk(KERN_INFO "IRQ: ISA PIC not found\n");
irq = -1;
}
if (irq != -1) {
for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
set_irq_chip(irq, &isa_lo_chip);
set_irq_handler(irq, do_level_IRQ);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
set_irq_chip(irq, &isa_hi_chip);
set_irq_handler(irq, do_level_IRQ);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
request_resource(&ioport_resource, &pic1_resource);
request_resource(&ioport_resource, &pic2_resource);
setup_irq(IRQ_ISA_CASCADE, &irq_cascade);
set_irq_chained_handler(irq, isa_irq_handler);
/*
* On the NetWinder, don't automatically
* enable ISA IRQ11 when it is requested.
* There appears to be a missing pull-up
* resistor on this line.
*/
if (machine_is_netwinder())
set_irq_flags(_ISA_IRQ(11), IRQF_VALID |
IRQF_PROBE | IRQF_NOAUTOEN);
}
}
...@@ -47,20 +47,16 @@ static void sc_unmask_irq(unsigned int irq) ...@@ -47,20 +47,16 @@ static void sc_unmask_irq(unsigned int irq)
__raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
} }
static struct irqchip sc_chip = {
ack: sc_mask_irq,
mask: sc_mask_irq,
unmask: sc_unmask_irq,
};
void __init integrator_init_irq(void) void __init integrator_init_irq(void)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < NR_IRQS; i++) {
if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
irq_desc[i].valid = 1;
irq_desc[i].probe_ok = 1;
irq_desc[i].mask_ack = sc_mask_irq;
irq_desc[i].mask = sc_mask_irq;
irq_desc[i].unmask = sc_unmask_irq;
}
}
/* Disable all interrupts initially. */ /* Disable all interrupts initially. */
/* Do the core module ones */ /* Do the core module ones */
__raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); __raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
...@@ -68,4 +64,12 @@ void __init integrator_init_irq(void) ...@@ -68,4 +64,12 @@ void __init integrator_init_irq(void)
/* do the header card stuff next */ /* do the header card stuff next */
__raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); __raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
__raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); __raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
for (i = 0; i < NR_IRQS; i++) {
if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
set_irq_chip(i, &sc_chip);
set_irq_handler(i, do_level_IRQ);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
}
} }
...@@ -29,40 +29,46 @@ extern void xs80200_init_irq(void); ...@@ -29,40 +29,46 @@ extern void xs80200_init_irq(void);
extern void do_IRQ(int, struct pt_regs *); extern void do_IRQ(int, struct pt_regs *);
u32 iop310_mask = 0; static u32 iop310_mask /* = 0 */;
static void static void iop310_irq_mask (unsigned int irq)
iop310_irq_mask (unsigned int irq)
{ {
iop310_mask |= (1 << (irq - IOP310_IRQ_OFS)); iop310_mask ++;
/* /*
* No mask bits on the 80312, so we have to * No mask bits on the 80312, so we have to
* mask everything from the outside! * mask everything from the outside!
*/ */
xs80200_irq_mask(IRQ_XS80200_EXTIRQ); if (iop310_mask == 1) {
disable_irq(IRQ_XS80200_EXTIRQ);
irq_desc[IRQ_XS80200_EXTIRQ].chip->mask(IRQ_XS80200_EXTIRQ);
}
} }
static void static void iop310_irq_unmask (unsigned int irq)
iop310_irq_unmask (unsigned int irq)
{ {
iop310_mask &= ~(1 << (irq - IOP310_IRQ_OFS)); if (iop310_mask)
iop310_mask --;
/* /*
* Check if all 80312 sources are unmasked now * Check if all 80312 sources are unmasked now
*/ */
if(!iop310_mask) if (iop310_mask == 0)
{ enable_irq(IRQ_XS80200_EXTIRQ);
xs80200_irq_unmask(IRQ_XS80200_EXTIRQ);
}
} }
void iop310_irq_demux(int irq, void *dev_id, struct irqchip ext_chip = {
struct pt_regs *regs) ack: iop310_irq_mask,
mask: iop310_irq_mask,
unmask: iop310_irq_unmask,
};
void
iop310_irq_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
u32 fiq1isr = *((volatile u32*)IOP310_FIQ1ISR); u32 fiq1isr = *((volatile u32*)IOP310_FIQ1ISR);
u32 fiq2isr = *((volatile u32*)IOP310_FIQ2ISR); u32 fiq2isr = *((volatile u32*)IOP310_FIQ2ISR);
struct irqdesc *d;
unsigned int irqno = 0; unsigned int irqno = 0;
if(fiq1isr) if(fiq1isr)
...@@ -86,22 +92,22 @@ void iop310_irq_demux(int irq, void *dev_id, ...@@ -86,22 +92,22 @@ void iop310_irq_demux(int irq, void *dev_id,
irqno = IRQ_IOP310_MU; irqno = IRQ_IOP310_MU;
} }
do_IRQ(irqno, regs); if (irqno) {
d = irq_desc + irqno;
d->handle(irqno, d, regs);
}
} }
void __init iop310_init_irq(void) void __init iop310_init_irq(void)
{ {
int i; unsigned int i;
for(i = IOP310_IRQ_OFS; i < NR_IOP310_IRQS; i++) for(i = IOP310_IRQ_OFS; i < NR_IOP310_IRQS; i++)
{ {
irq_desc[i].valid = 1; set_irq_chip(i, &ext_chip);
irq_desc[i].probe_ok = 1; set_irq_handler(i, do_level_IRQ);
irq_desc[i].mask_ack = iop310_irq_mask; set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
irq_desc[i].mask = iop310_irq_mask;
irq_desc[i].unmask = iop310_irq_unmask;
} }
xs80200_init_irq(); xs80200_init_irq();
} }
...@@ -27,121 +27,86 @@ ...@@ -27,121 +27,86 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
extern void xs80200_irq_mask(unsigned int); extern void iop310_init_irq(void);
extern void xs80200_irq_unmask(unsigned int); extern void iop310_irq_demux(unsigned int, struct irqdesc *, struct pt_regs *);
extern void xs80200_init_irq(void);
extern void do_IRQ(int, struct pt_regs *); static void iq80310_irq_mask(unsigned int irq)
{
*(volatile char *)IQ80310_INT_MASK |= (1 << (irq - IQ80310_IRQ_OFS));
}
extern u32 iop310_mask; static void iq80310_irq_unmask(unsigned int irq)
{
*(volatile char *)IQ80310_INT_MASK &= ~(1 << (irq - IQ80310_IRQ_OFS));
}
extern void iop310_irq_demux(int, void *, struct pt_regs *); static struct irqchip iq80310_irq_chip = {
ack: iq80310_irq_mask,
mask: iq80310_irq_mask,
unmask: iq80310_irq_unmask,
};
extern int iop310_init_irq(void); extern struct irqchip ext_chip;
static void static void
iq80310_irq_mask (unsigned int irq) iq80310_cpld_irq_handler(unsigned int irq, struct irqdesc *desc,
struct pt_regs *regs)
{ {
volatile char *mask = (volatile char *)IQ80310_INT_MASK; unsigned int irq_stat = *(volatile u8*)IQ80310_INT_STAT;
*mask |= (1 << (irq - IQ80310_IRQ_OFS)); unsigned int irq_mask = *(volatile u8*)IQ80310_INT_MASK;
unsigned int i, handled = 0;
struct irqdesc *d;
desc->chip->ack(irq);
/* /*
* There's no mask for PCI INT A-C, so we just mask out all * Mask out the interrupts which aren't enabled.
* external interrupts on the CPU.
*
* We set a bit of the iop310 mask so that the iop310_irq_mask
* function does not unmask EXTINT
*/ */
if (irq > IRQ_IQ80310_INTD) irq_stat &= 0x1f & ~irq_mask;
{
xs80200_irq_mask(IRQ_XS80200_EXTIRQ);
iop310_mask |= (0x80000000 >> (irq - IRQ_IQ80310_INTD));
}
}
static void
iq80310_irq_unmask (unsigned int irq)
{
volatile char *mask = (volatile char *)IQ80310_INT_MASK;
*mask &= ~(1 << (irq - IQ80310_IRQ_OFS));
/* /*
* See comment above * Test each IQ80310 CPLD interrupt
*/ */
if (irq > IRQ_IQ80310_INTD) for (i = IRQ_IQ80310_TIMER, d = irq_desc + IRQ_IQ80310_TIMER;
{ irq_stat; i++, d++, irq_stat >>= 1)
xs80200_irq_unmask(IRQ_XS80200_EXTIRQ); if (irq_stat & 1) {
iop310_mask &= ~((0x80000000 >> (irq - IRQ_IQ80310_INTD))); d->handle(i, d, regs);
} handled++;
}
static void iq80310_cpld_irq_demux(int irq, void *dev_id,
struct pt_regs *regs)
{
u8 irq_stat = *((volatile u8*)IQ80310_INT_STAT);
u8 irq_mask = *((volatile u8*)IQ80310_INT_MASK);
unsigned int irqno = 0xffffffff;
// Needed? If IRQ is masked, it shouldn't get through...
irq_stat &= ~irq_mask;
if(irq_stat & 0x01)
irqno = IRQ_IQ80310_TIMER;
else if(irq_stat & 0x02)
irqno = IRQ_IQ80310_I82559;
else if(irq_stat & 0x04)
irqno = IRQ_IQ80310_UART1;
else if(irq_stat & 0x08)
irqno = IRQ_IQ80310_UART2;
else if(irq_stat & 0x10)
irqno = IRQ_IQ80310_INTD;
else if(system_rev)
{
irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 0xf;
if(irq_stat & 0x1)
irqno = IRQ_IQ80310_INTA;
else if(irq_stat & 0x2)
irqno = IRQ_IQ80310_INTB;
else if(irq_stat & 0x4)
irqno = IRQ_IQ80310_INTC;
} }
else /* Running on a REV D.1 or older, assume PCI INTA */
irqno = IRQ_IQ80310_INTA;
/* /*
* If we didn't read a CPLD interrupt, we assume it's from * If running on a board later than REV D.1, we can
* a device on the chipset itself. * decode the PCI interrupt status.
*/ */
if(irqno == 0xffffffff) if (system_rev) {
{ irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 7;
iop310_irq_demux(irq, dev_id, regs);
return; for (i = IRQ_IQ80310_INTA, d = irq_desc + IRQ_IQ80310_INTA;
irq_stat; i++, d++, irq_stat >>= 1)
if (irq_stat & 0x1) {
d->handle(i, d, regs);
handled++;
}
} }
/* /*
* If on a REV D.1 or lower board, we just assumed INTA since * If on a REV D.1 or lower board, we just assumed INTA
* PCI is not routed, and it may actually be an on-chip interrupt. * since PCI is not routed, and it may actually be an
* on-chip interrupt.
*
* Note that we're giving on-chip interrupts slightly
* higher priority than PCI by handling them first.
* *
* Note that we're giving on-chip interrupts slightly higher * On boards later than REV D.1, if we didn't read a
* priority than PCI by handling them first. * CPLD interrupt, we assume it's from a device on the
* chipset itself.
*/ */
if(irqno == IRQ_IQ80310_INTA && !system_rev) if (system_rev == 0 || handled == 0)
iop310_irq_demux(irq, dev_id, regs); iop310_irq_demux(irq, desc, regs);
do_IRQ(irqno, regs); desc->chip->unmask(irq);
} }
static struct irqaction iq80310_cpld_irq = {
name: "CPLD_IRQ",
handler: iq80310_cpld_irq_demux,
flags: SA_INTERRUPT
};
extern int setup_arm_irq(int, struct irqaction *);
void __init iq80310_init_irq(void) void __init iq80310_init_irq(void)
{ {
volatile char *mask = (volatile char *)IQ80310_INT_MASK; volatile char *mask = (volatile char *)IQ80310_INT_MASK;
...@@ -154,17 +119,26 @@ void __init iq80310_init_irq(void) ...@@ -154,17 +119,26 @@ void __init iq80310_init_irq(void)
*/ */
*IOP310_PIRSR = 0xff; *IOP310_PIRSR = 0xff;
for (i = IQ80310_IRQ_OFS; i < NR_IRQS; i++) { /*
irq_desc[i].valid = 1; * Setup the IRQs in the FE820000/FE860000 registers
irq_desc[i].probe_ok = 1; */
irq_desc[i].mask_ack = iq80310_irq_mask; for (i = IQ80310_IRQ_OFS; i <= IRQ_IQ80310_INTD; i++) {
irq_desc[i].mask = iq80310_irq_mask; set_irq_chip(i, &iq80310_irq_chip);
irq_desc[i].unmask = iq80310_irq_unmask; set_irq_handler(i, do_level_IRQ);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
/*
* Setup the PCI IRQs
*/
for (i = IRQ_IQ80310_INTA; i < IRQ_IQ80310_INTC; i++) {
set_irq_chip(i, &ext_chip);
set_irq_handler(i, do_level_IRQ);
set_irq_flags(i, IRQF_VALID);
} }
*mask = 0xff; /* mask all sources */ *mask = 0xff; /* mask all sources */
setup_arm_irq(IRQ_XS80200_EXTIRQ, &iq80310_cpld_irq);
/* enable only external IRQ in the INTCTL for now */ set_irq_chained_handler(IRQ_XS80200_EXTIRQ,
asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (1<<1)); &iq80310_cpld_irq_handler);
} }
...@@ -11,25 +11,21 @@ ...@@ -11,25 +11,21 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/timex.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <asm/uaccess.h> #include <asm/hardware.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/timex.h>
#include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/irq.h>
static void iq80310_write_timer (u_long val) static void iq80310_write_timer (u_long val)
{ {
...@@ -109,14 +105,12 @@ static struct irqaction timer_irq = { ...@@ -109,14 +105,12 @@ static struct irqaction timer_irq = {
}; };
extern int setup_arm_irq(int, struct irqaction*);
void __init time_init(void) void __init time_init(void)
{ {
volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN; volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN;
gettimeoffset = iq80310_gettimeoffset; gettimeoffset = iq80310_gettimeoffset;
setup_arm_irq(IRQ_IQ80310_TIMER, &timer_irq); setup_irq(IRQ_IQ80310_TIMER, &timer_irq);
*timer_en = 0; *timer_en = 0;
iq80310_write_timer(LATCH); iq80310_write_timer(LATCH);
*timer_en |= 2; *timer_en |= 2;
......
...@@ -20,45 +20,47 @@ ...@@ -20,45 +20,47 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
void static void xs80200_irq_mask (unsigned int irq)
xs80200_irq_mask (unsigned int irq)
{ {
long INTCTL; unsigned long intctl;
asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (intctl));
switch (irq) { switch (irq) {
case IRQ_XS80200_BCU: INTCTL &= ~(1<<3); break; case IRQ_XS80200_BCU: intctl &= ~(1<<3); break;
case IRQ_XS80200_PMU: INTCTL &= ~(1<<2); break; case IRQ_XS80200_PMU: intctl &= ~(1<<2); break;
case IRQ_XS80200_EXTIRQ: INTCTL &= ~(1<<1); break; case IRQ_XS80200_EXTIRQ: intctl &= ~(1<<1); break;
case IRQ_XS80200_EXTFIQ: INTCTL &= ~(1<<0); break; case IRQ_XS80200_EXTFIQ: intctl &= ~(1<<0); break;
} }
asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (intctl));
} }
void static void xs80200_irq_unmask (unsigned int irq)
xs80200_irq_unmask (unsigned int irq)
{ {
long INTCTL; unsigned long intctl;
asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (intctl));
switch (irq) { switch (irq) {
case IRQ_XS80200_BCU: INTCTL |= (1<<3); break; case IRQ_XS80200_BCU: intctl |= (1<<3); break;
case IRQ_XS80200_PMU: INTCTL |= (1<<2); break; case IRQ_XS80200_PMU: intctl |= (1<<2); break;
case IRQ_XS80200_EXTIRQ: INTCTL |= (1<<1); break; case IRQ_XS80200_EXTIRQ: intctl |= (1<<1); break;
case IRQ_XS80200_EXTFIQ: INTCTL |= (1<<0); break; case IRQ_XS80200_EXTFIQ: intctl |= (1<<0); break;
} }
asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (intctl));
} }
static struct irqchip xs80200_chip = {
ack: xs80200_irq_mask,
mask: xs80200_irq_mask,
unmask: xs80200_irq_unmask,
};
void __init xs80200_init_irq(void) void __init xs80200_init_irq(void)
{ {
int i; unsigned int i;
asm("mcr p13, 0, %0, c0, c0, 0" : : "r" (0));
for (i = 0; i < NR_XS80200_IRQS; i++) { for (i = 0; i < NR_XS80200_IRQS; i++) {
irq_desc[i].valid = 1; set_irq_chip(i, &xs80200_chip);
irq_desc[i].probe_ok = 0; set_irq_handler(i, do_level_IRQ);
irq_desc[i].mask_ack = xs80200_irq_mask; set_irq_flags(i, IRQF_VALID);
irq_desc[i].mask = xs80200_irq_mask;
irq_desc[i].unmask = xs80200_irq_unmask;
} }
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
static void rpc_mask_irq_ack_a(unsigned int irq) static void iomd_ack_irq_a(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -15,7 +15,7 @@ static void rpc_mask_irq_ack_a(unsigned int irq) ...@@ -15,7 +15,7 @@ static void rpc_mask_irq_ack_a(unsigned int irq)
iomd_writeb(mask, IOMD_IRQCLRA); iomd_writeb(mask, IOMD_IRQCLRA);
} }
static void rpc_mask_irq_a(unsigned int irq) static void iomd_mask_irq_a(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -24,7 +24,7 @@ static void rpc_mask_irq_a(unsigned int irq) ...@@ -24,7 +24,7 @@ static void rpc_mask_irq_a(unsigned int irq)
iomd_writeb(val & ~mask, IOMD_IRQMASKA); iomd_writeb(val & ~mask, IOMD_IRQMASKA);
} }
static void rpc_unmask_irq_a(unsigned int irq) static void iomd_unmask_irq_a(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -33,7 +33,13 @@ static void rpc_unmask_irq_a(unsigned int irq) ...@@ -33,7 +33,13 @@ static void rpc_unmask_irq_a(unsigned int irq)
iomd_writeb(val | mask, IOMD_IRQMASKA); iomd_writeb(val | mask, IOMD_IRQMASKA);
} }
static void rpc_mask_irq_b(unsigned int irq) static struct irqchip iomd_a_chip = {
ack: iomd_ack_irq_a,
mask: iomd_mask_irq_a,
unmask: iomd_unmask_irq_a,
};
static void iomd_mask_irq_b(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -42,7 +48,7 @@ static void rpc_mask_irq_b(unsigned int irq) ...@@ -42,7 +48,7 @@ static void rpc_mask_irq_b(unsigned int irq)
iomd_writeb(val & ~mask, IOMD_IRQMASKB); iomd_writeb(val & ~mask, IOMD_IRQMASKB);
} }
static void rpc_unmask_irq_b(unsigned int irq) static void iomd_unmask_irq_b(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -51,7 +57,13 @@ static void rpc_unmask_irq_b(unsigned int irq) ...@@ -51,7 +57,13 @@ static void rpc_unmask_irq_b(unsigned int irq)
iomd_writeb(val | mask, IOMD_IRQMASKB); iomd_writeb(val | mask, IOMD_IRQMASKB);
} }
static void rpc_mask_irq_dma(unsigned int irq) static struct irqchip iomd_b_chip = {
ack: iomd_mask_irq_b,
mask: iomd_mask_irq_b,
unmask: iomd_unmask_irq_b,
};
static void iomd_mask_irq_dma(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -60,7 +72,7 @@ static void rpc_mask_irq_dma(unsigned int irq) ...@@ -60,7 +72,7 @@ static void rpc_mask_irq_dma(unsigned int irq)
iomd_writeb(val & ~mask, IOMD_DMAMASK); iomd_writeb(val & ~mask, IOMD_DMAMASK);
} }
static void rpc_unmask_irq_dma(unsigned int irq) static void iomd_unmask_irq_dma(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -69,7 +81,13 @@ static void rpc_unmask_irq_dma(unsigned int irq) ...@@ -69,7 +81,13 @@ static void rpc_unmask_irq_dma(unsigned int irq)
iomd_writeb(val | mask, IOMD_DMAMASK); iomd_writeb(val | mask, IOMD_DMAMASK);
} }
static void rpc_mask_irq_fiq(unsigned int irq) static struct irqchip iomd_dma_chip = {
ack: iomd_mask_irq_dma,
mask: iomd_mask_irq_dma,
unmask: iomd_unmask_irq_dma,
};
static void iomd_mask_irq_fiq(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -78,7 +96,7 @@ static void rpc_mask_irq_fiq(unsigned int irq) ...@@ -78,7 +96,7 @@ static void rpc_mask_irq_fiq(unsigned int irq)
iomd_writeb(val & ~mask, IOMD_FIQMASK); iomd_writeb(val & ~mask, IOMD_FIQMASK);
} }
static void rpc_unmask_irq_fiq(unsigned int irq) static void iomd_unmask_irq_fiq(unsigned int irq)
{ {
unsigned int val, mask; unsigned int val, mask;
...@@ -87,9 +105,15 @@ static void rpc_unmask_irq_fiq(unsigned int irq) ...@@ -87,9 +105,15 @@ static void rpc_unmask_irq_fiq(unsigned int irq)
iomd_writeb(val | mask, IOMD_FIQMASK); iomd_writeb(val | mask, IOMD_FIQMASK);
} }
static struct irqchip iomd_fiq_chip = {
ack: iomd_mask_irq_fiq,
mask: iomd_mask_irq_fiq,
unmask: iomd_unmask_irq_fiq,
};
void __init rpc_init_irq(void) void __init rpc_init_irq(void)
{ {
int irq; unsigned int irq, flags;
iomd_writeb(0, IOMD_IRQMASKA); iomd_writeb(0, IOMD_IRQMASKA);
iomd_writeb(0, IOMD_IRQMASKB); iomd_writeb(0, IOMD_IRQMASKB);
...@@ -97,46 +121,41 @@ void __init rpc_init_irq(void) ...@@ -97,46 +121,41 @@ void __init rpc_init_irq(void)
iomd_writeb(0, IOMD_DMAMASK); iomd_writeb(0, IOMD_DMAMASK);
for (irq = 0; irq < NR_IRQS; irq++) { for (irq = 0; irq < NR_IRQS; irq++) {
flags = IRQF_VALID;
if (irq <= 6 || (irq >= 9 && irq <= 15))
flags |= IRQF_PROBE;
if (irq == 21 || (irq >= 16 && irq <= 19) ||
irq == IRQ_KEYBOARDTX)
flags |= IRQF_NOAUTOEN;
switch (irq) { switch (irq) {
case 0 ... 6: case 0 ... 7:
irq_desc[irq].probe_ok = 1; set_irq_chip(irq, &iomd_a_chip);
case 7: set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].valid = 1; set_irq_flags(irq, flags);
irq_desc[irq].mask_ack = rpc_mask_irq_ack_a;
irq_desc[irq].mask = rpc_mask_irq_a;
irq_desc[irq].unmask = rpc_unmask_irq_a;
break; break;
case 9 ... 15: case 8 ... 15:
irq_desc[irq].probe_ok = 1; set_irq_chip(irq, &iomd_b_chip);
case 8: set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].valid = 1; set_irq_flags(irq, flags);
irq_desc[irq].mask_ack = rpc_mask_irq_b;
irq_desc[irq].mask = rpc_mask_irq_b;
irq_desc[irq].unmask = rpc_unmask_irq_b;
break; break;
case 16 ... 19: case 16 ... 21:
case 21: set_irq_chip(irq, &iomd_dma_chip);
irq_desc[irq].noautoenable = 1; set_irq_handler(irq, do_level_IRQ);
case 20: set_irq_flags(irq, flags);
irq_desc[irq].valid = 1;
irq_desc[irq].mask_ack = rpc_mask_irq_dma;
irq_desc[irq].mask = rpc_mask_irq_dma;
irq_desc[irq].unmask = rpc_unmask_irq_dma;
break; break;
case 64 ... 71: case 64 ... 71:
irq_desc[irq].valid = 1; set_irq_chip(irq, &iomd_fiq_chip);
irq_desc[irq].mask_ack = rpc_mask_irq_fiq; set_irq_flags(irq, IRQF_VALID);
irq_desc[irq].mask = rpc_mask_irq_fiq;
irq_desc[irq].unmask = rpc_unmask_irq_fiq;
break; break;
} }
} }
irq_desc[IRQ_KEYBOARDTX].noautoenable = 1;
init_FIQ(); init_FIQ();
} }
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -89,7 +90,7 @@ static int __init assabet_init(void) ...@@ -89,7 +90,7 @@ static int __init assabet_init(void)
/* /*
* Set the IRQ edges * Set the IRQ edges
*/ */
set_GPIO_IRQ_edge(GPIO_GPIO23, GPIO_RISING_EDGE); /* UCB1300 */ set_irq_type(IRQ_GPIO23, IRQT_RISING); /* UCB1300 */
sa1100fb_lcd_power = assabet_lcd_power; sa1100fb_lcd_power = assabet_lcd_power;
sa1100fb_backlight_power = assabet_backlight_power; sa1100fb_backlight_power = assabet_backlight_power;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <asm/irq.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -26,12 +27,12 @@ static void __init cerf_init_irq(void) ...@@ -26,12 +27,12 @@ static void __init cerf_init_irq(void)
*/ */
#ifdef CONFIG_SA1100_CERF_CPLD #ifdef CONFIG_SA1100_CERF_CPLD
/* PDA Full serial port */ /* PDA Full serial port */
set_GPIO_IRQ_edge(GPIO_GPIO3, GPIO_RISING_EDGE); set_irq_type(IRQ_GPIO3, IRQT_RISING);
/* PDA Bluetooth */ /* PDA Bluetooth */
set_GPIO_IRQ_edge(GPIO_GPIO2, GPIO_RISING_EDGE); set_irq_type(IRQ_GPIO2, IRQT_RISING);
#endif /* CONFIG_SA1100_CERF_CPLD */ #endif /* CONFIG_SA1100_CERF_CPLD */
set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE); set_irq_type(IRQ_GPIO_UCB1200_IRQ, IRQT_RISING);
} }
static void __init static void __init
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <asm/arch/irq.h>
#include "generic.h" #include "generic.h"
...@@ -68,6 +66,12 @@ static void ADS_unmask_irq0(unsigned int irq) ...@@ -68,6 +66,12 @@ static void ADS_unmask_irq0(unsigned int irq)
ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0))); ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0)));
} }
static struct irqchip ADS0_chip = {
ack: ADS_mask_and_ack_irq0,
mask: ADS_mask_irq0,
unmask: ADS_unmask_irq0,
};
static void ADS_mask_and_ack_irq1(unsigned int irq) static void ADS_mask_and_ack_irq1(unsigned int irq)
{ {
int mask = (1 << (irq - ADS_EXT_IRQ(8))); int mask = (1 << (irq - ADS_EXT_IRQ(8)));
...@@ -85,9 +89,15 @@ static void ADS_unmask_irq1(unsigned int irq) ...@@ -85,9 +89,15 @@ static void ADS_unmask_irq1(unsigned int irq)
ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8))); ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8)));
} }
static struct irqchip ADS1_chip = {
ack: ADS_mask_and_ack_irq1,
mask: ADS_mask_irq1,
unmask: ADS_unmask_irq1,
};
static void __init graphicsclient_init_irq(void) static void __init graphicsclient_init_irq(void)
{ {
int irq; unsigned int irq;
/* First the standard SA1100 IRQs */ /* First the standard SA1100 IRQs */
sa1100_init_irq(); sa1100_init_irq();
...@@ -100,18 +110,14 @@ static void __init graphicsclient_init_irq(void) ...@@ -100,18 +110,14 @@ static void __init graphicsclient_init_irq(void)
ADS_INT_ST2 = 0xff; ADS_INT_ST2 = 0xff;
for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) { for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &ADS0_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].mask_ack = ADS_mask_and_ack_irq0; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = ADS_mask_irq0;
irq_desc[irq].unmask = ADS_unmask_irq0;
} }
for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) { for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &ADS1_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].mask_ack = ADS_mask_and_ack_irq1; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = ADS_mask_irq1;
irq_desc[irq].unmask = ADS_unmask_irq1;
} }
set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
...@@ -148,6 +154,8 @@ static struct gc_uart_ctrl_data_t gc_uart_ctrl_data[] = { ...@@ -148,6 +154,8 @@ static struct gc_uart_ctrl_data_t gc_uart_ctrl_data[] = {
{ GPIO_GC_UART2_CTS, 0, NULL,NULL } { GPIO_GC_UART2_CTS, 0, NULL,NULL }
}; };
#error Old code. Someone needs to decide what to do with this
#if 0
static void static void
graphicsclient_cts_intr(int irq, void *dev_id, struct pt_regs *regs) graphicsclient_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
{ {
...@@ -243,6 +251,7 @@ graphicsclient_uart_close(struct uart_port *port, struct uart_info *info) ...@@ -243,6 +251,7 @@ graphicsclient_uart_close(struct uart_port *port, struct uart_info *info)
return 0; return 0;
} }
#endif
static u_int graphicsclient_get_mctrl(struct uart_port *port) static u_int graphicsclient_get_mctrl(struct uart_port *port)
{ {
...@@ -296,8 +305,6 @@ graphicsclient_uart_pm(struct uart_port *port, u_int state, u_int oldstate) ...@@ -296,8 +305,6 @@ graphicsclient_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
} }
static struct sa1100_port_fns graphicsclient_port_fns __initdata = { static struct sa1100_port_fns graphicsclient_port_fns __initdata = {
open: graphicsclient_uart_open,
close: graphicsclient_uart_close,
get_mctrl: graphicsclient_get_mctrl, get_mctrl: graphicsclient_get_mctrl,
set_mctrl: graphicsclient_set_mctrl, set_mctrl: graphicsclient_set_mctrl,
pm: graphicsclient_uart_pm, pm: graphicsclient_uart_pm,
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include <asm/arch/irq.h>
#include "generic.h" #include "generic.h"
#include "sa1111.h" #include "sa1111.h"
...@@ -130,6 +128,12 @@ static void ADS_unmask_irq0(unsigned int irq) ...@@ -130,6 +128,12 @@ static void ADS_unmask_irq0(unsigned int irq)
ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0))); ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0)));
} }
static struct irqchip ADS0_chip = {
ack: ADS_mask_and_ack_irq0,
mask: ADS_mask_irq0,
unmask: ADS_unmask_irq0,
};
static void ADS_mask_and_ack_irq1(unsigned int irq) static void ADS_mask_and_ack_irq1(unsigned int irq)
{ {
int mask = (1 << (irq - ADS_EXT_IRQ(8))); int mask = (1 << (irq - ADS_EXT_IRQ(8)));
...@@ -147,9 +151,15 @@ static void ADS_unmask_irq1(unsigned int irq) ...@@ -147,9 +151,15 @@ static void ADS_unmask_irq1(unsigned int irq)
ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8))); ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8)));
} }
static struct irqchip ADS1_chip = {
ack: ADS_mask_irq1,
mask: ADS_mask_irq1,
unmask: ADS_mask_irq1,
};
static void __init graphicsmaster_init_irq(void) static void __init graphicsmaster_init_irq(void)
{ {
int irq; unsigned int irq;
/* First the standard SA1100 IRQs */ /* First the standard SA1100 IRQs */
sa1100_init_irq(); sa1100_init_irq();
...@@ -162,18 +172,14 @@ static void __init graphicsmaster_init_irq(void) ...@@ -162,18 +172,14 @@ static void __init graphicsmaster_init_irq(void)
ADS_INT_ST2 = 0xff; ADS_INT_ST2 = 0xff;
for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) { for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &ADS0_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].mask_ack = ADS_mask_and_ack_irq0; set_irq_flags(irq, IRQF_PROBE | IRQF_VALID);
irq_desc[irq].mask = ADS_mask_irq0;
irq_desc[irq].unmask = ADS_unmask_irq0;
} }
for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) { for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &ADS1_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].mask_ack = ADS_mask_and_ack_irq1; set_irq_flags(irq, IRQF_PROBE | IRQF_VALID);
irq_desc[irq].mask = ADS_mask_irq1;
irq_desc[irq].unmask = ADS_unmask_irq1;
} }
set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
...@@ -206,6 +212,8 @@ static struct map_desc graphicsmaster_io_desc[] __initdata = { ...@@ -206,6 +212,8 @@ static struct map_desc graphicsmaster_io_desc[] __initdata = {
LAST_DESC LAST_DESC
}; };
#error Old code. Someone needs to decide what to do about this.
#if 0
static int graphicsmaster_uart_open(struct uart_port *port, struct uart_info *info) static int graphicsmaster_uart_open(struct uart_port *port, struct uart_info *info)
{ {
int ret = 0; int ret = 0;
...@@ -226,6 +234,7 @@ static int graphicsmaster_uart_open(struct uart_port *port, struct uart_info *in ...@@ -226,6 +234,7 @@ static int graphicsmaster_uart_open(struct uart_port *port, struct uart_info *in
} }
return ret; return ret;
} }
#endif
static u_int graphicsmaster_get_mctrl(struct uart_port *port) static u_int graphicsmaster_get_mctrl(struct uart_port *port)
{ {
...@@ -279,7 +288,6 @@ graphicsmaster_uart_pm(struct uart_port *port, u_int state, u_int oldstate) ...@@ -279,7 +288,6 @@ graphicsmaster_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
} }
static struct sa1100_port_fns graphicsmaster_port_fns __initdata = { static struct sa1100_port_fns graphicsmaster_port_fns __initdata = {
open: graphicsmaster_uart_open,
get_mctrl: graphicsmaster_get_mctrl, get_mctrl: graphicsmaster_get_mctrl,
set_mctrl: graphicsmaster_set_mctrl, set_mctrl: graphicsmaster_set_mctrl,
pm: graphicsmaster_uart_pm, pm: graphicsmaster_uart_pm,
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/arch/irq.h>
#include "generic.h" #include "generic.h"
...@@ -30,156 +29,170 @@ ...@@ -30,156 +29,170 @@
* This must be called *before* the appropriate IRQ is registered. * This must be called *before* the appropriate IRQ is registered.
* Use this instead of directly setting GRER/GFER. * Use this instead of directly setting GRER/GFER.
*/ */
static int GPIO_IRQ_rising_edge; static int GPIO_IRQ_rising_edge;
static int GPIO_IRQ_falling_edge; static int GPIO_IRQ_falling_edge;
static int GPIO_IRQ_mask = (1 << 11) - 1;
void set_GPIO_IRQ_edge( int gpio_mask, int edge ) static void sa1100_manual_rerun(unsigned int irq)
{ {
int flags; struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
local_irq_save(flags); irq_desc[irq].handle(irq, &irq_desc[irq], &regs);
if (edge & GPIO_FALLING_EDGE)
GPIO_IRQ_falling_edge |= gpio_mask;
else
GPIO_IRQ_falling_edge &= ~gpio_mask;
if (edge & GPIO_RISING_EDGE)
GPIO_IRQ_rising_edge |= gpio_mask;
else
GPIO_IRQ_rising_edge &= ~gpio_mask;
GPDR &= ~gpio_mask;
GAFR &= ~gpio_mask;
restore_flags(flags);
} }
EXPORT_SYMBOL(set_GPIO_IRQ_edge); #define GPIO11_27_MASK(irq) (1 << GPIO_11_27_IRQ(irq))
static int sa1100_gpio_type(unsigned int irq, unsigned int type)
{
unsigned int mask;
/* printk(KERN_DEBUG "IRQ%d: ", irq);
* We don't need to ACK IRQs on the SA1100 unless they're GPIOs
* this is for internal IRQs i.e. from 11 to 31.
*/
static void sa1100_mask_irq(unsigned int irq) if (irq <= 10)
{ mask = 1 << irq;
ICMR &= ~(1 << irq); else
} mask = GPIO11_27_MASK(irq);
static void sa1100_unmask_irq(unsigned int irq) if (type & __IRQT_RISEDGE) {
{ printk("rising ");
ICMR |= (1 << irq); GPIO_IRQ_rising_edge |= mask;
} else
GPIO_IRQ_rising_edge &= ~mask;
if (type & __IRQT_FALEDGE) {
printk("falling ");
GPIO_IRQ_falling_edge |= mask;
} else
GPIO_IRQ_falling_edge &= ~mask;
printk("edges\n");
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
return 0;
} }
/* /*
* GPIO IRQs must be acknoledged. This is for IRQs from 0 to 10. * GPIO IRQs must be acknoledged. This is for IRQs from 0 to 10.
*/ */
static void sa1100_low_gpio_ack(unsigned int irq)
static void sa1100_mask_and_ack_GPIO0_10_irq(unsigned int irq)
{ {
ICMR &= ~(1 << irq);
GEDR = (1 << irq); GEDR = (1 << irq);
} }
static void sa1100_mask_GPIO0_10_irq(unsigned int irq) static void sa1100_low_gpio_mask(unsigned int irq)
{ {
ICMR &= ~(1 << irq); ICMR &= ~(1 << irq);
} }
static void sa1100_unmask_GPIO0_10_irq(unsigned int irq) static void sa1100_low_gpio_unmask(unsigned int irq)
{ {
GRER = (GRER & ~(1 << irq)) | (GPIO_IRQ_rising_edge & (1 << irq)); ICMR |= 1 << irq;
GFER = (GFER & ~(1 << irq)) | (GPIO_IRQ_falling_edge & (1 << irq));
ICMR |= (1 << irq);
} }
static struct irqchip sa1100_low_gpio_chip = {
ack: sa1100_low_gpio_ack,
mask: sa1100_low_gpio_mask,
unmask: sa1100_low_gpio_unmask,
rerun: sa1100_manual_rerun,
type: sa1100_gpio_type,
};
/* /*
* Install handler for GPIO 11-27 edge detect interrupts * IRQ11 (GPIO11 through 27) handler. We enter here with the
* irq_controller_lock held, and IRQs disabled. Decode the IRQ
* and call the handler.
*/ */
static void
static int GPIO_11_27_enabled; /* enabled i.e. unmasked GPIO IRQs */ sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc,
static int GPIO_11_27_spurious; /* GPIOs that triggered when masked */
static void sa1100_GPIO11_27_demux(int irq, void *dev_id,
struct pt_regs *regs) struct pt_regs *regs)
{ {
int i, spurious; unsigned int mask;
while ((irq = (GEDR & 0xfffff800))) { mask = GEDR & 0xfffff800;
do {
/* /*
* We don't want to clear GRER/GFER when the corresponding * clear down all currently active IRQ sources.
* IRQ is masked because we could miss a level transition * We will be processing them all.
* i.e. an IRQ which need servicing as soon as it is
* unmasked. However, such situation should happen only
* during the loop below. Thus all IRQs which aren't
* enabled at this point are considered spurious. Those
* are cleared but only de-activated if they happen twice.
*/ */
spurious = irq & ~GPIO_11_27_enabled; GEDR = mask;
if (spurious) {
GEDR = spurious;
GRER &= ~(spurious & GPIO_11_27_spurious);
GFER &= ~(spurious & GPIO_11_27_spurious);
GPIO_11_27_spurious |= spurious;
irq ^= spurious;
if (!irq) continue;
}
for (i = 11; i <= 27; ++i) { irq = IRQ_GPIO11;
if (irq & (1<<i)) { desc = irq_desc + irq;
do_IRQ(IRQ_GPIO11 + i - 11, regs); mask >>= 11;
} do {
} if (mask & 1)
} desc->handle(irq, desc, regs);
mask >>= 1;
irq++;
desc++;
} while (mask);
mask = GEDR & 0xfffff800;
} while (mask);
} }
static struct irqaction GPIO11_27_irq = { /*
name: "GPIO 11-27", * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially.
handler: sa1100_GPIO11_27_demux, * In addition, the IRQs are all collected up into one bit in the
flags: SA_INTERRUPT * interrupt controller registers.
}; */
static void sa1100_high_gpio_ack(unsigned int irq)
static void sa1100_mask_and_ack_GPIO11_27_irq(unsigned int irq)
{ {
int mask = (1 << GPIO_11_27_IRQ(irq)); unsigned int mask = GPIO11_27_MASK(irq);
GPIO_11_27_spurious &= ~mask;
GPIO_11_27_enabled &= ~mask;
GEDR = mask; GEDR = mask;
} }
static void sa1100_mask_GPIO11_27_irq(unsigned int irq) static void sa1100_high_gpio_mask(unsigned int irq)
{ {
int mask = (1 << GPIO_11_27_IRQ(irq)); unsigned int mask = GPIO11_27_MASK(irq);
GPIO_11_27_spurious &= ~mask;
GPIO_11_27_enabled &= ~mask; GPIO_IRQ_mask &= ~mask;
GRER &= ~mask;
GFER &= ~mask;
} }
static void sa1100_unmask_GPIO11_27_irq(unsigned int irq) static void sa1100_high_gpio_unmask(unsigned int irq)
{ {
int mask = (1 << GPIO_11_27_IRQ(irq)); unsigned int mask = GPIO11_27_MASK(irq);
if (GPIO_11_27_spurious & mask) {
/* GPIO_IRQ_mask |= mask;
* We don't want to miss an interrupt that would have occurred
* while it was masked. Simulate it if it is the case. GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
}
static struct irqchip sa1100_high_gpio_chip = {
ack: sa1100_high_gpio_ack,
mask: sa1100_high_gpio_mask,
unmask: sa1100_high_gpio_unmask,
rerun: sa1100_manual_rerun,
type: sa1100_gpio_type,
};
/*
* We don't need to ACK IRQs on the SA1100 unless they're GPIOs
* this is for internal IRQs i.e. from 11 to 31.
*/ */
int state = GPLR; static void sa1100_mask_irq(unsigned int irq)
if (((state & GPIO_IRQ_rising_edge) | {
(~state & GPIO_IRQ_falling_edge)) & mask) ICMR &= ~(1 << irq);
{ }
/* just in case it gets referenced: */
struct pt_regs dummy; static void sa1100_unmask_irq(unsigned int irq)
{
memzero(&dummy, sizeof(dummy)); ICMR |= (1 << irq);
do_IRQ(irq, &dummy);
/* we are being called recursively from do_IRQ() */
return;
}
}
GPIO_11_27_enabled |= mask;
GRER = (GRER & ~mask) | (GPIO_IRQ_rising_edge & mask);
GFER = (GFER & ~mask) | (GPIO_IRQ_falling_edge & mask);
} }
static struct irqchip sa1100_normal_chip = {
ack: sa1100_mask_irq,
mask: sa1100_mask_irq,
unmask: sa1100_unmask_irq,
/* rerun should never be called */
};
static struct resource irq_resource = { static struct resource irq_resource = {
name: "irqs", name: "irqs",
start: 0x90050000, start: 0x90050000,
...@@ -188,7 +201,7 @@ static struct resource irq_resource = { ...@@ -188,7 +201,7 @@ static struct resource irq_resource = {
void __init sa1100_init_irq(void) void __init sa1100_init_irq(void)
{ {
int irq; unsigned int irq;
request_resource(&iomem_resource, &irq_resource); request_resource(&iomem_resource, &irq_resource);
...@@ -210,33 +223,32 @@ void __init sa1100_init_irq(void) ...@@ -210,33 +223,32 @@ void __init sa1100_init_irq(void)
ICCR = 1; ICCR = 1;
for (irq = 0; irq <= 10; irq++) { for (irq = 0; irq <= 10; irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &sa1100_low_gpio_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_edge_IRQ);
irq_desc[irq].mask_ack = sa1100_mask_and_ack_GPIO0_10_irq; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = sa1100_mask_GPIO0_10_irq;
irq_desc[irq].unmask = sa1100_unmask_GPIO0_10_irq;
} }
for (irq = 11; irq <= 31; irq++) { for (irq = 12; irq <= 31; irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &sa1100_normal_chip);
irq_desc[irq].probe_ok = 0; set_irq_handler(irq, do_level_IRQ);
irq_desc[irq].mask_ack = sa1100_mask_irq; set_irq_flags(irq, IRQF_VALID);
irq_desc[irq].mask = sa1100_mask_irq;
irq_desc[irq].unmask = sa1100_unmask_irq;
} }
for (irq = 32; irq <= 48; irq++) { for (irq = 32; irq <= 48; irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &sa1100_high_gpio_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_edge_IRQ);
irq_desc[irq].mask_ack = sa1100_mask_and_ack_GPIO11_27_irq; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = sa1100_mask_GPIO11_27_irq;
irq_desc[irq].unmask = sa1100_unmask_GPIO11_27_irq;
} }
setup_arm_irq( IRQ_GPIO11_27, &GPIO11_27_irq );
/*
* Install handler for GPIO 11-27 edge detect interrupts
*/
set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip);
set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler);
/* /*
* We generally don't want the LCD IRQ being * We generally don't want the LCD IRQ being
* enabled as soon as we request it. * enabled as soon as we request it.
*/ */
irq_desc[IRQ_LCD].noautoenable = 1; set_irq_flags(IRQ_LCD, IRQF_VALID | IRQF_NOAUTOEN);
} }
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/arch/irq.h>
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include <asm/arch/assabet.h> #include <asm/arch/assabet.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
...@@ -24,53 +23,78 @@ ...@@ -24,53 +23,78 @@
/* /*
* Install handler for Neponset IRQ. Yes, yes... we are way down the IRQ * Install handler for Neponset IRQ. Note that we have to loop here
* cascade which is not good for IRQ latency, but the hardware has been * since the ETHERNET and USAR IRQs are level based, and we need to
* designed that way... * ensure that the IRQ signal is deasserted before returning. This
* is rather unfortunate.
*/ */
static void
static void neponset_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
int irr; unsigned int irr;
while (1) {
struct irqdesc *d;
for(;;){ /*
irr = IRR & (IRR_ETHERNET | IRR_USAR | IRR_SA1111); * Acknowledge the parent IRQ.
/* Let's have all active IRQ bits high.
* Note: there is a typo in the Neponset user's guide
* for the SA1111 IRR level.
*/ */
irr ^= (IRR_ETHERNET | IRR_USAR); desc->chip->ack(irq);
if (!irr) break;
/*
* Read the interrupt reason register. Let's have all
* active IRQ bits high. Note: there is a typo in the
* Neponset user's guide for the SA1111 IRR level.
*/
irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
break;
if( irr & IRR_ETHERNET ) /*
do_IRQ(IRQ_NEPONSET_SMC9196, regs); * Since there is no individual mask, we have to
* mask the parent IRQ. This is safe, since we'll
* recheck the register for any pending IRQs.
*/
if (irr & (IRR_ETHERNET | IRR_USAR)) {
desc->chip->mask(irq);
if( irr & IRR_USAR ) if (irr & IRR_ETHERNET) {
do_IRQ(IRQ_NEPONSET_USAR, regs); d = irq_desc + IRQ_NEPONSET_SMC9196;
d->handle(IRQ_NEPONSET_SMC9196, d, regs);
}
if( irr & IRR_SA1111 ) if (irr & IRR_USAR) {
sa1111_IRQ_demux(irq, dev_id, regs); d = irq_desc + IRQ_NEPONSET_USAR;
d->handle(IRQ_NEPONSET_USAR, d, regs);
} }
}
static struct irqaction neponset_irq = { desc->chip->unmask(irq);
name: "Neponset", }
handler: neponset_IRQ_demux,
flags: SA_INTERRUPT if (irr & IRR_SA1111) {
}; d = irq_desc + IRQ_NEPONSET_SA1111;
d->handle(IRQ_NEPONSET_SA1111, d, regs);
}
}
}
static void __init neponset_init_irq(void) static void __init neponset_init_irq(void)
{ {
sa1111_init_irq(-1); /* SA1111 IRQ not routed to a GPIO */ /*
* Install handler for GPIO25.
/* setup extra Neponset IRQs */ */
irq_desc[IRQ_NEPONSET_SMC9196].valid = 1; set_irq_type(IRQ_GPIO25, IRQT_RISING);
irq_desc[IRQ_NEPONSET_SMC9196].probe_ok = 1; set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler);
irq_desc[IRQ_NEPONSET_USAR].valid = 1;
irq_desc[IRQ_NEPONSET_USAR].probe_ok = 1;
set_GPIO_IRQ_edge(GPIO_GPIO25, GPIO_RISING_EDGE); /*
setup_arm_irq(IRQ_GPIO25, &neponset_irq); * Setup other Neponset IRQs. SA1111 will be done by the
* generic SA1111 code.
*/
set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ);
set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ);
set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
} }
static int __init neponset_init(void) static int __init neponset_init(void)
...@@ -101,6 +125,8 @@ static int __init neponset_init(void) ...@@ -101,6 +125,8 @@ static int __init neponset_init(void)
return -ENODEV; return -ENODEV;
} }
neponset_init_irq();
/* /*
* Disable GPIO 0/1 drivers so the buttons work on the module. * Disable GPIO 0/1 drivers so the buttons work on the module.
*/ */
...@@ -146,7 +172,10 @@ static int __init neponset_init(void) ...@@ -146,7 +172,10 @@ static int __init neponset_init(void)
*/ */
sa1110_mb_enable(); sa1110_mb_enable();
neponset_init_irq(); /*
* Initialise SA1111 IRQs
*/
sa1111_init_irq(IRQ_NEPONSET_SA1111);
return 0; return 0;
} }
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/arch/irq.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
...@@ -40,70 +39,104 @@ struct resource sa1111_resource = { ...@@ -40,70 +39,104 @@ struct resource sa1111_resource = {
EXPORT_SYMBOL(sa1111_resource); EXPORT_SYMBOL(sa1111_resource);
/* /*
* SA1111 interrupt support * SA1111 interrupt support. Since clearing an IRQ while there are
* active IRQs causes the interrupt output to pulse, the upper levels
* will call us again if there are more interrupts to process.
*/ */
void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs) static void
sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
unsigned long stat0, stat1; unsigned int stat0, stat1, i;
while (1) { desc->chip->ack(irq);
int i;
stat0 = INTSTATCLR0; stat0 = INTSTATCLR0;
stat1 = INTSTATCLR1; stat1 = INTSTATCLR1;
if (stat0 == 0 && stat1 == 0) if (stat0 == 0 && stat1 == 0) {
break; do_bad_IRQ(irq, desc, regs);
return;
}
for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1)
if (stat0 & 1) if (stat0 & 1)
do_IRQ(i, regs); do_edge_IRQ(i, irq_desc + i, regs);
for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1)
if (stat1 & 1) if (stat1 & 1)
do_IRQ(i, regs); do_edge_IRQ(i, irq_desc + i, regs);
}
} }
#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) #define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START))
#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) #define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32))
static void sa1111_ack_lowirq(unsigned int irq)
{
INTSTATCLR0 = SA1111_IRQMASK_LO(irq);
}
static void sa1111_mask_lowirq(unsigned int irq)
{
INTEN0 &= ~SA1111_IRQMASK_LO(irq);
}
static void sa1111_unmask_lowirq(unsigned int irq)
{
INTEN0 |= SA1111_IRQMASK_LO(irq);
}
/* /*
* A note about masking IRQs: * Attempt to re-trigger the interrupt. The SA1111 contains a register
* * (INTSET) which claims to do this. However, in practice no amount of
* The GPIO IRQ edge detection only functions while the IRQ itself is * manipulation of INTEN and INTSET guarantees that the interrupt will
* enabled; edges are not detected while the IRQ is disabled. * be triggered. In fact, its very difficult, if not impossible to get
* * INTSET to re-trigger the interrupt.
* This is especially important for the PCMCIA signals, where we must
* pick up every transition. We therefore do not disable the IRQs
* while processing them.
*
* However, since we are changed to a GPIO on the host processor,
* all SA1111 IRQs will be disabled while we're processing any SA1111
* IRQ.
*
* Note also that changing INTPOL while an IRQ is enabled will itself
* trigger an IRQ.
*/ */
static void sa1111_mask_and_ack_lowirq(unsigned int irq) static void sa1111_rerun_lowirq(unsigned int irq)
{ {
unsigned int mask = SA1111_IRQMASK_LO(irq); unsigned int mask = SA1111_IRQMASK_LO(irq);
int i;
for (i = 0; i < 8; i++) {
INTPOL0 ^= mask;
INTPOL0 ^= mask;
if (INTSTATCLR1 & mask)
break;
}
//INTEN0 &= ~mask; if (i == 8)
INTSTATCLR0 = mask; printk(KERN_ERR "Danger Will Robinson: failed to "
"re-trigger IRQ%d\n", irq);
} }
static void sa1111_mask_and_ack_highirq(unsigned int irq) static int sa1111_type_lowirq(unsigned int irq, unsigned int flags)
{ {
unsigned int mask = SA1111_IRQMASK_HI(irq); unsigned int mask = SA1111_IRQMASK_LO(irq);
if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0)
return -EINVAL;
//INTEN1 &= ~mask; printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling");
INTSTATCLR1 = mask;
if (flags & __IRQT_RISEDGE)
INTPOL0 &= ~mask;
else
INTPOL0 |= mask;
return 0;
} }
static void sa1111_mask_lowirq(unsigned int irq) static struct irqchip sa1111_low_chip = {
ack: sa1111_ack_lowirq,
mask: sa1111_mask_lowirq,
unmask: sa1111_unmask_lowirq,
rerun: sa1111_rerun_lowirq,
type: sa1111_type_lowirq,
};
static void sa1111_ack_highirq(unsigned int irq)
{ {
INTEN0 &= ~SA1111_IRQMASK_LO(irq); INTSTATCLR1 = SA1111_IRQMASK_HI(irq);
} }
static void sa1111_mask_highirq(unsigned int irq) static void sa1111_mask_highirq(unsigned int irq)
...@@ -111,19 +144,63 @@ static void sa1111_mask_highirq(unsigned int irq) ...@@ -111,19 +144,63 @@ static void sa1111_mask_highirq(unsigned int irq)
INTEN1 &= ~SA1111_IRQMASK_HI(irq); INTEN1 &= ~SA1111_IRQMASK_HI(irq);
} }
static void sa1111_unmask_lowirq(unsigned int irq) static void sa1111_unmask_highirq(unsigned int irq)
{ {
INTEN0 |= SA1111_IRQMASK_LO(irq); INTEN1 |= SA1111_IRQMASK_HI(irq);
} }
static void sa1111_unmask_highirq(unsigned int irq) /*
* Attempt to re-trigger the interrupt. The SA1111 contains a register
* (INTSET) which claims to do this. However, in practice no amount of
* manipulation of INTEN and INTSET guarantees that the interrupt will
* be triggered. In fact, its very difficult, if not impossible to get
* INTSET to re-trigger the interrupt.
*/
static void sa1111_rerun_highirq(unsigned int irq)
{ {
INTEN1 |= SA1111_IRQMASK_HI(irq); unsigned int mask = SA1111_IRQMASK_HI(irq);
int i;
for (i = 0; i < 8; i++) {
INTPOL1 ^= mask;
INTPOL1 ^= mask;
if (INTSTATCLR1 & mask)
break;
}
if (i == 8)
printk(KERN_ERR "Danger Will Robinson: failed to "
"re-trigger IRQ%d\n", irq);
} }
static int sa1111_type_highirq(unsigned int irq, unsigned int flags)
{
unsigned int mask = SA1111_IRQMASK_HI(irq);
if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0)
return -EINVAL;
printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling");
if (flags & __IRQT_RISEDGE)
INTPOL1 &= ~mask;
else
INTPOL1 |= mask;
return 0;
}
static struct irqchip sa1111_high_chip = {
ack: sa1111_ack_highirq,
mask: sa1111_mask_highirq,
unmask: sa1111_unmask_highirq,
rerun: sa1111_rerun_highirq,
type: sa1111_type_highirq,
};
void __init sa1111_init_irq(int irq_nr) void __init sa1111_init_irq(int irq_nr)
{ {
int irq, ret; unsigned int irq;
request_mem_region(_INTTEST0, 512, "irqs"); request_mem_region(_INTTEST0, 512, "irqs");
...@@ -140,33 +217,26 @@ void __init sa1111_init_irq(int irq_nr) ...@@ -140,33 +217,26 @@ void __init sa1111_init_irq(int irq_nr)
SA1111_IRQMASK_HI(S1_READY_NINT); SA1111_IRQMASK_HI(S1_READY_NINT);
/* clear all IRQs */ /* clear all IRQs */
INTSTATCLR0 = -1; INTSTATCLR0 = ~0;
INTSTATCLR1 = -1; INTSTATCLR1 = ~0;
for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &sa1111_low_chip);
irq_desc[irq].probe_ok = 0; set_irq_handler(irq, do_edge_IRQ);
irq_desc[irq].mask_ack = sa1111_mask_and_ack_lowirq; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = sa1111_mask_lowirq;
irq_desc[irq].unmask = sa1111_unmask_lowirq;
} }
for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) { for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &sa1111_high_chip);
irq_desc[irq].probe_ok = 0; set_irq_handler(irq, do_edge_IRQ);
irq_desc[irq].mask_ack = sa1111_mask_and_ack_highirq; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = sa1111_mask_highirq;
irq_desc[irq].unmask = sa1111_unmask_highirq;
} }
/* Register SA1111 interrupt */ /*
if (irq_nr < 0) * Register SA1111 interrupt
return; */
set_irq_type(irq_nr, IRQT_RISING);
ret = request_irq(irq_nr, sa1111_IRQ_demux, SA_INTERRUPT, set_irq_chained_handler(irq_nr, sa1111_irq_handler);
"SA1111", NULL);
if (ret < 0)
printk(KERN_ERR "SA1111: unable to claim IRQ%d: %d\n",
irq_nr, ret);
} }
/** /**
...@@ -199,12 +269,12 @@ int __init sa1111_probe(unsigned long phys_addr) ...@@ -199,12 +269,12 @@ int __init sa1111_probe(unsigned long phys_addr)
*/ */
id = SBI_SKID; id = SBI_SKID;
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
printk(KERN_DEBUG "SA-1111 not detected: ID = %08lx\n", id); printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
ret = -ENODEV; ret = -ENODEV;
goto release; goto release;
} }
printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " printk(KERN_INFO "SA1111 Microprocessor Companion Chip: "
"silicon revision %lx, metal revision %lx\n", "silicon revision %lx, metal revision %lx\n",
(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
......
...@@ -93,7 +93,7 @@ static void __init simpad_map_io(void) ...@@ -93,7 +93,7 @@ static void __init simpad_map_io(void)
sa1100_register_uart(0, 3); sa1100_register_uart(0, 3);
sa1100_register_uart(1, 1); sa1100_register_uart(1, 1);
set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ); set_irq_type(IRQ_GPIO_UCB1300_IRQ, IRQT_RISING);
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -7,6 +7,12 @@ ...@@ -7,6 +7,12 @@
* include/asm-arm/arch-ebsa110/irq.h * include/asm-arm/arch-ebsa110/irq.h
* Copyright (C) 1996-1998 Russell King * Copyright (C) 1996-1998 Russell King
*/ */
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
...@@ -31,12 +37,12 @@ static void shark_disable_8259A_irq(unsigned int irq) ...@@ -31,12 +37,12 @@ static void shark_disable_8259A_irq(unsigned int irq)
if (irq<8) { if (irq<8) {
mask = 1 << irq; mask = 1 << irq;
cached_irq_mask[0] |= mask; cached_irq_mask[0] |= mask;
outb(cached_irq_mask[1],0xA1);
} else { } else {
mask = 1 << (irq-8); mask = 1 << (irq-8);
cached_irq_mask[1] |= mask; cached_irq_mask[1] |= mask;
}
outb(cached_irq_mask[1],0xA1);
outb(cached_irq_mask[0],0x21); outb(cached_irq_mask[0],0x21);
}
} }
static void shark_enable_8259A_irq(unsigned int irq) static void shark_enable_8259A_irq(unsigned int irq)
...@@ -45,32 +51,16 @@ static void shark_enable_8259A_irq(unsigned int irq) ...@@ -45,32 +51,16 @@ static void shark_enable_8259A_irq(unsigned int irq)
if (irq<8) { if (irq<8) {
mask = ~(1 << irq); mask = ~(1 << irq);
cached_irq_mask[0] &= mask; cached_irq_mask[0] &= mask;
outb(cached_irq_mask[0],0x21);
} else { } else {
mask = ~(1 << (irq-8)); mask = ~(1 << (irq-8));
cached_irq_mask[1] &= mask; cached_irq_mask[1] &= mask;
}
outb(cached_irq_mask[1],0xA1); outb(cached_irq_mask[1],0xA1);
outb(cached_irq_mask[0],0x21);
}
/*
* Careful! The 8259A is a fragile beast, it pretty
* much _has_ to be done exactly like this (mask it
* first, _then_ send the EOI, and the order of EOI
* to the two 8259s is important!
*/
static void shark_mask_and_ack_8259A_irq(unsigned int irq)
{
if (irq & 8) {
cached_irq_mask[1] |= 1 << (irq-8);
inb(0xA1); /* DUMMY */
outb(cached_irq_mask[1],0xA1);
} else {
cached_irq_mask[0] |= 1 << irq;
outb(cached_irq_mask[0],0x21);
} }
} }
static void shark_ack_8259A_irq(unsigned int irq){}
static void bogus_int(int irq, void *dev_id, struct pt_regs *regs) static void bogus_int(int irq, void *dev_id, struct pt_regs *regs)
{ {
printk("Got interrupt %i!\n",irq); printk("Got interrupt %i!\n",irq);
...@@ -78,32 +68,30 @@ static void bogus_int(int irq, void *dev_id, struct pt_regs *regs) ...@@ -78,32 +68,30 @@ static void bogus_int(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction cascade; static struct irqaction cascade;
static struct irqchip fb_chip = {
ack: shark_ack_8259A_irq,
mask: shark_disable_8259A_irq,
unmask: shark_enable_8259A_irq,
};
void __init shark_init_irq(void) void __init shark_init_irq(void)
{ {
int irq; int irq;
for (irq = 0; irq < NR_IRQS; irq++) { for (irq = 0; irq < NR_IRQS; irq++) {
irq_desc[irq].valid = 1; set_irq_chip(irq, &fb_chip);
irq_desc[irq].probe_ok = 1; set_irq_handler(irq, do_edge_IRQ);
irq_desc[irq].mask_ack = shark_mask_and_ack_8259A_irq; set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
irq_desc[irq].mask = shark_disable_8259A_irq;
irq_desc[irq].unmask = shark_enable_8259A_irq;
} }
/* The PICs are initialized to level triggered and auto eoi!
* If they are set to edge triggered they lose some IRQs,
* if they are set to manual eoi they get locked up after
* a short time
*/
/* init master interrupt controller */ /* init master interrupt controller */
outb(0x19, 0x20); /* Start init sequence, level triggered */ outb(0x11, 0x20); /* Start init sequence, edge triggered (level: 0x19)*/
outb(0x00, 0x21); /* Vector base */ outb(0x00, 0x21); /* Vector base */
outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */ outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/ outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/
outb(0x0A, 0x20); outb(0x0A, 0x20);
/* init slave interrupt controller */ /* init slave interrupt controller */
outb(0x19, 0xA0); /* Start init sequence, level triggered */ outb(0x11, 0xA0); /* Start init sequence, edge triggered */
outb(0x08, 0xA1); /* Vector base */ outb(0x08, 0xA1); /* Vector base */
outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */ outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */ outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */
...@@ -119,6 +107,6 @@ void __init shark_init_irq(void) ...@@ -119,6 +107,6 @@ void __init shark_init_irq(void)
cascade.name = "cascade"; cascade.name = "cascade";
cascade.next = NULL; cascade.next = NULL;
cascade.dev_id = NULL; cascade.dev_id = NULL;
setup_arm_irq(2,&cascade); setup_irq(2,&cascade);
} }
/*
* linux/include/asm-arm/arch-adifcc/irq.h
*
* Copyright (C) 2001 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define fixup_irq(irq) (irq)
...@@ -18,11 +18,3 @@ ...@@ -18,11 +18,3 @@
#define NR_IRQS NR_XS80200_IRQS #define NR_IRQS NR_XS80200_IRQS
#define IRQ_XSCALE_PMU IRQ_XS80200_PMU #define IRQ_XSCALE_PMU IRQ_XS80200_PMU
#ifdef CONFIG_XSCALE_ADI_EVB
/* Interrupts available on the ADI Eval Board */
#endif
/*
* linux/include/asm-arm/arch-anakin/irq.h
*
* Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Changelog:
* 10-Apr-2001 TTC Created
*/
#ifndef __ASM_ARCH_IRQ_H
#define __ASM_ARCH_IRQ_H
#define fixup_irq(i) i
#endif
...@@ -24,7 +24,7 @@ void __init time_init(void) ...@@ -24,7 +24,7 @@ void __init time_init(void)
{ {
timer_irq.handler = anakin_timer_interrupt; timer_irq.handler = anakin_timer_interrupt;
timer_irq.flags = SA_INTERRUPT; timer_irq.flags = SA_INTERRUPT;
setup_arm_irq(IRQ_TICK, &timer_irq); setup_irq(IRQ_TICK, &timer_irq);
} }
#endif #endif
/*
* linux/include/asm-arm/arch-arc/irq.h
*
* Copyright (C) 1996 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define fixup_irq(x) (x)
...@@ -30,5 +30,5 @@ void __init time_init(void) ...@@ -30,5 +30,5 @@ void __init time_init(void)
timer_irq.handler = timer_interrupt; timer_irq.handler = timer_interrupt;
setup_arm_irq(IRQ_TIMER, &timer_irq); setup_irq(IRQ_TIMER, &timer_irq);
} }
...@@ -37,5 +37,5 @@ void __init time_init(void) ...@@ -37,5 +37,5 @@ void __init time_init(void)
timer_irq.handler = timer_interrupt; timer_irq.handler = timer_interrupt;
setup_arm_irq(IRQ_TIMER, &timer_irq); setup_irq(IRQ_TIMER, &timer_irq);
} }
/*
* linux/include/asm-arm/arch-clps711x/irq.h
*
* Copyright (C) 2000 Deep Blue Solutions Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define fixup_irq(i) (i)
...@@ -39,5 +39,5 @@ void __init time_init(void) ...@@ -39,5 +39,5 @@ void __init time_init(void)
{ {
clps711x_setup_timer(); clps711x_setup_timer();
timer_irq.handler = p720t_timer_interrupt; timer_irq.handler = p720t_timer_interrupt;
setup_arm_irq(IRQ_TC2OI, &timer_irq); setup_irq(IRQ_TC2OI, &timer_irq);
} }
/*
* linux/include/asm-arm/arch-ebsa110/irq.h
*
* Copyright (C) 1996-1998 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Changelog:
* 22-08-1998 RMK Restructured IRQ routines
*/
#define fixup_irq(i) (i)
...@@ -39,7 +39,7 @@ void __init time_init(void) ...@@ -39,7 +39,7 @@ void __init time_init(void)
timer_irq.handler = timer_interrupt; timer_irq.handler = timer_interrupt;
setup_arm_irq(IRQ_EBSA110_TIMER0, &timer_irq); setup_irq(IRQ_EBSA110_TIMER0, &timer_irq);
} }
/*
* linux/include/asm-arm/arch-ebsa285/irq.h
*
* Copyright (C) 1996-1998 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Changelog:
* 22-Aug-1998 RMK Restructured IRQ routines
* 03-Sep-1998 PJB Merged CATS support
* 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder
* 26-Jan-1999 PJB Don't use IACK on CATS
* 16-Mar-1999 RMK Added autodetect of ISA PICs
*/
#include <asm/hardware.h>
#include <asm/hardware/dec21285.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
int isa_irq = -1;
static inline int fixup_irq(unsigned int irq)
{
#ifdef PCIIACK_BASE
if (irq == isa_irq)
irq = *(unsigned char *)PCIIACK_BASE;
#endif
return irq;
}
...@@ -270,5 +270,5 @@ void __init time_init(void) ...@@ -270,5 +270,5 @@ void __init time_init(void)
timer_irq.handler = isa_timer_interrupt; timer_irq.handler = isa_timer_interrupt;
irq = IRQ_ISA_TIMER; irq = IRQ_ISA_TIMER;
} }
setup_arm_irq(irq, &timer_irq); setup_irq(irq, &timer_irq);
} }
/*
* linux/include/asm-arm/arch-epxa10/irq.h
*
* Copyright (C) 1999 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define fixup_irq(i) (i)
...@@ -48,7 +48,7 @@ void __init time_init(void) ...@@ -48,7 +48,7 @@ void __init time_init(void)
/* /*
* Make irqs happen for the system timer * Make irqs happen for the system timer
*/ */
setup_arm_irq(IRQ_TIMER0, &timer_irq); setup_irq(IRQ_TIMER0, &timer_irq);
/* Start the timer */ /* Start the timer */
*TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200); *TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200);
......
/*
* linux/include/asm-arm/arch-integrator/irq.h
*
* Copyright (C) 1999 ARM Limited
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define fixup_irq(i) (i)
...@@ -135,6 +135,6 @@ void __init time_init(void) ...@@ -135,6 +135,6 @@ void __init time_init(void)
/* /*
* Make irqs happen for the system timer * Make irqs happen for the system timer
*/ */
setup_arm_irq(IRQ_TIMERINT1, &timer_irq); setup_irq(IRQ_TIMERINT1, &timer_irq);
gettimeoffset = integrator_gettimeoffset; gettimeoffset = integrator_gettimeoffset;
} }
/*
* linux/include/asm-arm/arch-iop80310/irq.h
*
* Copyright (C) 2001 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define fixup_irq(irq) (irq)
/*
* include/asm-arm/arch-l7200/irq.h
*
* Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.ne
* Steve Hill (sjhill@cotw.com)
*
* Changelog:
* 01-02-2000 RS Created l7200 version, derived from ebsa110 code
* 04-15-2000 RS Made dependent on hardware.h
* 05-05-2000 SJH Complete rewrite
*/
#define fixup_irq(x) (x)
...@@ -58,7 +58,7 @@ void __init time_init(void) ...@@ -58,7 +58,7 @@ void __init time_init(void)
timer_irq.handler = timer_interrupt; timer_irq.handler = timer_interrupt;
setup_arm_irq(IRQ_RTC_TICK, &timer_irq); setup_irq(IRQ_RTC_TICK, &timer_irq);
RTC_RTCCR = RTC_RATE_128 | RTC_EN_TIC; /* Set rate and enable timer */ RTC_RTCCR = RTC_RATE_128 | RTC_EN_TIC; /* Set rate and enable timer */
} }
......
/*
* include/asm-arm/arch-nexuspci/irq.h
*
* Copyright (C) 1998, 1999, 2000 Philip Blundell
*/
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#define fixup_irq(x) (x)
...@@ -55,5 +55,5 @@ void __init time_init(void) ...@@ -55,5 +55,5 @@ void __init time_init(void)
timer_irq.handler = timer_interrupt; timer_irq.handler = timer_interrupt;
timer_irq.flags = SA_SHIRQ; timer_irq.flags = SA_SHIRQ;
setup_arm_irq(IRQ_TIMER, &timer_irq); setup_irq(IRQ_TIMER, &timer_irq);
} }
/*
* linux/include/asm-arm/arch-rpc/irq.h
*
* Copyright (C) 1996 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Changelog:
* 10-10-1996 RMK Brought up to date with arch-sa110eval
* 22-08-1998 RMK Restructured IRQ routines
*/
#define fixup_irq(x) (x)
...@@ -30,5 +30,5 @@ void __init time_init(void) ...@@ -30,5 +30,5 @@ void __init time_init(void)
timer_irq.handler = timer_interrupt; timer_irq.handler = timer_interrupt;
setup_arm_irq(IRQ_TIMER, &timer_irq); setup_irq(IRQ_TIMER, &timer_irq);
} }
...@@ -87,22 +87,6 @@ typedef struct { volatile u32 offset[4096]; } __regbase; ...@@ -87,22 +87,6 @@ typedef struct { volatile u32 offset[4096]; } __regbase;
#include "SA-1100.h" #include "SA-1100.h"
/*
* SA1100 GPIO edge detection for IRQs:
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
* This must be called *before* the corresponding IRQ is registered.
* Use this instead of directly setting GRER/GFER.
*/
#define GPIO_NO_EDGES 0
#define GPIO_FALLING_EDGE 1
#define GPIO_RISING_EDGE 2
#define GPIO_BOTH_EDGES 3
#ifndef __ASSEMBLY__
extern void set_GPIO_IRQ_edge( int gpio_mask, int edge_mask );
#endif
/* /*
* Implementation specifics. * Implementation specifics.
* *
......
...@@ -113,7 +113,7 @@ ide_init_default_hwifs(void) ...@@ -113,7 +113,7 @@ ide_init_default_hwifs(void)
/* Enable GPIO as interrupt line */ /* Enable GPIO as interrupt line */
GPDR &= ~LART_GPIO_IDE; GPDR &= ~LART_GPIO_IDE;
set_GPIO_IRQ_edge(LART_GPIO_IDE, GPIO_RISING_EDGE); set_irq_type(LART_IRQ_IDE, IRQT_RISING);
/* set PCMCIA interface timing */ /* set PCMCIA interface timing */
MECR = 0x00060006; MECR = 0x00060006;
......
/*
* linux/include/asm-arm/arch-sa1100/irq.h
*
* Author: Nicolas Pitre
*/
#define fixup_irq(x) (x)
/*
* This prototype is required for cascading of multiplexed interrupts.
* Since it doesn't exist elsewhere, we'll put it here for now.
*/
extern void do_IRQ(int irq, struct pt_regs *regs);
...@@ -148,6 +148,7 @@ ...@@ -148,6 +148,7 @@
*/ */
#define IRQ_NEPONSET_SMC9196 (IRQ_BOARD_START + 0) #define IRQ_NEPONSET_SMC9196 (IRQ_BOARD_START + 0)
#define IRQ_NEPONSET_USAR (IRQ_BOARD_START + 1) #define IRQ_NEPONSET_USAR (IRQ_BOARD_START + 1)
#define IRQ_NEPONSET_SA1111 (IRQ_BOARD_START + 2)
/* PT Digital Board Interrupts (CONFIG_SA1100_PT_SYSTEM3) */ /* PT Digital Board Interrupts (CONFIG_SA1100_PT_SYSTEM3) */
#define IRQ_SYSTEM3_SMC9196 (IRQ_BOARD_START + 0) #define IRQ_SYSTEM3_SMC9196 (IRQ_BOARD_START + 0)
...@@ -98,7 +98,7 @@ void __init time_init(void) ...@@ -98,7 +98,7 @@ void __init time_init(void)
timer_irq.handler = sa1100_timer_interrupt; timer_irq.handler = sa1100_timer_interrupt;
OSMR0 = 0; /* set initial match at 0 */ OSMR0 = 0; /* set initial match at 0 */
OSSR = 0xf; /* clear status on all timers */ OSSR = 0xf; /* clear status on all timers */
setup_arm_irq(IRQ_OST0, &timer_irq); setup_irq(IRQ_OST0, &timer_irq);
OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */
OSCR = 0; /* initialize free-running timer, force first match */ OSCR = 0; /* initialize free-running timer, force first match */
} }
......
/*
* linux/include/asm-arm/arch-shark/irq.h
*
* by Alexander Schulz
*
* derived from linux/arch/ppc/kernel/i8259.c and:
* include/asm-arm/arch-ebsa110/irq.h
* Copyright (C) 1996-1998 Russell King
*/
#define fixup_irq(x) (x)
/*
* include/asm-arm/arch-tbox/irq.h
*
* Copyright (C) 1998, 1999, 2000 Philip Blundell
*/
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#define fixup_irq(x) (x)
...@@ -32,5 +32,5 @@ static void timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) ...@@ -32,5 +32,5 @@ static void timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
void __init time_init(void) void __init time_init(void)
{ {
timer_irq.handler = timer_interrupt; timer_irq.handler = timer_interrupt;
setup_arm_irq(IRQ_TIMER, &timer_irq); setup_irq(IRQ_TIMER, &timer_irq);
} }
...@@ -24,5 +24,19 @@ ...@@ -24,5 +24,19 @@
extern void disable_irq(unsigned int); extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int); extern void enable_irq(unsigned int);
#define __IRQT_FALEDGE (1 << 0)
#define __IRQT_RISEDGE (1 << 1)
#define __IRQT_LOWLVL (1 << 2)
#define __IRQT_HIGHLVL (1 << 3)
#define IRQT_NOEDGE (0)
#define IRQT_RISING (__IRQT_RISEDGE)
#define IRQT_FALLING (__IRQT_FALEDGE)
#define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE)
#define IRQT_LOW (__IRQT_LOWLVL)
#define IRQT_HIGH (__IRQT_HIGHLVL)
int set_irq_type(unsigned int irq, unsigned int type);
#endif #endif
...@@ -10,19 +10,54 @@ ...@@ -10,19 +10,54 @@
#ifndef __ASM_ARM_MACH_IRQ_H #ifndef __ASM_ARM_MACH_IRQ_H
#define __ASM_ARM_MACH_IRQ_H #define __ASM_ARM_MACH_IRQ_H
struct irqdesc;
struct pt_regs;
struct seq_file;
typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *);
typedef void (*irq_control_t)(unsigned int);
struct irqchip {
/*
* Acknowledge the IRQ.
* If this is a level-based IRQ, then it is expected to mask the IRQ
* as well.
*/
void (*ack)(unsigned int);
/*
* Mask the IRQ in hardware.
*/
void (*mask)(unsigned int);
/*
* Unmask the IRQ in hardware.
*/
void (*unmask)(unsigned int);
/*
* Re-run the IRQ
*/
void (*rerun)(unsigned int);
/*
* Set the type of the IRQ.
*/
int (*type)(unsigned int, unsigned int);
};
struct irqdesc { struct irqdesc {
unsigned int nomask : 1; /* IRQ does not mask in IRQ */ irq_handler_t handle;
struct irqchip *chip;
struct irqaction *action;
unsigned int enabled : 1; /* IRQ is currently enabled */ unsigned int enabled : 1; /* IRQ is currently enabled */
unsigned int triggered: 1; /* IRQ has occurred */ unsigned int triggered: 1; /* IRQ has occurred */
unsigned int running : 1; /* IRQ is running */
unsigned int pending : 1; /* IRQ is pending */
unsigned int probing : 1; /* IRQ in use for a probe */ unsigned int probing : 1; /* IRQ in use for a probe */
unsigned int probe_ok : 1; /* IRQ can be used for probe */ unsigned int probe_ok : 1; /* IRQ can be used for probe */
unsigned int valid : 1; /* IRQ claimable */ unsigned int valid : 1; /* IRQ claimable */
unsigned int noautoenable : 1; /* don't automatically enable IRQ */ unsigned int noautoenable : 1; /* don't automatically enable IRQ */
unsigned int unused :25; unsigned int unused :23;
void (*mask_ack)(unsigned int irq); /* Mask and acknowledge IRQ */ unsigned int depth; /* disable depth */
void (*mask)(unsigned int irq); /* Mask IRQ */
void (*unmask)(unsigned int irq); /* Unmask IRQ */
struct irqaction *action;
/* /*
* IRQ lock detection * IRQ lock detection
*/ */
...@@ -33,9 +68,52 @@ struct irqdesc { ...@@ -33,9 +68,52 @@ struct irqdesc {
extern struct irqdesc irq_desc[]; extern struct irqdesc irq_desc[];
/*
* This is internal. Do not use it.
*/
extern void (*init_arch_irq)(void); extern void (*init_arch_irq)(void);
extern int setup_arm_irq(int, struct irqaction *);
extern int show_fiq_list(struct seq_file *, void *);
extern void init_FIQ(void); extern void init_FIQ(void);
extern int show_fiq_list(struct seq_file *, void *);
void __set_irq_handler(unsigned int irq, irq_handler_t, int);
int setup_irq(unsigned int, struct irqaction *);
/*
* External stuff.
*/
#define set_irq_handler(irq,handler) __set_irq_handler(irq,handler,0)
#define set_irq_chained_handler(irq,handler) __set_irq_handler(irq,handler,1)
void set_irq_chip(unsigned int irq, struct irqchip *);
void set_irq_flags(unsigned int irq, unsigned int flags);
#ifdef not_yet
/*
* This is to be used by the top-level machine IRQ decoder only.
*/
static inline void call_irq(struct pt_regs *regs, unsigned int irq)
{
struct irqdesc *desc = irq_desc + irq;
spin_lock(&irq_controller_lock);
desc->handle(irq, desc, regs);
spin_unlock(&irq_controller_lock);
if (softirq_pending(smp_processor_id()))
do_softirq();
}
#endif
#define IRQF_VALID (1 << 0)
#define IRQF_PROBE (1 << 1)
#define IRQF_NOAUTOEN (1 << 2)
/*
* Built-in IRQ handlers.
*/
void do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
void do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
void do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
void dummy_mask_unmask_irq(unsigned int irq);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment