On Tue, 17 Dec 2002, Jun Sun wrote: > > > No MIPS boards are using do_slow_gettimeoffset(). We really should get > > > rid of it. > > > > I know none does at the moment. But are you sure there is no system that > > would need it and might be supported one day? > > I serisouly don't think so. Moving forward every CPU will have a CPU counter, > which can be used for timeoffset purpose. Even if it does not have one, > it will surely have some onboard high resolution timer, which can be used > to intra-jiffy offset purpose. Well, I do hope so, too, but you'll never know until you find out. ;-) > > Here is an example (untested) code that I would recommend. It sends > > explicit ACKs to the i8259As, which has the following advantages: > > > <snip> > > Cool. This code works for me. Excellent. I worked on the code a bit more and removed the spurious IRQ stuff. It's not really necessary -- mask_and_ack_8259A() will deal with it anyway (a bit less precisely, but we don't care -- they are very rare and drivers absolutely have to be able to deal with spurious interrupts) and we want the low-level IRQ handling to be fast as it's performance critical. At this point the function became so compact it would be unreasonable not to make it inline -- the generated code is 24 instructions on my system. The positive side effect is the code won't be compiled for systems that don't use it. Following is a patch that I consider a candidate for submission. I changed the interface a bit to permit greater flexibility. I renamed the function to reflect the new semantic. Unless special handling is needed you may simply call: do_IRQ(poll_8259A_irq(), regs); > I studied it a little bit and I am convinced it is a better choice. > It should work for MIPS in general. Actually for any system that doesn't send hardware INTAs to i8259A PICs. > In my original code I did verify that the IRR bit is not cleared, > which apparently will be a problem in cases. The real problem is sources of edge-triggered interrupts need not deassert their IRQs until they want to trigger another interrupt. The i8254 is a notorius example. > The only catch with your code is that we don't have iob() macro (which > apparently is very useful). Any suggestions on this? Otherwise > I will probably remove it. iob() comes from <asm/system.h> -- do you miss it somehow? Unfortunately its drawback is it uses a memory clobber which for this specific example costs 4 unnecessary instructions (or 20%) to reread mips_io_port_base twice. The following patch was successfully tested at the run time on a Malta system (after replacing most of the junk from mips/mips-boards/malta/malta_int.c with the single-liner shown above). Apart from adding the function to ACK i8259A IRQs, it cleans up the i8259A stuff a bit: - private init_i8259_irqs() declarations scattered over the tree are removed and files referring to it now include <asm/i8259.h>, - declarations of obsolete, non-existent i8259A handling functions are removed. Note the i8259A_lock is now extern for poll_8259A_irq() but not declared in <asm/i8259.h> publicly as it shouldn't be used elsewhere. Ralf, is it OK to apply? Maciej -- + Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: macro@ds2.pg.gda.pl, PGP key available + patch-mips-2.4.20-pre6-20021212-poll-8259A-4 diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/cobalt/irq.c linux-mips-2.4.20-pre6-20021212/arch/mips/cobalt/irq.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/cobalt/irq.c 2002-12-04 03:56:24.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/cobalt/irq.c 2002-12-18 00:50:36.000000000 +0000 @@ -17,6 +17,7 @@ #include <linux/ioport.h> #include <asm/bootinfo.h> +#include <asm/i8259.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/mipsregs.h> diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/ddb5xxx/ddb5074/irq.c linux-mips-2.4.20-pre6-20021212/arch/mips/ddb5xxx/ddb5074/irq.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/ddb5xxx/ddb5074/irq.c 2002-08-06 02:57:07.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/ddb5xxx/ddb5074/irq.c 2002-12-18 00:54:16.000000000 +0000 @@ -12,6 +12,7 @@ #include <linux/interrupt.h> #include <linux/ioport.h> +#include <asm/i8259.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/irq_cpu.h> @@ -21,13 +22,7 @@ #include <asm/ddb5xxx/ddb5074.h> -extern void __init i8259_init(void); -extern void init_i8259_irqs (void); -extern void i8259_disable_irq(unsigned int irq_nr); -extern void i8259_enable_irq(unsigned int irq_nr); - extern asmlinkage void ddbIRQ(void); -extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL }; diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/ddb5xxx/ddb5476/irq.c linux-mips-2.4.20-pre6-20021212/arch/mips/ddb5xxx/ddb5476/irq.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/ddb5xxx/ddb5476/irq.c 2002-08-06 02:57:07.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/ddb5xxx/ddb5476/irq.c 2002-12-18 00:55:01.000000000 +0000 @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/interrupt.h> +#include <asm/i8259.h> #include <asm/io.h> #include <asm/ptrace.h> diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/ddb5xxx/ddb5477/irq.c linux-mips-2.4.20-pre6-20021212/arch/mips/ddb5xxx/ddb5477/irq.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/ddb5xxx/ddb5477/irq.c 2002-12-04 03:56:25.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/ddb5xxx/ddb5477/irq.c 2002-12-18 00:55:53.000000000 +0000 @@ -16,6 +16,7 @@ #include <linux/types.h> #include <linux/ptrace.h> +#include <asm/i8259.h> #include <asm/system.h> #include <asm/mipsregs.h> #include <asm/debug.h> @@ -71,7 +72,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 ddb_out32(pci, reg_value); } -extern void init_i8259_irqs (void); extern void vrc5477_irq_init(u32 base); extern void mips_cpu_irq_init(u32 base); extern asmlinkage void ddb5477_handle_int(void); diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/jazz/irq.c linux-mips-2.4.20-pre6-20021212/arch/mips/jazz/irq.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/jazz/irq.c 2001-12-18 05:27:34.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/jazz/irq.c 2002-12-18 00:56:22.000000000 +0000 @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/spinlock.h> +#include <asm/i8259.h> #include <asm/io.h> #include <asm/jazz.h> @@ -19,7 +20,7 @@ extern asmlinkage void jazz_handle_int(v /* * On systems with i8259-style interrupt controllers we assume for - * driver compatibility reasons interrupts 0 - 15 to be the i8295 + * driver compatibility reasons interrupts 0 - 15 to be the i8259 * interrupts even if the hardware uses a different interrupt numbering. */ void __init init_IRQ (void) diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/kernel/i8259.c linux-mips-2.4.20-pre6-20021212/arch/mips/kernel/i8259.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/kernel/i8259.c 2002-08-06 02:57:16.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/kernel/i8259.c 2002-12-17 23:18:16.000000000 +0000 @@ -29,7 +29,7 @@ void disable_8259A_irq(unsigned int irq) * moves to arch independent land */ -static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; +spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; static void end_8259A_irq (unsigned int irq) { diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/mips-boards/malta/malta_int.c linux-mips-2.4.20-pre6-20021212/arch/mips/mips-boards/malta/malta_int.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/mips-boards/malta/malta_int.c 2002-12-12 03:56:34.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/mips-boards/malta/malta_int.c 2002-12-18 00:57:12.000000000 +0000 @@ -29,6 +29,7 @@ #include <linux/kernel_stat.h> #include <linux/random.h> +#include <asm/i8259.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/mips-boards/malta.h> @@ -40,7 +41,6 @@ extern asmlinkage void mipsIRQ(void); extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); -extern void init_i8259_irqs (void); extern int mips_pcibios_iack(void); static spinlock_t mips_irq_lock = SPIN_LOCK_UNLOCKED; diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips/sni/irq.c linux-mips-2.4.20-pre6-20021212/arch/mips/sni/irq.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips/sni/irq.c 2001-12-18 05:27:36.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips/sni/irq.c 2002-12-18 00:58:13.000000000 +0000 @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/spinlock.h> +#include <asm/i8259.h> #include <asm/io.h> #include <asm/sni.h> diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/arch/mips64/kernel/i8259.c linux-mips-2.4.20-pre6-20021212/arch/mips64/kernel/i8259.c --- linux-mips-2.4.20-pre6-20021212.macro/arch/mips64/kernel/i8259.c 2002-08-06 02:57:35.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/arch/mips64/kernel/i8259.c 2002-12-18 01:03:29.000000000 +0000 @@ -29,7 +29,7 @@ void disable_8259A_irq(unsigned int irq) * moves to arch independent land */ -static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; +spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; static void end_8259A_irq (unsigned int irq) { diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips/i8259.h linux-mips-2.4.20-pre6-20021212/include/asm-mips/i8259.h --- linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips/i8259.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/include/asm-mips/i8259.h 2002-12-18 00:31:40.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * include/asm-mips/i8259.h + * + * i8259A interrupt definitions. + * + * Copyright (C) 2002 Maciej W. Rozycki + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef __ASM_MIPS_I8259_H +#define __ASM_MIPS_I8259_H + +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/system.h> + +extern void init_i8259_irqs(void); + +/* + * Ack an i8259A IRQ for systems that don't use hardware INTA cycles. + * + * Note we intentionally ignore the "I" (valid) bit reported by the + * controllers and pass spurious IRQs as real ones, since they are + * rare so the overhead is small and they will be handled later by + * mask_and_ack_8259A() anyway. + */ +static inline int poll_8259A_irq(void) +{ + extern spinlock_t i8259A_lock; + int irq; + + spin_lock(&i8259A_lock); + + outb(0x0c, 0x20); + iob(); + /* Ack the IRQ in the master. */ + irq = inb(0x20) & 7; + if (irq == 2) { + outb(0x0c, 0xa0); + iob(); + /* Ditto for the slave. */ + irq = (inb(0xa0) & 7) + 8; + } + + spin_unlock(&i8259A_lock); + + return irq; +} + +#endif /* __ASM_MIPS_I8259_H */ diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips/irq.h linux-mips-2.4.20-pre6-20021212/include/asm-mips/irq.h --- linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips/irq.h 2002-12-16 17:16:46.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/include/asm-mips/irq.h 2002-12-18 15:58:52.000000000 +0000 @@ -24,9 +24,6 @@ static inline int irq_cannonicalize(int #define irq_cannonicalize(irq) (irq) /* Sane hardware, sane code ... */ #endif -struct irqaction; -extern int i8259_setup_irq(int irq, struct irqaction * new); - extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips64/i8259.h linux-mips-2.4.20-pre6-20021212/include/asm-mips64/i8259.h --- linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips64/i8259.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/include/asm-mips64/i8259.h 2002-12-18 00:32:19.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * include/asm-mips/i8259.h + * + * i8259A interrupt definitions. + * + * Copyright (C) 2002 Maciej W. Rozycki + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef __ASM_MIPS64_I8259_H +#define __ASM_MIPS64_I8259_H + +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/system.h> + +extern void init_i8259_irqs(void); + +/* + * Ack an i8259A IRQ for systems that don't use hardware INTA cycles. + * + * Note we intentionally ignore the "I" (valid) bit reported by the + * controllers and pass spurious IRQs as real ones, since they are + * rare so the overhead is small and they will be handled later by + * mask_and_ack_8259A() anyway. + */ +static inline int poll_8259A_irq(void) +{ + extern spinlock_t i8259A_lock; + int irq; + + spin_lock(&i8259A_lock); + + outb(0x0c, 0x20); + iob(); + /* Ack the IRQ in the master. */ + irq = inb(0x20) & 7; + if (irq == 2) { + outb(0x0c, 0xa0); + iob(); + /* Ditto for the slave. */ + irq = (inb(0xa0) & 7) + 8; + } + + spin_unlock(&i8259A_lock); + + return irq; +} + +#endif /* __ASM_MIPS64_I8259_H */ diff -up --recursive --new-file linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips64/irq.h linux-mips-2.4.20-pre6-20021212/include/asm-mips64/irq.h --- linux-mips-2.4.20-pre6-20021212.macro/include/asm-mips64/irq.h 2002-12-16 16:56:09.000000000 +0000 +++ linux-mips-2.4.20-pre6-20021212/include/asm-mips64/irq.h 2002-12-18 16:03:00.000000000 +0000 @@ -42,9 +42,6 @@ static inline int irq_cannonicalize(int #define irq_cannonicalize(irq) (irq) /* Sane hardware, sane code ... */ #endif -struct irqaction; -extern int i8259_setup_irq(int irq, struct irqaction * new); - extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int);