Commit 8953e802 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] Generic IRQ support for PA-RISC

Make PA-RISC use the generic interrupt handling code.  We need one tiny
change to the generic code -- the addition of a data pointer to irq_desc.
This shouldn't be a problem in terms of increasing size of irq_desc for
other architectures as the struct is cacheline aligned.  It's now 32
bytes on 32-bit platforms and 44/48 bytes on 64-bit platforms (assuming
spinlock_t is 4 bytes on 32-bit and 4 or 8 bytes on 64-bit).
Signed-off-by: default avatarMatthew Wilcox <matthew@wil.cx>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ad8c410c
......@@ -39,6 +39,12 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_ISA_DMA
bool
config GENERIC_HARDIRQS
def_bool y
config GENERIC_IRQ_PROBE
def_bool y
# unless you want to implement ACPI on PA-RISC ... ;-)
config PM
bool
......
......@@ -54,21 +54,19 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
#define DBG_IRQ(irq, x) do { } while (0)
#endif /* DEBUG_IRQ */
#define EIEM_MASK(irq) (1UL<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
#define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq))
/* Bits in EIEM correlate with cpu_irq_action[].
** Numbered *Big Endian*! (ie bit 0 is MSB)
*/
static volatile unsigned long cpu_eiem = 0;
static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; /* protect IRQ regions */
static void cpu_set_eiem(void *info)
{
set_eiem((unsigned long) info);
}
static inline void disable_cpu_irq(void *unused, int irq)
static inline void cpu_disable_irq(unsigned int irq)
{
unsigned long eirr_bit = EIEM_MASK(irq);
......@@ -76,7 +74,7 @@ static inline void disable_cpu_irq(void *unused, int irq)
on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
}
static void enable_cpu_irq(void *unused, int irq)
static void cpu_enable_irq(unsigned int irq)
{
unsigned long eirr_bit = EIEM_MASK(irq);
......@@ -85,172 +83,56 @@ static void enable_cpu_irq(void *unused, int irq)
on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
}
/* mask and disable are the same at the CPU level
** Difference is enable clears pending interrupts
*/
#define mask_cpu_irq disable_cpu_irq
static inline void unmask_cpu_irq(void *unused, int irq)
static unsigned int cpu_startup_irq(unsigned int irq)
{
unsigned long eirr_bit = EIEM_MASK(irq);
cpu_eiem |= eirr_bit;
/* NOTE: sending an IPI will cause do_cpu_irq_mask() to
** handle *any* unmasked pending interrupts.
** ie We don't need to check for pending interrupts here.
*/
on_each_cpu(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
cpu_enable_irq(irq);
return 0;
}
/*
* XXX cpu_irq_actions[] will become 2 dimensional for per CPU EIR support.
* correspond changes needed in:
* processor_probe() initialize additional action arrays
* request_irq() handle CPU IRQ region specially
* do_cpu_irq_mask() index into the matching irq_action array.
*/
struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
[IRQ_OFFSET(TIMER_IRQ)] = {
.handler = timer_interrupt,
.name = "timer",
},
#ifdef CONFIG_SMP
[IRQ_OFFSET(IPI_IRQ)] = {
.handler = ipi_interrupt,
.name = "IPI",
},
#endif
};
struct irq_region cpu0_irq_region = {
.ops = {
.disable_irq = disable_cpu_irq,
.enable_irq = enable_cpu_irq,
.mask_irq = unmask_cpu_irq,
.unmask_irq = unmask_cpu_irq
},
.data = {
.dev = &cpu_data[0],
.name = "PARISC-CPU",
.irqbase = IRQ_FROM_REGION(CPU_IRQ_REGION),
},
.action = cpu_irq_actions,
};
struct irq_region *irq_region[NR_IRQ_REGS] = {
[ 0 ] = NULL, /* reserved for EISA, else causes data page fault (aka code 15) */
[ CPU_IRQ_REGION ] = &cpu0_irq_region,
void no_ack_irq(unsigned int irq) { }
void no_end_irq(unsigned int irq) { }
static struct hw_interrupt_type cpu_interrupt_type = {
.typename = "CPU",
.startup = cpu_startup_irq,
.shutdown = cpu_disable_irq,
.enable = cpu_enable_irq,
.disable = cpu_disable_irq,
.ack = no_ack_irq,
.end = no_end_irq,
// .set_affinity = cpu_set_affinity_irq,
};
/*
** Generic interfaces that device drivers can use:
** mask_irq() block IRQ
** unmask_irq() re-enable IRQ and trigger if IRQ is pending
** disable_irq() block IRQ
** enable_irq() clear pending and re-enable IRQ
*/
void mask_irq(int irq)
{
struct irq_region *region;
DBG_IRQ(irq, ("mask_irq(%d) %d+%d eiem 0x%lx\n", irq,
IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
irq = irq_canonicalize(irq);
region = irq_region[IRQ_REGION(irq)];
if (region->ops.mask_irq)
region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
}
void unmask_irq(int irq)
{
struct irq_region *region;
DBG_IRQ(irq, ("unmask_irq(%d) %d+%d eiem 0x%lx\n", irq,
IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
irq = irq_canonicalize(irq);
region = irq_region[IRQ_REGION(irq)];
if (region->ops.unmask_irq)
region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
}
void disable_irq(int irq)
{
struct irq_region *region;
DBG_IRQ(irq, ("disable_irq(%d) %d+%d eiem 0x%lx\n", irq,
IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
irq = irq_canonicalize(irq);
region = irq_region[IRQ_REGION(irq)];
if (region->ops.disable_irq)
region->ops.disable_irq(region->data.dev, IRQ_OFFSET(irq));
else
BUG();
}
EXPORT_SYMBOL(disable_irq);
void enable_irq(int irq)
{
struct irq_region *region;
DBG_IRQ(irq, ("enable_irq(%d) %d+%d EIRR 0x%lx EIEM 0x%lx\n", irq,
IRQ_REGION(irq), IRQ_OFFSET(irq), mfctl(23), mfctl(15)));
irq = irq_canonicalize(irq);
region = irq_region[IRQ_REGION(irq)];
if (region->ops.enable_irq)
region->ops.enable_irq(region->data.dev, IRQ_OFFSET(irq));
else
BUG();
}
EXPORT_SYMBOL(enable_irq);
int show_interrupts(struct seq_file *p, void *v)
{
#ifdef CONFIG_PROC_FS
unsigned int regnr = *(loff_t *) v, i = 0;
int i = *(loff_t *) v, j;
unsigned long flags;
if (regnr == 0) {
seq_puts(p, " ");
#ifdef CONFIG_SMP
for (i = 0; i < NR_CPUS; i++)
if (cpu_online(i))
#endif
seq_printf(p, " CPU%02d ", i);
if (i == 0) {
seq_puts(p, " ");
for_each_online_cpu(j)
seq_printf(p, " CPU%d", j);
#ifdef PARISC_IRQ_CR16_COUNTS
seq_printf(p, "[min/avg/max] (CPU cycle counts)");
seq_printf(p, " [min/avg/max] (CPU cycle counts)");
#endif
seq_putc(p, '\n');
}
/* We don't need *irqsave lock variants since this is
** only allowed to change while in the base context.
*/
spin_lock(&irq_lock);
if (regnr < NR_IRQ_REGS) {
struct irq_region *region = irq_region[regnr];
if (!region || !region->action)
goto skip;
for (i = 0; i <= MAX_CPU_IRQ; i++) {
struct irqaction *action = &region->action[i];
unsigned int irq_no = IRQ_FROM_REGION(regnr) + i;
int j = 0;
if (!action->handler)
continue;
seq_printf(p, "%3d: ", irq_no);
if (i < NR_IRQS) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
struct irqaction *action = irq_desc[i].action;
if (!action)
goto skip;
seq_printf(p, "%3d: ", i);
#ifdef CONFIG_SMP
for (; j < NR_CPUS; j++)
if (cpu_online(j))
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#else
seq_printf(p, "%10u ", kstat_irqs(i));
#endif
seq_printf(p, "%10u ", kstat_cpu(j).irqs[irq_no]);
seq_printf(p, " %14s",
region->data.name ? region->data.name : "N/A");
seq_printf(p, " %14s", irq_desc[i].handler->typename);
#ifndef PARISC_IRQ_CR16_COUNTS
seq_printf(p, " %s", action->name);
......@@ -281,12 +163,10 @@ int show_interrupts(struct seq_file *p, void *v)
#endif
seq_putc(p, '\n');
}
skip:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
}
skip:
spin_unlock(&irq_lock);
#endif /* CONFIG_PROC_FS */
return 0;
}
......@@ -300,34 +180,42 @@ int show_interrupts(struct seq_file *p, void *v)
** Then use that to get the Transaction address and data.
*/
int
txn_alloc_irq(void)
int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
{
int irq;
/* never return irq 0 cause that's the interval timer */
for (irq = 1; irq <= MAX_CPU_IRQ; irq++) {
if (cpu_irq_actions[irq].handler == NULL) {
return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq);
}
if (irq_desc[irq].action)
return -EBUSY;
if (irq_desc[irq].handler != &cpu_interrupt_type)
return -EBUSY;
if (type) {
irq_desc[irq].handler = type;
irq_desc[irq].handler_data = data;
cpu_interrupt_type.enable(irq);
}
return 0;
}
/* unlikely, but be prepared */
return -1;
int txn_claim_irq(int irq)
{
return cpu_claim_irq(irq, NULL, NULL) ? -1 : irq;
}
int
txn_claim_irq(int irq)
int txn_alloc_irq(void)
{
if (irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)].handler ==NULL)
int irq;
/* never return irq 0 cause that's the interval timer */
for (irq = CPU_IRQ_BASE + 1; irq <= CPU_IRQ_MAX; irq++) {
if (cpu_claim_irq(irq, NULL, NULL) < 0)
continue;
return irq;
}
/* unlikely, but be prepared */
return -1;
}
unsigned long
txn_alloc_addr(int virt_irq)
unsigned long txn_alloc_addr(int virt_irq)
{
static int next_cpu = -1;
......@@ -364,68 +252,20 @@ txn_alloc_addr(int virt_irq)
** I/O subsystem supports more bits than PA2.0 has. The first
** case is the problem.
*/
unsigned int
txn_alloc_data(int virt_irq, unsigned int bits_wide)
unsigned int txn_alloc_data(int virt_irq, unsigned int bits_wide)
{
/* XXX FIXME : bits_wide indicates how wide the transaction
** data is allowed to be...we may need a different virt_irq
** if this one won't work. Another reason to index virtual
** irq's into a table which can manage CPU/IRQ bit separately.
*/
if (IRQ_OFFSET(virt_irq) > (1 << (bits_wide -1)))
{
if ((virt_irq - CPU_IRQ_BASE) > (1 << (bits_wide - 1))) {
panic("Sorry -- didn't allocate valid IRQ for this device\n");
}
return (IRQ_OFFSET(virt_irq));
}
void do_irq(struct irqaction *action, int irq, struct pt_regs * regs)
{
int cpu = smp_processor_id();
irq_enter();
++kstat_cpu(cpu).irqs[irq];
DBG_IRQ(irq, ("do_irq(%d) %d+%d eiem 0x%lx\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
for (; action; action = action->next) {
#ifdef PARISC_IRQ_CR16_COUNTS
unsigned long cr_start = mfctl(16);
#endif
if (action->handler == NULL) {
if (IRQ_REGION(irq) == EISA_IRQ_REGION && irq_region[EISA_IRQ_REGION]) {
/* were we called due to autodetecting (E)ISA irqs ? */
unsigned int *status;
status = &irq_region[EISA_IRQ_REGION]->data.status[IRQ_OFFSET(irq)];
if (*status & IRQ_AUTODETECT) {
*status &= ~IRQ_WAITING;
continue;
}
}
printk(KERN_ERR "IRQ: CPU:%d No handler for IRQ %d !\n", cpu, irq);
continue;
}
action->handler(irq, action->dev_id, regs);
#ifdef PARISC_IRQ_CR16_COUNTS
{
unsigned long cr_end = mfctl(16);
unsigned long tmp = cr_end - cr_start;
/* check for roll over */
cr_start = (cr_end < cr_start) ? -(tmp) : (tmp);
}
action->cr16_hist[action->cr16_idx++] = (int) cr_start;
action->cr16_idx &= PARISC_CR16_HIST_SIZE - 1;
#endif
}
irq_exit();
return virt_irq - CPU_IRQ_BASE;
}
/* ONLY called from entry.S:intr_extint() */
void do_cpu_irq_mask(struct pt_regs *regs)
{
......@@ -449,9 +289,12 @@ void do_cpu_irq_mask(struct pt_regs *regs)
* 3) Limit the number of times we loop to make sure other
* processing can occur.
*/
while ((eirr_val = (mfctl(23) & cpu_eiem)) && --i) {
unsigned long bit = (1UL<<MAX_CPU_IRQ);
for (;;) {
unsigned long bit = (1UL << (BITS_PER_LONG - 1));
unsigned int irq;
eirr_val = mfctl(23) & cpu_eiem;
if (!eirr_val || !i--)
break;
mtctl(eirr_val, 23); /* reset bits we are going to process */
......@@ -461,408 +304,52 @@ void do_cpu_irq_mask(struct pt_regs *regs)
#endif
/* Work our way from MSb to LSb...same order we alloc EIRs */
for (irq = 0; eirr_val && bit; bit>>=1, irq++)
{
for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
if (!(bit & eirr_val & cpu_eiem))
continue;
/* clear bit in mask - can exit loop sooner */
eirr_val &= ~bit;
do_irq(&cpu_irq_actions[irq], TIMER_IRQ+irq, regs);
__do_IRQ(irq, regs);
}
}
set_eiem(cpu_eiem);
}
/* Called from second level IRQ regions: eg dino or iosapic. */
void do_irq_mask(unsigned long mask, struct irq_region *region, struct pt_regs *regs)
{
unsigned long bit;
unsigned int irq;
#ifdef DEBUG_IRQ
if (mask != (1L<<MAX_CPU_IRQ))
printk(KERN_DEBUG "do_irq_mask %08lx %p %p\n", mask, region, regs);
#endif
for (bit = (1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
unsigned int irq_num;
if (!(bit&mask))
continue;
mask &= ~bit; /* clear bit in mask - can exit loop sooner */
irq_num = region->data.irqbase + irq;
mask_irq(irq_num);
do_irq(&region->action[irq], irq_num, regs);
unmask_irq(irq_num);
}
}
static inline int find_free_region(void)
{
int irqreg;
for (irqreg=1; irqreg <= (NR_IRQ_REGS); irqreg++) {
if (irq_region[irqreg] == NULL)
return irqreg;
}
return 0;
}
/*****
* alloc_irq_region - allocate/init a new IRQ region
* @count: number of IRQs in this region.
* @ops: function table with request/release/mask/unmask/etc.. entries.
* @name: name of region owner for /proc/interrupts output.
* @dev: private data to associate with the new IRQ region.
*
* Every IRQ must become a MMIO write to the CPU's EIRR in
* order to get CPU service. The IRQ region represents the
* number of unique events the region handler can (or must)
* identify. For PARISC CPU, that's the width of the EIR Register.
* IRQ regions virtualize IRQs (eg EISA or PCI host bus controllers)
* for line based devices.
*/
struct irq_region *alloc_irq_region( int count, struct irq_region_ops *ops,
const char *name, void *dev)
{
struct irq_region *region;
int index;
index = find_free_region();
if (index == 0) {
printk(KERN_ERR "Maximum number of irq regions exceeded. Increase NR_IRQ_REGS!\n");
return NULL;
}
if ((IRQ_REGION(count-1)))
return NULL;
if (count < IRQ_PER_REGION) {
DBG_IRQ(0, ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n",
IRQ_PER_REGION, name, count));
count = IRQ_PER_REGION;
}
/* if either mask *or* unmask is set, both have to be set. */
if((ops->mask_irq || ops->unmask_irq) &&
!(ops->mask_irq && ops->unmask_irq))
return NULL;
/* ditto for enable/disable */
if( (ops->disable_irq || ops->enable_irq) &&
!(ops->disable_irq && ops->enable_irq) )
return NULL;
region = kmalloc(sizeof(*region), GFP_ATOMIC);
if (!region)
return NULL;
memset(region, 0, sizeof(*region));
region->action = kmalloc(count * sizeof(*region->action), GFP_ATOMIC);
if (!region->action) {
kfree(region);
return NULL;
}
memset(region->action, 0, count * sizeof(*region->action));
region->ops = *ops;
region->data.irqbase = IRQ_FROM_REGION(index);
region->data.name = name;
region->data.dev = dev;
irq_region[index] = region;
return irq_region[index];
}
/* FIXME: SMP, flags, bottom halves, rest */
int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char * devname,
void *dev_id)
{
struct irqaction * action;
static struct irqaction timer_action = {
.handler = timer_interrupt,
.name = "timer",
};
#if 0
printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id);
#ifdef CONFIG_SMP
static struct irqaction ipi_action = {
.handler = ipi_interrupt,
.name = "IPI",
};
#endif
irq = irq_canonicalize(irq);
/* request_irq()/free_irq() may not be called from interrupt context. */
if (in_interrupt())
BUG();
if (!handler) {
printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n",
irq);
return -EINVAL;
}
if (irq_region[IRQ_REGION(irq)] == NULL) {
/*
** Bug catcher for drivers which use "char" or u8 for
** the IRQ number. They lose the region number which
** is in pcidev->irq (an int).
*/
printk(KERN_ERR "%p (%s?) called request_irq with an invalid irq %d\n",
__builtin_return_address(0), devname, irq);
return -EINVAL;
}
spin_lock(&irq_lock);
action = &(irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]);
/* First one is preallocated. */
if (action->handler) {
/* But it's in use...find the tail and allocate a new one */
while (action->next)
action = action->next;
action->next = kmalloc(sizeof(*action), GFP_ATOMIC);
memset(action->next, 0, sizeof(*action));
action = action->next;
}
if (!action) {
spin_unlock(&irq_lock);
printk(KERN_ERR "request_irq(): Augh! No action!\n") ;
return -ENOMEM;
}
action->handler = handler;
action->flags = irqflags;
cpus_clear(action->mask);
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
spin_unlock(&irq_lock);
enable_irq(irq);
return 0;
}
EXPORT_SYMBOL(request_irq);
void free_irq(unsigned int irq, void *dev_id)
static void claim_cpu_irqs(void)
{
struct irqaction *action, **p;
/* See comments in request_irq() about interrupt context */
irq = irq_canonicalize(irq);
if (in_interrupt()) BUG();
spin_lock(&irq_lock);
action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
if (action->dev_id == dev_id) {
if (action->next == NULL) {
action->handler = NULL;
} else {
memcpy(action, action->next, sizeof(*action));
}
spin_unlock(&irq_lock);
return;
int i;
for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
irq_desc[i].handler = &cpu_interrupt_type;
}
p = &action->next;
action = action->next;
for (; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;
/* Found it - now free it */
*p = action->next;
kfree(action);
spin_unlock(&irq_lock);
return;
}
spin_unlock(&irq_lock);
printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
}
EXPORT_SYMBOL(free_irq);
irq_desc[TIMER_IRQ].action = &timer_action;
irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU;
#ifdef CONFIG_SMP
void synchronize_irq(unsigned int irqnum)
{
while (in_irq()) ;
}
EXPORT_SYMBOL(synchronize_irq);
irq_desc[IPI_IRQ].action = &ipi_action;
irq_desc[IPI_IRQ].status = IRQ_PER_CPU;
#endif
/*
* IRQ autodetection code..
*
* This depends on the fact that any interrupt that
* comes in on to an unassigned handler will get stuck
* with "IRQ_WAITING" cleared and the interrupt
* disabled.
*/
static DECLARE_MUTEX(probe_sem);
/**
* probe_irq_on - begin an interrupt autodetect
*
* Commence probing for an interrupt. The interrupts are scanned
* and a mask of potential interrupt lines is returned.
*
*/
/* TODO: spin_lock_irq(desc->lock -> irq_lock) */
unsigned long probe_irq_on(void)
{
unsigned int i;
unsigned long val;
unsigned long delay;
struct irq_region *region;
/* support for irq autoprobing is limited to EISA (irq region 0) */
region = irq_region[EISA_IRQ_REGION];
if (!EISA_bus || !region)
return 0;
down(&probe_sem);
/*
* enable any unassigned irqs
* (we must startup again here because if a longstanding irq
* happened in the previous stage, it may have masked itself)
*/
for (i = EISA_MAX_IRQS-1; i > 0; i--) {
struct irqaction *action;
spin_lock_irq(&irq_lock);
action = region->action + i;
if (!action->handler) {
region->data.status[i] |= IRQ_AUTODETECT | IRQ_WAITING;
region->ops.enable_irq(region->data.dev,i);
}
spin_unlock_irq(&irq_lock);
}
/*
* Wait for spurious interrupts to trigger
*/
for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
/* about 100ms delay */ barrier();
/*
* Now filter out any obviously spurious interrupts
*/
val = 0;
for (i = 0; i < EISA_MAX_IRQS; i++) {
unsigned int status;
spin_lock_irq(&irq_lock);
status = region->data.status[i];
if (status & IRQ_AUTODETECT) {
/* It triggered already - consider it spurious. */
if (!(status & IRQ_WAITING)) {
region->data.status[i] = status & ~IRQ_AUTODETECT;
region->ops.disable_irq(region->data.dev,i);
} else
if (i < BITS_PER_LONG)
val |= (1 << i);
}
spin_unlock_irq(&irq_lock);
}
return val;
}
EXPORT_SYMBOL(probe_irq_on);
/*
* Return the one interrupt that triggered (this can
* handle any interrupt source).
*/
/**
* probe_irq_off - end an interrupt autodetect
* @val: mask of potential interrupts (unused)
*
* Scans the unused interrupt lines and returns the line which
* appears to have triggered the interrupt. If no interrupt was
* found then zero is returned. If more than one interrupt is
* found then minus the first candidate is returned to indicate
* their is doubt.
*
* The interrupt probe logic state is returned to its previous
* value.
*
* BUGS: When used in a module (which arguably shouldnt happen)
* nothing prevents two IRQ probe callers from overlapping. The
* results of this are non-optimal.
*/
int probe_irq_off(unsigned long val)
{
struct irq_region *region;
int i, irq_found, nr_irqs;
/* support for irq autoprobing is limited to EISA (irq region 0) */
region = irq_region[EISA_IRQ_REGION];
if (!EISA_bus || !region)
return 0;
nr_irqs = 0;
irq_found = 0;
for (i = 0; i < EISA_MAX_IRQS; i++) {
unsigned int status;
spin_lock_irq(&irq_lock);
status = region->data.status[i];
if (status & IRQ_AUTODETECT) {
if (!(status & IRQ_WAITING)) {
if (!nr_irqs)
irq_found = i;
nr_irqs++;
}
region->ops.disable_irq(region->data.dev,i);
region->data.status[i] = status & ~IRQ_AUTODETECT;
}
spin_unlock_irq(&irq_lock);
}
up(&probe_sem);
if (nr_irqs > 1)
irq_found = -irq_found;
return irq_found;
}
EXPORT_SYMBOL(probe_irq_off);
unsigned int probe_irq_mask(unsigned long irqs)
{
return 0;
}
EXPORT_SYMBOL(probe_irq_mask);
void __init init_IRQ(void)
{
local_irq_disable(); /* PARANOID - should already be disabled */
mtctl(~0UL, 23); /* EIRR : clear all pending external intr */
claim_cpu_irqs();
#ifdef CONFIG_SMP
if (!cpu_eiem)
cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
......@@ -873,9 +360,14 @@ void __init init_IRQ(void)
}
#ifdef CONFIG_PROC_FS
/* called from kernel/sysctl.c:sysctl_init() */
void __init init_irq_proc(void)
void hw_resend_irq(struct hw_interrupt_type *type, unsigned int irq)
{
/* XXX: Needs to be written. We managed without it so far, but
* we really ought to write it.
*/
}
void ack_bad_irq(unsigned int irq)
{
printk("unexpected IRQ %d\n", irq);
}
#endif
......@@ -277,7 +277,7 @@ ipi_send(int cpu, enum ipi_message_type op)
spin_lock_irqsave(&(p->lock),flags);
p->pending_ipi |= 1 << op;
__raw_writel(IRQ_OFFSET(IPI_IRQ), cpu_data[cpu].hpa);
gsc_writel(IPI_IRQ - CPU_IRQ_BASE, cpu_data[cpu].hpa);
spin_unlock_irqrestore(&(p->lock),flags);
}
......@@ -533,7 +533,7 @@ int __init smp_boot_one_cpu(int cpuid)
** EIR{0}). MEM_RENDEZ is valid only when it is nonzero and the
** contents of memory are valid."
*/
__raw_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpuid].hpa);
gsc_writel(TIMER_IRQ - CPU_IRQ_BASE, cpu_data[cpuid].hpa);
mb();
/*
......
......@@ -2,11 +2,6 @@
# Makefile for most of the non-PCI devices in PA-RISC machines
#
obj-y :=
obj-m :=
obj-n :=
obj- :=
# I/O SAPIC is also on IA64 platforms.
# The two could be merged into a common source some day.
obj-$(CONFIG_IOSAPIC) += iosapic.o
......@@ -17,7 +12,7 @@ obj-$(CONFIG_PCI_LBA) += lba_pci.o
# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
obj-y += gsc.o
obj-$(CONFIG_GSC) += gsc.o
obj-$(CONFIG_HPPB) += hppb.o
obj-$(CONFIG_GSC_DINO) += dino.o
......
......@@ -13,7 +13,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
......@@ -30,25 +30,27 @@
#define VIPER_INT_WORD 0xFFFBF088 /* addr of viper interrupt word */
static int asp_choose_irq(struct parisc_device *dev)
static void asp_choose_irq(struct parisc_device *dev, void *ctrl)
{
int irq = -1;
int irq;
switch (dev->id.sversion) {
case 0x71: irq = 22; break; /* SCSI */
case 0x72: irq = 23; break; /* LAN */
case 0x73: irq = 30; break; /* HIL */
case 0x74: irq = 24; break; /* Centronics */
case 0x75: irq = (dev->hw_path == 4) ? 26 : 25; break; /* RS232 */
case 0x76: irq = 21; break; /* EISA BA */
case 0x77: irq = 20; break; /* Graphics1 */
case 0x7a: irq = 18; break; /* Audio (Bushmaster) */
case 0x7b: irq = 18; break; /* Audio (Scorpio) */
case 0x7c: irq = 28; break; /* FW SCSI */
case 0x7d: irq = 27; break; /* FDDI */
case 0x7f: irq = 18; break; /* Audio (Outfield) */
case 0x71: irq = 9; break; /* SCSI */
case 0x72: irq = 8; break; /* LAN */
case 0x73: irq = 1; break; /* HIL */
case 0x74: irq = 7; break; /* Centronics */
case 0x75: irq = (dev->hw_path == 4) ? 5 : 6; break; /* RS232 */
case 0x76: irq = 10; break; /* EISA BA */
case 0x77: irq = 11; break; /* Graphics1 */
case 0x7a: irq = 13; break; /* Audio (Bushmaster) */
case 0x7b: irq = 13; break; /* Audio (Scorpio) */
case 0x7c: irq = 3; break; /* FW SCSI */
case 0x7d: irq = 4; break; /* FDDI */
case 0x7f: irq = 13; break; /* Audio (Outfield) */
default: return; /* Unknown */
}
return irq;
gsc_asic_assign_irq(ctrl, irq, &dev->irq);
}
/* There are two register ranges we're interested in. Interrupt /
......@@ -62,11 +64,11 @@ static int asp_choose_irq(struct parisc_device *dev)
int __init
asp_init_chip(struct parisc_device *dev)
{
struct busdevice *asp;
struct gsc_asic *asp;
struct gsc_irq gsc_irq;
int irq, ret;
int ret;
asp = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
asp = kmalloc(sizeof(*asp), GFP_KERNEL);
if(!asp)
return -ENOMEM;
......@@ -79,37 +81,34 @@ asp_init_chip(struct parisc_device *dev)
/* the IRQ ASP should use */
ret = -EBUSY;
irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
if (irq < 0) {
dev->irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
if (dev->irq < 0) {
printk(KERN_ERR "%s(): cannot get GSC irq\n", __FUNCTION__);
goto out;
}
ret = request_irq(gsc_irq.irq, busdev_barked, 0, "asp", asp);
asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "asp", asp);
if (ret < 0)
goto out;
/* Save this for debugging later */
asp->parent_irq = gsc_irq.irq;
asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
/* Program VIPER to interrupt on the ASP irq */
gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD);
/* Done init'ing, register this driver */
ret = gsc_common_irqsetup(dev, asp);
ret = gsc_common_setup(dev, asp);
if (ret)
goto out;
fixup_child_irqs(dev, asp->busdev_region->data.irqbase, asp_choose_irq);
gsc_fixup_irqs(dev, asp, asp_choose_irq);
/* Mongoose is a sibling of Asp, not a child... */
fixup_child_irqs(dev->parent, asp->busdev_region->data.irqbase,
asp_choose_irq);
gsc_fixup_irqs(parisc_parent(dev), asp, asp_choose_irq);
/* initialize the chassis LEDs */
#ifdef CONFIG_CHASSIS_LCD_LED
register_led_driver(DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE,
(char *)ASP_LED_ADDR);
ASP_LED_ADDR);
#endif
return 0;
......
......@@ -57,7 +57,6 @@
#include <asm/page.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include "gsc.h"
......@@ -146,12 +145,10 @@ struct dino_device
spinlock_t dinosaur_pen;
unsigned long txn_addr; /* EIR addr to generate interrupt */
u32 txn_data; /* EIR data assign to each dino */
int irq; /* Virtual IRQ dino uses */
struct irq_region *dino_region; /* region for this Dino */
u32 imr; /* IRQ's which are enabled */
u32 imr; /* IRQ's which are enabled */
int global_irq[12]; /* map IMR bit to global irq */
#ifdef DINO_DEBUG
unsigned int dino_irr0; /* save most recent IRQ line stat */
unsigned int dino_irr0; /* save most recent IRQ line stat */
#endif
};
......@@ -298,45 +295,37 @@ struct pci_port_ops dino_port_ops = {
.outl = dino_out32
};
static void
dino_mask_irq(void *irq_dev, int irq)
static void dino_disable_irq(unsigned int irq)
{
struct dino_device *dino_dev = DINO_DEV(irq_dev);
struct dino_device *dino_dev = irq_desc[irq].handler_data;
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq);
DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq);
if (NULL == irq_dev || irq > DINO_IRQS || irq < 0) {
printk(KERN_WARNING "%s(0x%lx, %d) - not a dino irq?\n",
__FUNCTION__, (long) irq_dev, irq);
BUG();
} else {
/*
** Clear the matching bit in the IMR register
*/
dino_dev->imr &= ~(DINO_MASK_IRQ(irq));
gsc_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
}
/* Clear the matching bit in the IMR register */
dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq));
__raw_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
}
static void
dino_unmask_irq(void *irq_dev, int irq)
static void dino_enable_irq(unsigned int irq)
{
struct dino_device *dino_dev = DINO_DEV(irq_dev);
struct dino_device *dino_dev = irq_desc[irq].handler_data;
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, irq);
u32 tmp;
DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq);
if (NULL == irq_dev || irq > DINO_IRQS) {
printk(KERN_WARNING "%s(): %d not a dino irq?\n",
__FUNCTION__, irq);
BUG();
return;
}
/*
** clear pending IRQ bits
**
** This does NOT change ILR state!
** See comment below for ILR usage.
*/
__raw_readl(dino_dev->hba.base_addr+DINO_IPR);
/* set the matching bit in the IMR register */
dino_dev->imr |= DINO_MASK_IRQ(irq); /* used in dino_isr() */
gsc_writel( dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
dino_dev->imr |= DINO_MASK_IRQ(local_irq); /* used in dino_isr() */
__raw_writel( dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
/* Emulate "Level Triggered" Interrupt
** Basically, a driver is blowing it if the IRQ line is asserted
......@@ -347,38 +336,28 @@ dino_unmask_irq(void *irq_dev, int irq)
** dino_isr() will read IPR and find nothing. But then catch this
** when it also checks ILR.
*/
tmp = gsc_readl(dino_dev->hba.base_addr+DINO_ILR);
if (tmp & DINO_MASK_IRQ(irq)) {
tmp = __raw_readl(dino_dev->hba.base_addr+DINO_ILR);
if (tmp & DINO_MASK_IRQ(local_irq)) {
DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
__FUNCTION__, tmp);
gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
}
}
static void
dino_enable_irq(void *irq_dev, int irq)
static unsigned int dino_startup_irq(unsigned int irq)
{
struct dino_device *dino_dev = DINO_DEV(irq_dev);
/*
** clear pending IRQ bits
**
** This does NOT change ILR state!
** See comments in dino_unmask_irq() for ILR usage.
*/
gsc_readl(dino_dev->hba.base_addr+DINO_IPR);
dino_unmask_irq(irq_dev, irq);
dino_enable_irq(irq);
return 0;
}
static struct irq_region_ops dino_irq_ops = {
.disable_irq = dino_mask_irq, /* ??? */
.enable_irq = dino_enable_irq,
.mask_irq = dino_mask_irq,
.unmask_irq = dino_unmask_irq
static struct hw_interrupt_type dino_interrupt_type = {
.typename = "GSC-PCI",
.startup = dino_startup_irq,
.shutdown = dino_disable_irq,
.enable = dino_enable_irq,
.disable = dino_disable_irq,
.ack = no_ack_irq,
.end = no_end_irq,
};
......@@ -391,34 +370,28 @@ static struct irq_region_ops dino_irq_ops = {
static irqreturn_t
dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
{
struct dino_device *dino_dev = DINO_DEV(intr_dev);
struct dino_device *dino_dev = intr_dev;
u32 mask;
int ilr_loop = 100;
extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
/* read and acknowledge pending interrupts */
#ifdef DINO_DEBUG
dino_dev->dino_irr0 =
#endif
mask = gsc_readl(dino_dev->hba.base_addr+DINO_IRR0) & DINO_IRR_MASK;
ilr_again:
while (mask)
{
int irq;
irq = __ffs(mask);
mask = __raw_readl(dino_dev->hba.base_addr+DINO_IRR0) & DINO_IRR_MASK;
mask &= ~(1<<irq);
if (mask == 0)
return IRQ_NONE;
DBG(KERN_WARNING "%s(%x, %p) mask %0x\n",
ilr_again:
do {
int local_irq = __ffs(mask);
int irq = dino_dev->global_irq[local_irq];
DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
__FUNCTION__, irq, intr_dev, mask);
do_irq(&dino_dev->dino_region->action[irq],
dino_dev->dino_region->data.irqbase + irq,
regs);
}
__do_IRQ(irq, regs);
mask &= ~(1 << local_irq);
} while (mask);
/* Support for level triggered IRQ lines.
**
......@@ -427,27 +400,40 @@ dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
** device drivers may assume lines are level triggered (and not
** edge triggered like EISA/ISA can be).
*/
mask = gsc_readl(dino_dev->hba.base_addr+DINO_ILR) & dino_dev->imr;
mask = __raw_readl(dino_dev->hba.base_addr+DINO_ILR) & dino_dev->imr;
if (mask) {
if (--ilr_loop > 0)
goto ilr_again;
printk(KERN_ERR "Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
printk(KERN_ERR "Dino 0x%p: stuck interrupt %d\n",
dino_dev->hba.base_addr, mask);
return IRQ_NONE;
}
return IRQ_HANDLED;
}
static int dino_choose_irq(struct parisc_device *dev)
static void dino_assign_irq(struct dino_device *dino, int local_irq, int *irqp)
{
int irq = -1;
int irq = gsc_assign_irq(&dino_interrupt_type, dino);
if (irq == NO_IRQ)
return;
*irqp = irq;
dino->global_irq[local_irq] = irq;
}
static void dino_choose_irq(struct parisc_device *dev, void *ctrl)
{
int irq;
struct dino_device *dino = ctrl;
switch (dev->id.sversion) {
case 0x00084: irq = 8; break; /* PS/2 */
case 0x0008c: irq = 10; break; /* RS232 */
case 0x00096: irq = 8; break; /* PS/2 */
default: return; /* Unknown */
}
return irq;
dino_assign_irq(dino, irq, &dev->irq);
}
static void __init
......@@ -664,11 +650,15 @@ dino_fixup_bus(struct pci_bus *bus)
u32 irq_pin;
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin);
dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 1, dev->irq);
dev->irq += dino_dev->dino_region->data.irqbase;
printk(KERN_WARNING "Device %s has undefined IRQ, setting to %d\n", dev->slot_name, irq_pin);
dino_cfg_read(dev->bus, dev->devfn,
PCI_INTERRUPT_PIN, 1, &irq_pin);
irq_pin = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
printk(KERN_WARNING "Device %s has undefined IRQ, "
"setting to %d\n", dev->slot_name,
irq_pin);
dino_cfg_write(dev->bus, dev->devfn,
PCI_INTERRUPT_LINE, 1, irq_pin);
dino_assign_irq(dino_dev, irq_pin, &dev->irq);
#else
dev->irq = 65535;
printk(KERN_WARNING "Device %s has unassigned IRQ\n", dev->slot_name);
......@@ -676,7 +666,7 @@ dino_fixup_bus(struct pci_bus *bus)
} else {
/* Adjust INT_LINE for that busses region */
dev->irq += dino_dev->dino_region->data.irqbase;
dino_assign_irq(dino_dev, dev->irq, &dev->irq);
}
}
}
......@@ -830,7 +820,7 @@ static int __init dino_common_init(struct parisc_device *dev,
** still only has 11 IRQ input lines - just map some of them
** to a different processor.
*/
dino_dev->irq = gsc_alloc_irq(&gsc_irq);
dev->irq = gsc_alloc_irq(&gsc_irq);
dino_dev->txn_addr = gsc_irq.txn_addr;
dino_dev->txn_data = gsc_irq.txn_data;
eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
......@@ -839,49 +829,36 @@ static int __init dino_common_init(struct parisc_device *dev,
** Dino needs a PA "IRQ" to get a processor's attention.
** arch/parisc/kernel/irq.c returns an EIRR bit.
*/
if (dino_dev->irq < 0) {
if (dev->irq < 0) {
printk(KERN_WARNING "%s: gsc_alloc_irq() failed\n", name);
return 1;
}
status = request_irq(dino_dev->irq, dino_isr, 0, name, dino_dev);
status = request_irq(dev->irq, dino_isr, 0, name, dino_dev);
if (status) {
printk(KERN_WARNING "%s: request_irq() failed with %d\n",
name, status);
return 1;
}
/*
** Tell generic interrupt support we have 11 bits which need
** be checked in the interrupt handler.
*/
dino_dev->dino_region = alloc_irq_region(DINO_IRQS, &dino_irq_ops,
name, dino_dev);
if (NULL == dino_dev->dino_region) {
printk(KERN_WARNING "%s: alloc_irq_region() failed\n", name);
return 1;
}
/* Support the serial port which is sometimes attached on built-in
* Dino / Cujo chips.
*/
fixup_child_irqs(dev, dino_dev->dino_region->data.irqbase,
dino_choose_irq);
gsc_fixup_irqs(dev, dino_dev, dino_choose_irq);
/*
** This enables DINO to generate interrupts when it sees
** any of its inputs *change*. Just asserting an IRQ
** before it's enabled (ie unmasked) isn't good enough.
*/
gsc_writel(eim, dino_dev->hba.base_addr+DINO_IAR0);
__raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0);
/*
** Some platforms don't clear Dino's IRR0 register at boot time.
** Reading will clear it now.
*/
gsc_readl(dino_dev->hba.base_addr+DINO_IRR0);
__raw_readl(dino_dev->hba.base_addr+DINO_IRR0);
/* allocate I/O Port resource region */
res = &dino_dev->hba.io_space;
......
......@@ -29,7 +29,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
......@@ -142,7 +142,7 @@ static unsigned int eisa_irq_level; /* default to edge triggered */
/* called by free irq */
static void eisa_disable_irq(void *irq_dev, int irq)
static void eisa_disable_irq(unsigned int irq)
{
unsigned long flags;
......@@ -162,7 +162,7 @@ static void eisa_disable_irq(void *irq_dev, int irq)
}
/* called by request irq */
static void eisa_enable_irq(void *irq_dev, int irq)
static void eisa_enable_irq(unsigned int irq)
{
unsigned long flags;
EISA_DBG("enable irq %d\n", irq);
......@@ -180,52 +180,24 @@ static void eisa_enable_irq(void *irq_dev, int irq)
EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1));
}
static void eisa_mask_irq(void *irq_dev, int irq)
static unsigned int eisa_startup_irq(unsigned int irq)
{
unsigned long flags;
EISA_DBG("mask irq %d\n", irq);
/* mask irq */
spin_lock_irqsave(&eisa_irq_lock, flags);
if (irq & 8) {
slave_mask |= (1 << (irq&7));
eisa_out8(slave_mask, 0xa1);
} else {
master_mask |= (1 << (irq&7));
eisa_out8(master_mask, 0x21);
}
spin_unlock_irqrestore(&eisa_irq_lock, flags);
}
static void eisa_unmask_irq(void *irq_dev, int irq)
{
unsigned long flags;
EISA_DBG("unmask irq %d\n", irq);
/* unmask */
spin_lock_irqsave(&eisa_irq_lock, flags);
if (irq & 8) {
slave_mask &= ~(1 << (irq&7));
eisa_out8(slave_mask, 0xa1);
} else {
master_mask &= ~(1 << (irq&7));
eisa_out8(master_mask, 0x21);
}
spin_unlock_irqrestore(&eisa_irq_lock, flags);
eisa_enable_irq(irq);
return 0;
}
static struct irqaction action[IRQ_PER_REGION];
/* EISA needs to be fixed at IRQ region #0 (EISA_IRQ_REGION) */
static struct irq_region eisa_irq_region = {
.ops = { eisa_disable_irq, eisa_enable_irq, eisa_mask_irq, eisa_unmask_irq },
.data = { .name = "EISA", .irqbase = 0 },
.action = action,
static struct hw_interrupt_type eisa_interrupt_type = {
.typename = "EISA",
.startup = eisa_startup_irq,
.shutdown = eisa_disable_irq,
.enable = eisa_enable_irq,
.disable = eisa_disable_irq,
.ack = no_ack_irq,
.end = no_end_irq,
};
static irqreturn_t eisa_irq(int _, void *intr_dev, struct pt_regs *regs)
static irqreturn_t eisa_irq(int wax_irq, void *intr_dev, struct pt_regs *regs)
{
extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */
unsigned long flags;
......@@ -259,8 +231,7 @@ static irqreturn_t eisa_irq(int _, void *intr_dev, struct pt_regs *regs)
}
spin_unlock_irqrestore(&eisa_irq_lock, flags);
do_irq(&eisa_irq_region.action[irq], EISA_IRQ_REGION + irq, regs);
__do_IRQ(irq, regs);
spin_lock_irqsave(&eisa_irq_lock, flags);
/* unmask */
......@@ -281,6 +252,11 @@ static irqreturn_t dummy_irq2_handler(int _, void *dev, struct pt_regs *regs)
return IRQ_HANDLED;
}
static struct irqaction irq2_action = {
.handler = dummy_irq2_handler,
.name = "cascade",
};
static void init_eisa_pic(void)
{
unsigned long flags;
......@@ -331,7 +307,7 @@ static void init_eisa_pic(void)
static int __devinit eisa_probe(struct parisc_device *dev)
{
int result;
int i, result;
char *name = is_mongoose(dev) ? "Mongoose" : "Wax";
......@@ -361,18 +337,18 @@ static int __devinit eisa_probe(struct parisc_device *dev)
}
pcibios_register_hba(&eisa_dev.hba);
result = request_irq(dev->irq, eisa_irq, SA_SHIRQ, "EISA", NULL);
result = request_irq(dev->irq, eisa_irq, SA_SHIRQ, "EISA", &eisa_dev);
if (result) {
printk(KERN_ERR "EISA: request_irq failed!\n");
return result;
}
/* Reserve IRQ2 */
action[2].handler = dummy_irq2_handler;
action[2].name = "cascade";
irq_desc[2].action = &irq2_action;
eisa_irq_region.data.dev = dev;
irq_region[0] = &eisa_irq_region;
for (i = 0; i < 16; i++) {
irq_desc[i].handler = &eisa_interrupt_type;
}
EISA_bus = 1;
if (dev->num_addrs) {
......
......@@ -25,15 +25,9 @@
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "gsc.h"
/* This sets the vmerge boundary and size, it's here because it has to
* be available on all platforms (zero means no-virtual merging) */
unsigned long parisc_vmerge_boundary = 0;
unsigned long parisc_vmerge_max_size = 0;
#undef DEBUG
#ifdef DEBUG
......@@ -61,7 +55,7 @@ int gsc_claim_irq(struct gsc_irq *i, int irq)
{
int c = irq;
irq += IRQ_FROM_REGION(CPU_IRQ_REGION); /* virtualize the IRQ first */
irq += CPU_IRQ_BASE; /* virtualize the IRQ first */
irq = txn_claim_irq(irq);
if (irq < 0) {
......@@ -79,116 +73,146 @@ int gsc_claim_irq(struct gsc_irq *i, int irq)
EXPORT_SYMBOL(gsc_alloc_irq);
EXPORT_SYMBOL(gsc_claim_irq);
/* IRQ bits must be numbered from Most Significant Bit */
#define GSC_FIX_IRQ(x) (31-(x))
#define GSC_MASK_IRQ(x) (1<<(GSC_FIX_IRQ(x)))
/* Common interrupt demultiplexer used by Asp, Lasi & Wax. */
irqreturn_t busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs)
irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev, struct pt_regs *regs)
{
unsigned long irq;
struct busdevice *busdev = (struct busdevice *) dev;
/*
Don't need to protect OFFSET_IRR with spinlock since this is
the only place it's touched.
Protect busdev_region by disabling this region's interrupts,
modifying the region, and then re-enabling the region.
*/
irq = gsc_readl(busdev->hpa+OFFSET_IRR);
if (irq == 0) {
printk(KERN_ERR "%s: barking without apparent reason.\n", busdev->name);
} else {
DEBPRINTK ("%s (0x%x) barked, mask=0x%x, irq=%d\n",
busdev->name, busdev->busdev_region->data.irqbase,
irq, GSC_FIX_IRQ(ffs(irq))+1 );
do_irq_mask(irq, busdev->busdev_region, regs);
}
unsigned long irr;
struct gsc_asic *gsc_asic = dev;
irr = gsc_readl(gsc_asic->hpa + OFFSET_IRR);
if (irr == 0)
return IRQ_NONE;
DEBPRINTK("%s intr, mask=0x%x\n", gsc_asic->name, irr);
do {
int local_irq = __ffs(irr);
unsigned int irq = gsc_asic->global_irq[local_irq];
__do_IRQ(irq, regs);
irr &= ~(1 << local_irq);
} while (irr);
return IRQ_HANDLED;
}
static void
busdev_disable_irq(void *irq_dev, int irq)
int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
{
/* Disable the IRQ line by clearing the bit in the IMR */
u32 imr = gsc_readl(BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR);
imr &= ~(GSC_MASK_IRQ(irq));
int local_irq;
DEBPRINTK( KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n",
__FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr);
for (local_irq = 0; local_irq < limit; local_irq++) {
if (global_irqs[local_irq] == irq)
return local_irq;
}
gsc_writel(imr, BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR);
return NO_IRQ;
}
static void gsc_asic_disable_irq(unsigned int irq)
{
struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __FUNCTION__, irq,
irq_dev->name, imr);
static void
busdev_enable_irq(void *irq_dev, int irq)
/* Disable the IRQ line by clearing the bit in the IMR */
imr = gsc_readl(irq_dev->hpa + OFFSET_IMR);
imr &= ~(1 << local_irq);
gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
}
static void gsc_asic_enable_irq(unsigned int irq)
{
/* Enable the IRQ line by setting the bit in the IMR */
unsigned long addr = BUSDEV_DEV(irq_dev)->hpa + OFFSET_IMR;
u32 imr = gsc_readl(addr);
imr |= GSC_MASK_IRQ(irq);
struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
DEBPRINTK (KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n",
__FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr);
DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __FUNCTION__, irq,
irq_dev->name, imr);
gsc_writel(imr, addr);
// gsc_writel(~0L, addr);
/* Enable the IRQ line by setting the bit in the IMR */
imr = gsc_readl(irq_dev->hpa + OFFSET_IMR);
imr |= 1 << local_irq;
gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
/*
* FIXME: read IPR to make sure the IRQ isn't already pending.
* If so, we need to read IRR and manually call do_irq().
*/
}
/* FIXME: read IPR to make sure the IRQ isn't already pending.
** If so, we need to read IRR and manually call do_irq_mask().
** This code should be shared with busdev_unmask_irq().
*/
static unsigned int gsc_asic_startup_irq(unsigned int irq)
{
gsc_asic_enable_irq(irq);
return 0;
}
static void
busdev_mask_irq(void *irq_dev, int irq)
static struct hw_interrupt_type gsc_asic_interrupt_type = {
.typename = "GSC-ASIC",
.startup = gsc_asic_startup_irq,
.shutdown = gsc_asic_disable_irq,
.enable = gsc_asic_enable_irq,
.disable = gsc_asic_disable_irq,
.ack = no_ack_irq,
.end = no_end_irq,
};
int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
{
/* FIXME: Clear the IMR bit in busdev for that IRQ */
static int irq = GSC_IRQ_BASE;
if (irq > GSC_IRQ_MAX)
return NO_IRQ;
irq_desc[irq].handler = type;
irq_desc[irq].handler_data = data;
return irq++;
}
static void
busdev_unmask_irq(void *irq_dev, int irq)
void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp)
{
/* FIXME: Read IPR. Set the IMR bit in busdev for that IRQ.
call do_irq_mask() if IPR is non-zero
*/
int irq = gsc_assign_irq(&gsc_asic_interrupt_type, asic);
if (irq == NO_IRQ)
return;
*irqp = irq;
asic->global_irq[local_irq] = irq;
}
struct irq_region_ops busdev_irq_ops = {
.disable_irq = busdev_disable_irq,
.enable_irq = busdev_enable_irq,
.mask_irq = busdev_mask_irq,
.unmask_irq = busdev_unmask_irq
};
void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
void (*choose_irq)(struct parisc_device *, void *))
{
struct device *dev;
list_for_each_entry(dev, &parent->dev.children, node) {
struct parisc_device *padev = to_parisc_device(dev);
int gsc_common_irqsetup(struct parisc_device *parent, struct busdevice *busdev)
/* work-around for 715/64 and others which have parent
at path [5] and children at path [5/0/x] */
if (padev->id.hw_type == HPHW_FAULTY)
return gsc_fixup_irqs(padev, ctrl, choose_irq);
choose_irq(padev, ctrl);
}
}
int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic)
{
struct resource *res;
busdev->gsc = parent;
/* the IRQs we simulate */
busdev->busdev_region = alloc_irq_region(32, &busdev_irq_ops,
busdev->name, busdev);
if (!busdev->busdev_region)
return -ENOMEM;
gsc_asic->gsc = parent;
/* allocate resource region */
res = request_mem_region(busdev->hpa, 0x100000, busdev->name);
res = request_mem_region(gsc_asic->hpa, 0x100000, gsc_asic->name);
if (res) {
res->flags = IORESOURCE_MEM; /* do not mark it busy ! */
}
#if 0
printk(KERN_WARNING "%s IRQ %d EIM 0x%x", busdev->name,
busdev->parent_irq, busdev->eim);
if (gsc_readl(busdev->hpa + OFFSET_IMR))
printk(KERN_WARNING "%s IRQ %d EIM 0x%x", gsc_asic->name,
parent->irq, gsc_asic->eim);
if (gsc_readl(gsc_asic->hpa + OFFSET_IMR))
printk(" IMR is non-zero! (0x%x)",
gsc_readl(busdev->hpa + OFFSET_IMR));
gsc_readl(gsc_asic->hpa + OFFSET_IMR));
printk("\n");
#endif
......
......@@ -25,22 +25,23 @@ struct gsc_irq {
int irq; /* virtual IRQ */
};
struct busdevice {
struct gsc_asic {
struct parisc_device *gsc;
unsigned long hpa;
char *name;
int version;
int type;
int parent_irq;
int eim;
struct irq_region *busdev_region;
int global_irq[32];
};
/* short cut to keep the compiler happy */
#define BUSDEV_DEV(x) ((struct busdevice *) (x))
int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic);
int gsc_alloc_irq(struct gsc_irq *dev); /* dev needs an irq */
int gsc_claim_irq(struct gsc_irq *dev, int irq); /* dev needs this irq */
int gsc_assign_irq(struct hw_interrupt_type *type, void *data);
int gsc_find_local_irq(unsigned int irq, int *global_irq, int limit);
void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
void (*choose)(struct parisc_device *child, void *ctrl));
void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp);
int gsc_common_irqsetup(struct parisc_device *parent, struct busdevice *busdev);
extern int gsc_alloc_irq(struct gsc_irq *dev); /* dev needs an irq */
extern int gsc_claim_irq(struct gsc_irq *dev, int irq); /* dev needs this irq */
irqreturn_t busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs);
irqreturn_t gsc_asic_intr(int irq, void *dev, struct pt_regs *regs);
......@@ -76,35 +76,13 @@
** iosapic_register().
**
**
** IRQ region notes
** ----------------
** The data passed to iosapic_interrupt() is per IRQ line.
** Each IRQ line will get one txn_addr/data pair. Thus each IRQ region,
** will have several txn_addr/data pairs (up to 7 for current I/O SAPIC
** implementations). The IRQ region "sysdata" will NOT be directly passed
** to the interrupt handler like GSCtoPCI (dino.c).
**
** iosapic interrupt handler will NOT call do_irq_mask().
** It doesn't need to read a bit mask to determine which IRQ line was pulled
** since it already knows based on vector_info passed to iosapic_interrupt().
**
** One IRQ number represents both an IRQ line and a driver ISR.
** The I/O sapic driver can't manage shared IRQ lines because
** additional data besides the IRQ number must be passed via
** irq_region_ops. do_irq() and request_irq() must manage
** a sharing a bit in the mask.
**
** iosapic_interrupt() replaces do_irq_mask() and calls do_irq().
** Which IRQ line was asserted is already known since each
** line has unique data associated with it. We could omit
** iosapic_interrupt() from the calling path if it did NOT need
** to write EOI. For unshared lines, it really doesn't.
**
** Unfortunately, can't optimize out EOI if IRQ line isn't "shared".
** N-class console "device" and some sort of heartbeat actually share
** one line though only one driver is registered...<sigh>...this was
** true for HP-UX at least. May not be true for parisc-linux.
**
** IRQ handling notes
** ------------------
** The IO-SAPIC can indicate to the CPU which interrupt was asserted.
** So, unlike the GSC-ASIC and Dino, we allocate one CPU interrupt per
** IO-SAPIC interrupt and call the device driver's handler directly.
** The IO-SAPIC driver hijacks the CPU interrupt handler so it can
** issue the End Of Interrupt command to the IO-SAPIC.
**
** Overview of exported iosapic functions
** --------------------------------------
......@@ -138,11 +116,6 @@
** o locate vector_info (needs: isi, intr_line)
** o allocate processor "irq" and get txn_addr/data
** o request_irq(processor_irq, iosapic_interrupt, vector_info,...)
** o pcidev->irq = isi->isi_region...base + intr_line;
**
** iosapic_interrupt:
** o call do_irq(vector->isi->irq_region, vector->irq_line, regs)
** o assume level triggered and write EOI
**
** iosapic_enable_irq:
** o clear any pending IRQ on that line
......@@ -151,8 +124,6 @@
**
** iosapic_disable_irq:
** o disable IRdT - call disable_irq(vector[line]->processor_irq)
**
** FIXME: mask/unmask
*/
......@@ -160,18 +131,15 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/pci.h> /* pci cfg accessor functions */
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h> /* irqaction */
#include <linux/irq.h> /* irq_region support */
#include <linux/interrupt.h>
#include <asm/byteorder.h> /* get in-line asm for swab */
#include <asm/pdc.h>
#include <asm/pdcpat.h>
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h> /* read/write functions */
#ifdef CONFIG_SUPERIO
......@@ -278,10 +246,12 @@ static inline void iosapic_write(unsigned long iosapic, unsigned int reg, u32 va
#define IOSAPIC_IRDT_ID_EID_SHIFT 0x10
static struct iosapic_info *iosapic_list;
static spinlock_t iosapic_lock;
static int iosapic_count;
static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;
static inline void iosapic_eoi(void __iomem *addr, unsigned int data)
{
__raw_writel(data, addr);
}
/*
** REVISIT: future platforms may have more than one IRT.
......@@ -598,167 +568,34 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
return irt_find_irqline(isi, intr_slot, intr_pin);
}
static irqreturn_t
iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct vector_info *vi = (struct vector_info *) dev_id;
extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
int irq_num = vi->iosapic->isi_region->data.irqbase + vi->irqline;
DBG("iosapic_interrupt(): irq %d line %d eoi 0x%p 0x%x\n",
irq, vi->irqline, vi->eoi_addr, vi->eoi_data);
/* Do NOT need to mask/unmask IRQ. processor is already masked. */
do_irq(&vi->iosapic->isi_region->action[vi->irqline], irq_num, regs);
/*
** PARISC only supports PCI devices below I/O SAPIC.
** PCI only supports level triggered in order to share IRQ lines.
** ergo I/O SAPIC must always issue EOI on parisc.
**
** i386/ia64 support ISA devices and have to deal with
** edge-triggered interrupts too.
*/
__raw_writel(vi->eoi_data, vi->eoi_addr);
return IRQ_HANDLED;
}
int
iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
{
struct iosapic_info *isi = (struct iosapic_info *)isi_obj;
struct irt_entry *irte = NULL; /* only used if PAT PDC */
struct vector_info *vi;
int isi_line; /* line used by device */
int tmp;
if (NULL == isi) {
printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
pci_name(pcidev));
return(-1);
}
#ifdef CONFIG_SUPERIO
/*
* HACK ALERT! (non-compliant PCI device support)
*
* All SuckyIO interrupts are routed through the PIC's on function 1.
* But SuckyIO OHCI USB controller gets an IRT entry anyway because
* it advertises INT D for INT_PIN. Use that IRT entry to get the
* SuckyIO interrupt routing for PICs on function 1 (*BLEECCHH*).
*/
if (is_superio_device(pcidev)) {
/* We must call superio_fixup_irq() to register the pdev */
pcidev->irq = superio_fixup_irq(pcidev);
/* Don't return if need to program the IOSAPIC's IRT... */
if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN)
return pcidev->irq;
}
#endif /* CONFIG_SUPERIO */
/* lookup IRT entry for isi/slot/pin set */
irte = iosapic_xlate_pin(isi, pcidev);
if (NULL == irte) {
printk("iosapic: no IRTE for %s (IRQ not connected?)\n",
pci_name(pcidev));
return(-1);
}
DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n",
irte,
irte->entry_type,
irte->entry_length,
irte->polarity_trigger,
irte->src_bus_irq_devno,
irte->src_bus_id,
irte->src_seg_id,
irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr);
isi_line = irte->dest_iosapic_intin;
pcidev->irq = isi->isi_region->data.irqbase + isi_line;
/* get vector info for this input line */
ASSERT(NULL != isi->isi_vector);
vi = &(isi->isi_vector[isi_line]);
DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi);
/* If this IRQ line has already been setup, skip it */
if (vi->irte)
return pcidev->irq;
vi->irte = irte;
/* Allocate processor IRQ */
vi->txn_irq = txn_alloc_irq();
/* XXX/FIXME The txn_alloc_irq() code and related code should be moved
** to enable_irq(). That way we only allocate processor IRQ bits
** for devices that actually have drivers claiming them.
** Right now we assign an IRQ to every PCI device present regardless
** of whether it's used or not.
*/
if (vi->txn_irq < 0)
panic("I/O sapic: couldn't get TXN IRQ\n");
/* enable_irq() will use txn_* to program IRdT */
vi->txn_addr = txn_alloc_addr(vi->txn_irq);
vi->txn_data = txn_alloc_data(vi->txn_irq, 8);
ASSERT(vi->txn_data < 256); /* matches 8 above */
tmp = request_irq(vi->txn_irq, iosapic_interrupt, 0,
vi->name, vi);
ASSERT(tmp == 0);
vi->eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
vi->eoi_data = cpu_to_le32(vi->txn_data);
ASSERT(NULL != isi->isi_region);
DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->irq),
pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
return pcidev->irq;
}
static void
iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
static void iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
{
struct iosapic_info *isp = vi->iosapic;
u8 idx = vi->irqline;
*dp0 = iosapic_read(isp->isi_hpa, IOSAPIC_IRDT_ENTRY(idx));
*dp1 = iosapic_read(isp->isi_hpa, IOSAPIC_IRDT_ENTRY_HI(idx));
*dp0 = iosapic_read(isp->addr, IOSAPIC_IRDT_ENTRY(idx));
*dp1 = iosapic_read(isp->addr, IOSAPIC_IRDT_ENTRY_HI(idx));
}
static void
iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1)
static void iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1)
{
struct iosapic_info *isp = vi->iosapic;
ASSERT(NULL != isp);
ASSERT(0 != isp->isi_hpa);
DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p 0x%x 0x%x\n",
vi->irqline,
isp->isi_hpa,
dp0, dp1);
DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %lx 0x%x 0x%x\n",
vi->irqline, isp->isi_hpa, dp0, dp1);
iosapic_write(isp->isi_hpa, IOSAPIC_IRDT_ENTRY(vi->irqline), dp0);
iosapic_write(isp->addr, IOSAPIC_IRDT_ENTRY(vi->irqline), dp0);
/* Read the window register to flush the writes down to HW */
dp0 = readl(isp->isi_hpa+IOSAPIC_REG_WINDOW);
dp0 = readl(isp->addr+IOSAPIC_REG_WINDOW);
iosapic_write(isp->isi_hpa, IOSAPIC_IRDT_ENTRY_HI(vi->irqline), dp1);
iosapic_write(isp->addr, IOSAPIC_IRDT_ENTRY_HI(vi->irqline), dp1);
/* Read the window register to flush the writes down to HW */
dp1 = readl(isp->isi_hpa+IOSAPIC_REG_WINDOW);
dp1 = readl(isp->addr+IOSAPIC_REG_WINDOW);
}
/*
** set_irt prepares the data (dp0, dp1) according to the vector_info
** and target cpu (id_eid). dp0/dp1 are then used to program I/O SAPIC
......@@ -810,62 +647,31 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
}
static void
iosapic_disable_irq(void *irq_dev, int irq)
static struct vector_info *iosapic_get_vector(unsigned int irq)
{
ulong irqflags;
struct vector_info *vi = &(((struct vector_info *) irq_dev)[irq]);
u32 d0, d1;
ASSERT(NULL != vi);
IOSAPIC_LOCK(&iosapic_lock);
#ifdef REVISIT_DESIGN_ISSUE
/*
** XXX/FIXME
disable_irq()/enable_irq(): drawback of using IRQ as a "handle"
Current disable_irq interface only allows the irq_region support routines
to manage sharing of "irq" objects. The problem is the disable_irq()
interface specifies which IRQ line needs to be disabled but does not
identify the particular ISR which needs to be disabled. IO sapic
(and similar code in Dino) can only support one handler per IRQ
since they don't further encode the meaning of the IRQ number.
irq_region support has to hide it's implementation of "shared IRQ"
behind a function call.
Encoding the IRQ would be possible by I/O SAPIC but makes life really
complicated for the IRQ handler and not help performance.
return irq_desc[irq].handler_data;
}
Need more info on how Linux supports shared IRQ lines on a PC.
*/
#endif /* REVISIT_DESIGN_ISSUE */
static void iosapic_disable_irq(unsigned int irq)
{
unsigned long flags;
struct vector_info *vi = iosapic_get_vector(irq);
u32 d0, d1;
spin_lock_irqsave(&iosapic_lock, flags);
iosapic_rd_irt_entry(vi, &d0, &d1);
d0 |= IOSAPIC_IRDT_ENABLE;
iosapic_wr_irt_entry(vi, d0, d1);
IOSAPIC_UNLOCK(&iosapic_lock);
/* disable ISR for parent */
disable_irq(vi->txn_irq);
spin_unlock_irqrestore(&iosapic_lock, flags);
}
static void
iosapic_enable_irq(void *dev, int irq)
static void iosapic_enable_irq(unsigned int irq)
{
struct vector_info *vi = &(((struct vector_info *) dev)[irq]);
struct vector_info *vi = iosapic_get_vector(irq);
u32 d0, d1;
ASSERT(NULL != vi);
ASSERT(NULL != vi->irte);
/* data is initialized by fixup_irq */
ASSERT(0 < vi->txn_irq);
ASSERT(0UL != vi->txn_data);
WARN_ON(vi->txn_irq == 0);
iosapic_set_irt_data(vi, &d0, &d1);
iosapic_wr_irt_entry(vi, d0, d1);
......@@ -884,7 +690,7 @@ printk("iosapic_enable_irq(): sel ");
struct iosapic_info *isp = vi->iosapic;
for (d0=0x10; d0<0x1e; d0++) {
d1 = iosapic_read(isp->isi_hpa, d0);
d1 = iosapic_read(isp->addr, d0);
printk(" %x", d1);
}
}
......@@ -892,35 +698,141 @@ printk("\n");
#endif
/*
** Issueing I/O SAPIC an EOI causes an interrupt IFF IRQ line is
** asserted. IRQ generally should not be asserted when a driver
** enables their IRQ. It can lead to "interesting" race conditions
** in the driver initialization sequence.
*/
__raw_writel(vi->eoi_data, vi->eoi_addr);
* Issuing I/O SAPIC an EOI causes an interrupt IFF IRQ line is
* asserted. IRQ generally should not be asserted when a driver
* enables their IRQ. It can lead to "interesting" race conditions
* in the driver initialization sequence.
*/
DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq,
vi->eoi_addr, vi->eoi_data);
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
}
/*
* PARISC only supports PCI devices below I/O SAPIC.
* PCI only supports level triggered in order to share IRQ lines.
* ergo I/O SAPIC must always issue EOI on parisc.
*
* i386/ia64 support ISA devices and have to deal with
* edge-triggered interrupts too.
*/
static void iosapic_end_irq(unsigned int irq)
{
struct vector_info *vi = iosapic_get_vector(irq);
DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
vi->eoi_addr, vi->eoi_data);
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
}
static void
iosapic_mask_irq(void *dev, int irq)
static unsigned int iosapic_startup_irq(unsigned int irq)
{
BUG();
iosapic_enable_irq(irq);
return 0;
}
static struct hw_interrupt_type iosapic_interrupt_type = {
.typename = "IO-SAPIC-level",
.startup = iosapic_startup_irq,
.shutdown = iosapic_disable_irq,
.enable = iosapic_enable_irq,
.disable = iosapic_disable_irq,
.ack = no_ack_irq,
.end = iosapic_end_irq,
// .set_affinity = iosapic_set_affinity_irq,
};
static void
iosapic_unmask_irq(void *dev, int irq)
int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
{
BUG();
}
struct iosapic_info *isi = isi_obj;
struct irt_entry *irte = NULL; /* only used if PAT PDC */
struct vector_info *vi;
int isi_line; /* line used by device */
if (!isi) {
printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
pci_name(pcidev));
return -1;
}
static struct irq_region_ops iosapic_irq_ops = {
.disable_irq = iosapic_disable_irq,
.enable_irq = iosapic_enable_irq,
.mask_irq = iosapic_mask_irq,
.unmask_irq = iosapic_unmask_irq
};
#ifdef CONFIG_SUPERIO
/*
* HACK ALERT! (non-compliant PCI device support)
*
* All SuckyIO interrupts are routed through the PIC's on function 1.
* But SuckyIO OHCI USB controller gets an IRT entry anyway because
* it advertises INT D for INT_PIN. Use that IRT entry to get the
* SuckyIO interrupt routing for PICs on function 1 (*BLEECCHH*).
*/
if (is_superio_device(pcidev)) {
/* We must call superio_fixup_irq() to register the pdev */
pcidev->irq = superio_fixup_irq(pcidev);
/* Don't return if need to program the IOSAPIC's IRT... */
if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN)
return pcidev->irq;
}
#endif /* CONFIG_SUPERIO */
/* lookup IRT entry for isi/slot/pin set */
irte = iosapic_xlate_pin(isi, pcidev);
if (!irte) {
printk("iosapic: no IRTE for %s (IRQ not connected?)\n",
pci_name(pcidev));
return -1;
}
DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n",
irte,
irte->entry_type,
irte->entry_length,
irte->polarity_trigger,
irte->src_bus_irq_devno,
irte->src_bus_id,
irte->src_seg_id,
irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr);
isi_line = irte->dest_iosapic_intin;
/* get vector info for this input line */
vi = isi->isi_vector + isi_line;
DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi);
/* If this IRQ line has already been setup, skip it */
if (vi->irte)
goto out;
vi->irte = irte;
/* Allocate processor IRQ */
vi->txn_irq = txn_alloc_irq();
/*
* XXX/FIXME The txn_alloc_irq() code and related code should be
* moved to enable_irq(). That way we only allocate processor IRQ
* bits for devices that actually have drivers claiming them.
* Right now we assign an IRQ to every PCI device present,
* regardless of whether it's used or not.
*/
if (vi->txn_irq < 0)
panic("I/O sapic: couldn't get TXN IRQ\n");
/* enable_irq() will use txn_* to program IRdT */
vi->txn_addr = txn_alloc_addr(vi->txn_irq);
vi->txn_data = txn_alloc_data(vi->txn_irq, 8);
vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI;
vi->eoi_data = cpu_to_le32(vi->txn_data);
cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi);
out:
pcidev->irq = vi->txn_irq;
DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn),
pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
return pcidev->irq;
}
/*
......@@ -944,10 +856,9 @@ iosapic_rd_version(struct iosapic_info *isi)
** o read iosapic version and squirrel that away
** o read size of IRdT.
** o allocate and initialize isi_vector[]
** o allocate isi_region (registers region handlers)
** o allocate irq region
*/
void *
iosapic_register(unsigned long hpa)
void *iosapic_register(unsigned long hpa)
{
struct iosapic_info *isi = NULL;
struct irt_entry *irte = irt_cell;
......@@ -993,27 +904,16 @@ iosapic_register(unsigned long hpa)
if (vip == NULL) {
IOSAPIC_FREE(isi, struct iosapic_info, 1);
return (NULL);
return NULL;
}
memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors);
sprintf(isi->isi_name, "IO-SAPIC%02d", iosapic_count++);
/*
** Initialize vector array
*/
for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
vip->irqline = (unsigned char) cnt;
vip->iosapic = isi;
sprintf(vip->name, "%s-L%d", isi->isi_name, cnt);
}
isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
&iosapic_irq_ops, isi->isi_name,
(void *) isi->isi_vector);
ASSERT(NULL != isi->isi_region);
return ((void *) isi);
return isi;
}
......
......@@ -136,23 +136,20 @@ struct vector_info {
u32 eoi_data; /* IA64: ? PA: swapped txn_data */
int txn_irq; /* virtual IRQ number for processor */
ulong txn_addr; /* IA64: id_eid PA: partial HPA */
ulong txn_data; /* IA64: vector PA: EIR bit */
u32 txn_data; /* CPU interrupt bit */
u8 status; /* status/flags */
u8 irqline; /* INTINn(IRQ) */
char name[32]; /* user visible identity */
};
struct iosapic_info {
struct iosapic_info *isi_next; /* list of I/O SAPIC */
unsigned long isi_hpa; /* physical base address */
struct irq_region *isi_region; /* each I/O SAPIC is one region */
struct vector_info *isi_vector; /* IRdT (IRQ line) array */
int isi_num_vectors; /* size of IRdT array */
int isi_status; /* status/flags */
unsigned int isi_version; /* DEBUG: data fr version reg */
/* round up to next cacheline */
char isi_name[20]; /* identify region for users */
struct iosapic_info * isi_next; /* list of I/O SAPIC */
void __iomem * addr; /* remapped address */
unsigned long isi_hpa; /* physical base address */
struct vector_info * isi_vector; /* IRdT (IRQ line) array */
int isi_num_vectors; /* size of IRdT array */
int isi_status; /* status/flags */
unsigned int isi_version; /* DEBUG: data fr version reg */
};
......
......@@ -16,7 +16,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/pm.h>
......@@ -35,33 +35,30 @@
#define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */
#define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */
static int lasi_choose_irq(struct parisc_device *dev)
static void lasi_choose_irq(struct parisc_device *dev, void *ctrl)
{
int irq;
/*
** "irq" bits below are numbered relative to most significant bit.
*/
switch (dev->id.sversion) {
case 0x74: irq = 24; break; /* Centronics */
case 0x7B: irq = 18; break; /* Audio */
case 0x81: irq = 17; break; /* Lasi itself */
case 0x82: irq = 22; break; /* SCSI */
case 0x83: irq = 11; break; /* Floppy */
case 0x84: irq = 5; break; /* PS/2 Keyboard */
case 0x87: irq = 13; break; /* ISDN */
case 0x8A: irq = 23; break; /* LAN */
case 0x8C: irq = 26; break; /* RS232 */
case 0x8D: irq = (dev->hw_path == 13) ? 15 : 14;
break; /* Telephone */
default: irq = -1; break; /* unknown */
case 0x74: irq = 7; break; /* Centronics */
case 0x7B: irq = 13; break; /* Audio */
case 0x81: irq = 14; break; /* Lasi itself */
case 0x82: irq = 9; break; /* SCSI */
case 0x83: irq = 20; break; /* Floppy */
case 0x84: irq = 26; break; /* PS/2 Keyboard */
case 0x87: irq = 18; break; /* ISDN */
case 0x8A: irq = 8; break; /* LAN */
case 0x8C: irq = 5; break; /* RS232 */
case 0x8D: irq = (dev->hw_path == 13) ? 16 : 17; break;
/* Telephone */
default: return; /* unknown */
}
return irq;
gsc_asic_assign_irq(ctrl, irq, &dev->irq);
}
static void __init
lasi_init_irq(struct busdevice *this_lasi)
lasi_init_irq(struct gsc_asic *this_lasi)
{
unsigned long lasi_base = this_lasi->hpa;
......@@ -170,11 +167,11 @@ static void lasi_power_off(void)
int __init
lasi_init_chip(struct parisc_device *dev)
{
struct busdevice *lasi;
struct gsc_asic *lasi;
struct gsc_irq gsc_irq;
int irq, ret;
int ret;
lasi = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
lasi = kmalloc(sizeof(*lasi), GFP_KERNEL);
if (!lasi)
return -ENOMEM;
......@@ -193,36 +190,33 @@ lasi_init_chip(struct parisc_device *dev)
lasi_init_irq(lasi);
/* the IRQ lasi should use */
irq = gsc_alloc_irq(&gsc_irq);
if (irq < 0) {
dev->irq = gsc_alloc_irq(&gsc_irq);
if (dev->irq < 0) {
printk(KERN_ERR "%s(): cannot get GSC irq\n",
__FUNCTION__);
kfree(lasi);
return -EBUSY;
}
ret = request_irq(gsc_irq.irq, busdev_barked, 0, "lasi", lasi);
lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
if (ret < 0) {
kfree(lasi);
return ret;
}
/* Save this for debugging later */
lasi->parent_irq = gsc_irq.irq;
lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
/* enable IRQ's for devices below LASI */
gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR);
/* Done init'ing, register this driver */
ret = gsc_common_irqsetup(dev, lasi);
ret = gsc_common_setup(dev, lasi);
if (ret) {
kfree(lasi);
return ret;
}
fixup_child_irqs(dev, lasi->busdev_region->data.irqbase,
lasi_choose_irq);
gsc_fixup_irqs(dev, lasi, lasi_choose_irq);
/* initialize the power off function */
/* FIXME: Record the LASI HPA for the power off function. This should
......
......@@ -41,11 +41,9 @@
#include <linux/smp_lock.h>
#include <asm/byteorder.h>
#include <asm/irq.h> /* for struct irq_region support */
#include <asm/pdc.h>
#include <asm/pdcpat.h>
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/hardware.h> /* for register_parisc_driver() stuff */
......
......@@ -72,7 +72,6 @@
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/superio.h>
static struct superio_device sio_dev;
......@@ -87,9 +86,8 @@ static struct superio_device sio_dev;
#endif
static irqreturn_t
superio_interrupt(int irq, void *devp, struct pt_regs *regs)
superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
{
struct superio_device *sio = (struct superio_device *)devp;
u8 results;
u8 local_irq;
......@@ -108,7 +106,7 @@ superio_interrupt(int irq, void *devp, struct pt_regs *regs)
* We don't know if an interrupt was/is pending and thus
* just call the handler for that IRQ as if it were pending.
*/
return IRQ_HANDLED;
return IRQ_NONE;
}
/* Check to see which device is interrupting */
......@@ -116,7 +114,6 @@ superio_interrupt(int irq, void *devp, struct pt_regs *regs)
if (local_irq == 2 || local_irq > 7) {
printk(KERN_ERR "SuperIO: slave interrupted!\n");
BUG();
return IRQ_HANDLED;
}
......@@ -133,9 +130,7 @@ superio_interrupt(int irq, void *devp, struct pt_regs *regs)
}
/* Call the appropriate device's interrupt */
do_irq(&sio->irq_region->action[local_irq],
sio->irq_region->data.irqbase + local_irq,
regs);
__do_IRQ(local_irq, regs);
/* set EOI - forces a new interrupt if a lower priority device
* still needs service.
......@@ -280,59 +275,53 @@ superio_init(struct superio_device *sio)
}
static void
superio_disable_irq(void *dev, int local_irq)
static void superio_disable_irq(unsigned int irq)
{
u8 r8;
if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
printk(KERN_ERR "SuperIO: Illegal irq number.\n");
BUG();
return;
if ((irq < 1) || (irq == 2) || (irq > 7)) {
printk(KERN_ERR "SuperIO: Illegal irq number.\n");
BUG();
return;
}
/* Mask interrupt */
r8 = inb(IC_PIC1+1);
r8 |= (1 << local_irq);
r8 |= (1 << irq);
outb (r8,IC_PIC1+1);
}
static void
superio_enable_irq(void *dev, int local_irq)
static void superio_enable_irq(unsigned int irq)
{
u8 r8;
if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
printk(KERN_ERR "SuperIO: Illegal irq number (%d).\n", local_irq);
BUG();
return;
if ((irq < 1) || (irq == 2) || (irq > 7)) {
printk(KERN_ERR "SuperIO: Illegal irq number (%d).\n", irq);
BUG();
return;
}
/* Unmask interrupt */
r8 = inb(IC_PIC1+1);
r8 &= ~(1 << local_irq);
r8 &= ~(1 << irq);
outb (r8,IC_PIC1+1);
}
static void
superio_mask_irq(void *dev, int local_irq)
{
BUG();
}
static void
superio_unmask_irq(void *dev, int local_irq)
static unsigned int superio_startup_irq(unsigned int irq)
{
BUG();
superio_enable_irq(irq);
return 0;
}
static struct irq_region_ops superio_irq_ops = {
.disable_irq = superio_disable_irq,
.enable_irq = superio_enable_irq,
.mask_irq = superio_mask_irq,
.unmask_irq = superio_unmask_irq
static struct hw_interrupt_type superio_interrupt_type = {
.typename = "SuperIO",
.startup = superio_startup_irq,
.shutdown = superio_disable_irq,
.enable = superio_enable_irq,
.disable = superio_disable_irq,
.ack = no_ack_irq,
.end = no_end_irq,
};
#ifdef DEBUG_SUPERIO_INIT
......@@ -345,7 +334,7 @@ static unsigned short expected_device[3] = {
int superio_fixup_irq(struct pci_dev *pcidev)
{
int local_irq;
int local_irq, i;
#ifdef DEBUG_SUPERIO_INIT
int fn;
......@@ -362,15 +351,8 @@ int superio_fixup_irq(struct pci_dev *pcidev)
__builtin_return_address(0));
#endif
if (!sio_dev.irq_region) {
/* Allocate an irq region for SuperIO devices */
sio_dev.irq_region = alloc_irq_region(SUPERIO_NIRQS,
&superio_irq_ops,
"SuperIO", (void *) &sio_dev);
if (!sio_dev.irq_region) {
printk(KERN_WARNING "SuperIO: alloc_irq_region failed\n");
return -1;
}
for (i = 0; i < 16; i++) {
irq_desc[i].handler = &superio_interrupt_type;
}
/*
......@@ -396,7 +378,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
break;
}
return(sio_dev.irq_region->data.irqbase + local_irq);
return local_irq;
}
static struct uart_port serial[] = {
......@@ -416,25 +398,13 @@ static struct uart_port serial[] = {
}
};
void __devinit
superio_serial_init(void)
static void __devinit superio_serial_init(void)
{
#ifdef CONFIG_SERIAL_8250
int retval;
#ifdef CONFIG_SERIAL_8250_CONSOLE
extern void serial8250_console_init(void); /* drivers/serial/8250.c */
#endif
if (!sio_dev.irq_region)
return; /* superio not present */
if (!serial) {
printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.\n");
return;
}
serial[0].iobase = sio_dev.sp1_base;
serial[0].irq = sio_dev.irq_region->data.irqbase + SP1_IRQ;
serial[0].irq = SP1_IRQ;
retval = early_serial_setup(&serial[0]);
if (retval < 0) {
......@@ -442,12 +412,8 @@ superio_serial_init(void)
return;
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
serial8250_console_init();
#endif
serial[1].iobase = sio_dev.sp2_base;
serial[1].irq = sio_dev.irq_region->data.irqbase + SP2_IRQ;
serial[1].irq = SP2_IRQ;
retval = early_serial_setup(&serial[1]);
if (retval < 0)
......@@ -456,13 +422,12 @@ superio_serial_init(void)
}
static void __devinit
superio_parport_init(void)
static void __devinit superio_parport_init(void)
{
#ifdef CONFIG_PARPORT_PC
if (!parport_pc_probe_port(sio_dev.pp_base,
0 /*base_hi*/,
sio_dev.irq_region->data.irqbase + PAR_IRQ,
PAR_IRQ,
PARPORT_DMA_NONE /* dma */,
NULL /*struct pci_dev* */) )
......@@ -471,7 +436,7 @@ superio_parport_init(void)
}
void superio_fixup_pci(struct pci_dev *pdev)
static void superio_fixup_pci(struct pci_dev *pdev)
{
u8 prog;
......
......@@ -21,28 +21,28 @@
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include "gsc.h"
#define WAX_GSC_IRQ 7 /* Hardcoded Interrupt for GSC */
#define WAX_GSC_NMI_IRQ 29
static int wax_choose_irq(struct parisc_device *dev)
static void wax_choose_irq(struct parisc_device *dev, void *ctrl)
{
int irq = -1;
int irq;
switch (dev->id.sversion) {
case 0x73: irq = 30; break; /* HIL */
case 0x8c: irq = 25; break; /* RS232 */
case 0x90: irq = 21; break; /* WAX EISA BA */
case 0x73: irq = 1; break; /* HIL */
case 0x8c: irq = 6; break; /* RS232 */
case 0x90: irq = 10; break; /* WAX EISA BA */
default: return; /* Unknown */
}
return irq;
gsc_asic_assign_irq(ctrl, irq, &dev->irq);
}
static void __init
wax_init_irq(struct busdevice *wax)
wax_init_irq(struct gsc_asic *wax)
{
unsigned long base = wax->hpa;
......@@ -50,7 +50,7 @@ wax_init_irq(struct busdevice *wax)
gsc_writel(0x00000000, base+OFFSET_IMR);
/* clear pending interrupts */
(volatile u32) gsc_readl(base+OFFSET_IRR);
gsc_readl(base+OFFSET_IRR);
/* We're not really convinced we want to reset the onboard
* devices. Firmware does it for us...
......@@ -69,11 +69,12 @@ wax_init_irq(struct busdevice *wax)
int __init
wax_init_chip(struct parisc_device *dev)
{
struct busdevice *wax;
struct gsc_asic *wax;
struct parisc_device *parent;
struct gsc_irq gsc_irq;
int irq, ret;
int ret;
wax = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
wax = kmalloc(sizeof(*wax), GFP_KERNEL);
if (!wax)
return -ENOMEM;
......@@ -87,40 +88,37 @@ wax_init_chip(struct parisc_device *dev)
wax_init_irq(wax);
/* the IRQ wax should use */
irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
if (irq < 0) {
dev->irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
if (dev->irq < 0) {
printk(KERN_ERR "%s(): cannot get GSC irq\n",
__FUNCTION__);
kfree(wax);
return -EBUSY;
}
ret = request_irq(gsc_irq.irq, busdev_barked, 0, "wax", wax);
wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
if (ret < 0) {
kfree(wax);
return ret;
}
/* Save this for debugging later */
wax->parent_irq = gsc_irq.irq;
wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
/* enable IRQ's for devices below WAX */
gsc_writel(wax->eim, wax->hpa + OFFSET_IAR);
/* Done init'ing, register this driver */
ret = gsc_common_irqsetup(dev, wax);
ret = gsc_common_setup(dev, wax);
if (ret) {
kfree(wax);
return ret;
}
fixup_child_irqs(dev, wax->busdev_region->data.irqbase,
wax_choose_irq);
gsc_fixup_irqs(dev, wax, wax_choose_irq);
/* On 715-class machines, Wax EISA is a sibling of Wax, not a child. */
if (dev->parent->id.hw_type != HPHW_IOA) {
fixup_child_irqs(dev->parent, wax->busdev_region->data.irqbase,
wax_choose_irq);
parent = parisc_parent(dev);
if (parent->id.hw_type != HPHW_IOA) {
gsc_fixup_irqs(parent, wax, wax_choose_irq);
}
return ret;
......
......@@ -18,6 +18,7 @@
#include <linux/config.h>
#include <linux/threads.h>
#include <linux/cache.h>
#include <linux/irq.h>
typedef struct {
unsigned long __softirq_pending; /* set_bit is used on this */
......@@ -28,11 +29,13 @@ typedef struct {
#define HARDIRQ_BITS 16
/*
* The hardirq mask has to be large enough to have space for potentially all IRQ sources
* in the system nesting on a single CPU:
* The hardirq mask has to be large enough to have space for potentially all
* IRQ sources in the system nesting on a single CPU:
*/
#if (1 << HARDIRQ_BITS) < NR_IRQS
# error HARDIRQ_BITS is too low!
#endif
void ack_bad_irq(unsigned int irq);
#endif /* _PARISC_HARDIRQ_H */
......@@ -12,6 +12,6 @@
* <tomsoft@informatik.tu-chemnitz.de>
*/
#include <asm/irq.h>
extern void hw_resend_irq(struct hw_interrupt_type *, unsigned int);
#endif
/*
* linux/include/asm-parisc/irq.h
* include/asm-parisc/irq.h
*
* (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar,
* Copyright 1999 SuSE GmbH
*
* IRQ/IPI changes taken from work by Thomas Radke
* <tomsoft@informatik.tu-chemnitz.de>
* Copyright 2005 Matthew Wilcox <matthew@wil.cx>
*/
#ifndef _ASM_PARISC_IRQ_H
#define _ASM_PARISC_IRQ_H
#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/errno.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <asm/types.h>
#define NO_IRQ (-1)
#define CPU_IRQ_REGION 1
#define TIMER_IRQ (IRQ_FROM_REGION(CPU_IRQ_REGION) | 0)
#define IPI_IRQ (IRQ_FROM_REGION(CPU_IRQ_REGION) | 1)
/* This should be 31 for PA1.1 binaries and 63 for PA-2.0 wide mode */
#define MAX_CPU_IRQ (BITS_PER_LONG - 1)
#if BITS_PER_LONG == 32
# define IRQ_REGION_SHIFT 5
#ifdef CONFIG_GSC
#define GSC_IRQ_BASE 16
#define GSC_IRQ_MAX 63
#define CPU_IRQ_BASE 64
#else
# define IRQ_REGION_SHIFT 6
#define CPU_IRQ_BASE 16
#endif
#define IRQ_PER_REGION (1 << IRQ_REGION_SHIFT)
#define NR_IRQ_REGS 16
#define NR_IRQS (NR_IRQ_REGS * IRQ_PER_REGION)
#define IRQ_REGION(irq) ((irq) >> IRQ_REGION_SHIFT)
#define IRQ_OFFSET(irq) ((irq) & ((1<<IRQ_REGION_SHIFT)-1))
#define IRQ_FROM_REGION(reg) ((reg) << IRQ_REGION_SHIFT)
#define EISA_IRQ_REGION 0 /* region 0 needs to be reserved for EISA */
#define EISA_MAX_IRQS 16 /* max. (E)ISA irq line */
struct irq_region_ops {
void (*disable_irq)(void *dev, int irq);
void (* enable_irq)(void *dev, int irq);
void (* mask_irq)(void *dev, int irq);
void (* unmask_irq)(void *dev, int irq);
};
struct irq_region_data {
void *dev;
const char *name;
int irqbase;
unsigned int status[IRQ_PER_REGION]; /* IRQ status */
};
#define TIMER_IRQ (CPU_IRQ_BASE + 0)
#define IPI_IRQ (CPU_IRQ_BASE + 1)
#define CPU_IRQ_MAX (CPU_IRQ_BASE + (BITS_PER_LONG - 1))
struct irq_region {
struct irq_region_ops ops;
struct irq_region_data data;
struct irqaction *action;
};
extern struct irq_region *irq_region[NR_IRQ_REGS];
#define NR_IRQS (CPU_IRQ_MAX + 1)
static __inline__ int irq_canonicalize(int irq)
{
#ifdef CONFIG_EISA
return (irq == (IRQ_FROM_REGION(EISA_IRQ_REGION)+2)
? (IRQ_FROM_REGION(EISA_IRQ_REGION)+9) : irq);
#else
return irq;
#endif
return (irq == 2) ? 9 : irq;
}
extern void disable_irq(int);
#define disable_irq_nosync(i) disable_irq(i)
extern void enable_irq(int);
extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
extern void do_irq_mask(unsigned long mask, struct irq_region *region,
struct pt_regs *regs);
struct hw_interrupt_type;
extern struct irq_region *alloc_irq_region(int count, struct irq_region_ops *ops,
const char *name, void *dev);
/*
* Some useful "we don't have to do anything here" handlers. Should
* probably be provided by the generic code.
*/
void no_ack_irq(unsigned int irq);
void no_end_irq(unsigned int irq);
extern int txn_alloc_irq(void);
extern int txn_claim_irq(int);
extern unsigned int txn_alloc_data(int, unsigned int);
extern unsigned long txn_alloc_addr(int);
extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
/* soft power switch support (power.c) */
extern struct tasklet_struct power_tasklet;
struct irqaction;
int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
#endif /* _ASM_PARISC_IRQ_H */
......@@ -56,7 +56,6 @@ struct superio_device {
u32 pp_base;
u32 acpi_base;
int suckyio_irq_enabled;
struct irq_region *irq_region;
struct pci_dev *lio_pdev; /* pci device for legacy IO (fn 1) */
struct pci_dev *usb_pdev; /* pci device for USB (fn 2) */
};
......@@ -81,11 +80,6 @@ struct superio_device {
|| ((x)->device == PCI_DEVICE_ID_NS_87560_LIO) \
|| ((x)->device == PCI_DEVICE_ID_NS_87560_USB) ) )
struct hwif_s;
extern void superio_inform_irq(int irq);
extern void superio_serial_init(void); /* called by rs_init() */
extern int superio_fixup_irq(struct pci_dev *pcidev); /* called by iosapic */
extern void superio_fixup_pci(struct pci_dev *pdev);
#endif /* _PARISC_SUPERIO_H */
......@@ -59,9 +59,10 @@ typedef struct hw_interrupt_type hw_irq_controller;
* Pad this out to 32 bytes for cache and indexing reasons.
*/
typedef struct irq_desc {
unsigned int status; /* IRQ status */
hw_irq_controller *handler;
void *handler_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */
unsigned int depth; /* nested irq disables */
unsigned int irq_count; /* For detecting broken interrupts */
unsigned int irqs_unhandled;
......
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