Skip to content

Commit

Permalink
m68k/mac: Optimize interrupts using chain handlers
Browse files Browse the repository at this point in the history
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
  • Loading branch information
Geert Uytterhoeven committed Nov 8, 2011
1 parent ddc7fd2 commit 9145db5
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 63 deletions.
38 changes: 38 additions & 0 deletions arch/m68k/mac/baboon.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,39 @@ void __init baboon_init(void)
* Baboon interrupt handler. This works a lot like a VIA.
*/

#ifdef CONFIG_GENERIC_HARDIRQS
static void baboon_irq(unsigned int irq, struct irq_desc *desc)
{
int irq_bit, irq_num;
unsigned char events;

#ifdef DEBUG_IRQS
printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n",
(uint) baboon->mb_control, (uint) baboon->mb_ifr,
(uint) baboon->mb_status);
#endif

events = baboon->mb_ifr & 0x07;
if (!events)
return;

irq_num = IRQ_BABOON_0;
irq_bit = 1;
do {
if (events & irq_bit) {
baboon->mb_ifr &= ~irq_bit;
generic_handle_irq(irq_num);
}
irq_bit <<= 1;
irq_num++;
} while(events >= irq_bit);
#if 0
if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL);
/* for now we need to smash all interrupts */
baboon->mb_ifr &= ~events;
#endif
}
#else
static irqreturn_t baboon_irq(int irq, void *dev_id)
{
int irq_bit, irq_num;
Expand Down Expand Up @@ -87,6 +120,7 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
#endif
return IRQ_HANDLED;
}
#endif

/*
* Register the Baboon interrupt dispatcher on nubus slot $C.
Expand All @@ -95,8 +129,12 @@ static irqreturn_t baboon_irq(int irq, void *dev_id)
void __init baboon_register_interrupts(void)
{
baboon_disabled = 0;
#ifdef CONFIG_GENERIC_HARDIRQS
irq_set_chained_handler(IRQ_NUBUS_C, baboon_irq);
#else
if (request_irq(IRQ_NUBUS_C, baboon_irq, 0, "baboon", (void *)baboon))
pr_err("Couldn't register baboon interrupt\n");
#endif
}

/*
Expand Down
106 changes: 86 additions & 20 deletions arch/m68k/mac/oss.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@
int oss_present;
volatile struct mac_oss *oss;

static irqreturn_t oss_irq(int, void *);
static irqreturn_t oss_nubus_irq(int, void *);

#ifdef CONFIG_GENERIC_HARDIRQS
extern void via1_irq(unsigned int irq, struct irq_desc *desc);
#else
extern irqreturn_t via1_irq(int, void *);
#endif

/*
* Initialize the OSS
Expand All @@ -62,23 +63,6 @@ void __init oss_init(void)
oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1;
}

/*
* Register the OSS and NuBus interrupt dispatchers.
*/

void __init oss_register_interrupts(void)
{
if (request_irq(OSS_IRQLEV_SCSI, oss_irq, 0, "scsi", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "scsi");
if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, 0, "nubus",
(void *)oss))
pr_err("Couldn't register %s interrupt\n", "nubus");
if (request_irq(OSS_IRQLEV_SOUND, oss_irq, 0, "sound", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "sound");
if (request_irq(OSS_IRQLEV_VIA1, via1_irq, 0, "via1", (void *)via1))
pr_err("Couldn't register %s interrupt\n", "via1");
}

/*
* Initialize OSS for Nubus access
*/
Expand All @@ -92,6 +76,34 @@ void __init oss_nubus_init(void)
* and SCSI; everything else is routed to its own autovector IRQ.
*/

#ifdef CONFIG_GENERIC_HARDIRQS
static void oss_irq(unsigned int irq, struct irq_desc *desc)
{
int events;

events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
if (!events)
return;

#ifdef DEBUG_IRQS
if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
printk("oss_irq: irq %u events = 0x%04X\n", irq,
(int) oss->irq_pending);
}
#endif
/* FIXME: how do you clear a pending IRQ? */

if (events & OSS_IP_SOUND) {
oss->irq_pending &= ~OSS_IP_SOUND;
/* FIXME: call sound handler */
} else if (events & OSS_IP_SCSI) {
oss->irq_pending &= ~OSS_IP_SCSI;
generic_handle_irq(IRQ_MAC_SCSI);
} else {
/* FIXME: error check here? */
}
}
#else
static irqreturn_t oss_irq(int irq, void *dev_id)
{
int events;
Expand Down Expand Up @@ -119,13 +131,42 @@ static irqreturn_t oss_irq(int irq, void *dev_id)
}
return IRQ_HANDLED;
}
#endif

/*
* Nubus IRQ handler, OSS style
*
* Unlike the VIA/RBV this is on its own autovector interrupt level.
*/

#ifdef CONFIG_GENERIC_HARDIRQS
static void oss_nubus_irq(unsigned int irq, struct irq_desc *desc)
{
int events, irq_bit, i;

events = oss->irq_pending & OSS_IP_NUBUS;
if (!events)
return;

#ifdef DEBUG_NUBUS_INT
if (console_loglevel > 7) {
printk("oss_nubus_irq: events = 0x%04X\n", events);
}
#endif
/* There are only six slots on the OSS, not seven */

i = 6;
irq_bit = 0x40;
do {
--i;
irq_bit >>= 1;
if (events & irq_bit) {
oss->irq_pending &= ~irq_bit;
generic_handle_irq(NUBUS_SOURCE_BASE + i);
}
} while(events & (irq_bit - 1));
}
#else
static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
{
int events, irq_bit, i;
Expand Down Expand Up @@ -153,6 +194,31 @@ static irqreturn_t oss_nubus_irq(int irq, void *dev_id)
} while(events & (irq_bit - 1));
return IRQ_HANDLED;
}
#endif

