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
......
This diff is collapsed.
......@@ -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);
This diff is collapsed.
......@@ -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