/*
* Register the OSS and NuBus interrupt dispatchers.
*/

void __init oss_register_interrupts(void)
{
#ifdef CONFIG_GENERIC_HARDIRQS
irq_set_chained_handler(OSS_IRQLEV_SCSI, oss_irq);
irq_set_chained_handler(OSS_IRQLEV_NUBUS, oss_nubus_irq);
irq_set_chained_handler(OSS_IRQLEV_SOUND, oss_irq);
irq_set_chained_handler(OSS_IRQLEV_VIA1, via1_irq);
#else /* !CONFIG_GENERIC_HARDIRQS */
if (request_irq(OSS_IRQLEV_SCSI, oss_irq, 0, "scsi", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "scsi");
if (request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, 0, "nubus",
(void *)oss))
pr_err("Couldn't register %s interrupt\n", "nubus");
if (request_irq(OSS_IRQLEV_SOUND, oss_irq, 0, "sound", (void *)oss))
pr_err("Couldn't register %s interrupt\n", "sound");
if (request_irq(OSS_IRQLEV_VIA1, via1_irq, 0, "via1", (void *)via1))
pr_err("Couldn't register %s interrupt\n", "via1");
#endif /* !CONFIG_GENERIC_HARDIRQS */
}

/*
* Enable an OSS interrupt
Expand Down
74 changes: 57 additions & 17 deletions arch/m68k/mac/psc.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
int psc_present;
volatile __u8 *psc;

irqreturn_t psc_irq(int, void *);

/*
* Debugging dump, used in various places to see what's going on.
*/
Expand Down Expand Up @@ -115,26 +113,40 @@ void __init psc_init(void)
}

/*
* Register the PSC interrupt dispatchers for autovector interrupts 3-6.
* PSC interrupt handler. It's a lot like the VIA interrupt handler.
*/

void __init psc_register_interrupts(void)
#ifdef CONFIG_GENERIC_HARDIRQS
static void psc_irq(unsigned int irq, struct irq_desc *desc)
{
if (request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30))
pr_err("Couldn't register psc%d interrupt\n", 3);
if (request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40))
pr_err("Couldn't register psc%d interrupt\n", 4);
if (request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50))
pr_err("Couldn't register psc%d interrupt\n", 5);
if (request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60))
pr_err("Couldn't register psc%d interrupt\n", 6);
}
unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc);
int pIFR = pIFRbase + offset;
int pIER = pIERbase + offset;
int irq_num;
unsigned char irq_bit, events;

/*
* PSC interrupt handler. It's a lot like the VIA interrupt handler.
*/
#ifdef DEBUG_IRQS
printk("psc_irq: irq %u pIFR = 0x%02X pIER = 0x%02X\n",
irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER));
#endif

irqreturn_t psc_irq(int irq, void *dev_id)
events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
if (!events)
return;

irq_num = irq << 3;
irq_bit = 1;
do {
if (events & irq_bit) {
psc_write_byte(pIFR, irq_bit);
generic_handle_irq(irq_num);
}
irq_num++;
irq_bit <<= 1;
} while (events >= irq_bit);
}
#else
static irqreturn_t psc_irq(int irq, void *dev_id)
{
int pIFR = pIFRbase + ((int) dev_id);
int pIER = pIERbase + ((int) dev_id);
Expand Down Expand Up @@ -162,6 +174,34 @@ irqreturn_t psc_irq(int irq, void *dev_id)
} while (events >= irq_bit);
return IRQ_HANDLED;
}
#endif

/*
* Register the PSC interrupt dispatchers for autovector interrupts 3-6.
*/

void __init psc_register_interrupts(void)
{
#ifdef CONFIG_GENERIC_HARDIRQS
irq_set_chained_handler(IRQ_AUTO_3, psc_irq);
irq_set_handler_data(IRQ_AUTO_3, (void *)0x30);
irq_set_chained_handler(IRQ_AUTO_4, psc_irq);
irq_set_handler_data(IRQ_AUTO_4, (void *)0x40);
irq_set_chained_handler(IRQ_AUTO_5, psc_irq);
irq_set_handler_data(IRQ_AUTO_5, (void *)0x50);
irq_set_chained_handler(IRQ_AUTO_6, psc_irq);
irq_set_handler_data(IRQ_AUTO_6, (void *)0x60);
#else /* !CONFIG_GENERIC_HARDIRQS */
if (request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30))
pr_err("Couldn't register psc%d interrupt\n", 3);
if (request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40))
pr_err("Couldn't register psc%d interrupt\n", 4);
if (request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50))
pr_err("Couldn't register psc%d interrupt\n", 5);
if (request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60))
pr_err("Couldn't register psc%d interrupt\n", 6);
#endif /* !CONFIG_GENERIC_HARDIRQS */
}

void psc_irq_enable(int irq) {
int irq_src = IRQ_SRC(irq);
Expand Down
Loading

0 comments on commit 9145db5

Please sign in to comment.