Index: linux-2.6.14/arch/mips/au1000/common/irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/au1000/common/irq.c +++ linux-2.6.14/arch/mips/au1000/common/irq.c @@ -253,47 +253,43 @@ void restore_local_and_enable(int contro static struct hw_interrupt_type rise_edge_irq_type = { - "Au1000 Rise Edge", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_rise_edge_irq, - end_irq, - NULL + .typename = "Au1000 Rise Edge", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_rise_edge_irq, + .end = end_irq, }; static struct hw_interrupt_type fall_edge_irq_type = { - "Au1000 Fall Edge", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_fall_edge_irq, - end_irq, - NULL + .typename = "Au1000 Fall Edge", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_fall_edge_irq, + .end = end_irq, }; static struct hw_interrupt_type either_edge_irq_type = { - "Au1000 Rise or Fall Edge", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_either_edge_irq, - end_irq, - NULL + .typename = "Au1000 Rise or Fall Edge", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_either_edge_irq, + .end = end_irq, }; static struct hw_interrupt_type level_irq_type = { - "Au1000 Level", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_level_irq, - end_irq, - NULL + .typename = "Au1000 Level", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_level_irq, + .end = end_irq, }; #ifdef CONFIG_PM Index: linux-2.6.14/arch/mips/ddb5xxx/ddb5074/nile4_pic.c =================================================================== --- linux-2.6.14.orig/arch/mips/ddb5xxx/ddb5074/nile4_pic.c +++ linux-2.6.14/arch/mips/ddb5xxx/ddb5074/nile4_pic.c @@ -209,14 +209,13 @@ static void nile4_irq_end(unsigned int i #define nile4_irq_shutdown nile4_disable_irq static hw_irq_controller nile4_irq_controller = { - "nile4", - nile4_irq_startup, - nile4_irq_shutdown, - nile4_enable_irq, - nile4_disable_irq, - nile4_ack_irq, - nile4_irq_end, - NULL + .typename = "nile4", + .startup = nile4_irq_startup, + .shutdown = nile4_irq_shutdown, + .enable = nile4_enable_irq, + .disable = nile4_disable_irq, + .ack = nile4_ack_irq, + .end = nile4_irq_end, }; void nile4_irq_setup(u32 base) { Index: linux-2.6.14/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c +++ linux-2.6.14/arch/mips/ddb5xxx/ddb5476/vrc5476_irq.c @@ -53,14 +53,13 @@ static void vrc5476_irq_end(uint irq) } static hw_irq_controller vrc5476_irq_controller = { - "vrc5476", - vrc5476_irq_startup, - vrc5476_irq_shutdown, - vrc5476_irq_enable, - vrc5476_irq_disable, - vrc5476_irq_ack, - vrc5476_irq_end, - NULL /* no affinity stuff for UP */ + .typename = "vrc5476", + .startup = vrc5476_irq_startup, + .shutdown = vrc5476_irq_shutdown, + .enable = vrc5476_irq_enable, + .disable = vrc5476_irq_disable, + .ack = vrc5476_irq_ack, + .end = vrc5476_irq_end }; void __init Index: linux-2.6.14/arch/mips/ddb5xxx/ddb5477/irq_5477.c =================================================================== --- linux-2.6.14.orig/arch/mips/ddb5xxx/ddb5477/irq_5477.c +++ linux-2.6.14/arch/mips/ddb5xxx/ddb5477/irq_5477.c @@ -90,14 +90,13 @@ vrc5477_irq_end(unsigned int irq) } hw_irq_controller vrc5477_irq_controller = { - "vrc5477_irq", - vrc5477_irq_startup, - vrc5477_irq_shutdown, - vrc5477_irq_enable, - vrc5477_irq_disable, - vrc5477_irq_ack, - vrc5477_irq_end, - NULL /* no affinity stuff for UP */ + .typename = "vrc5477_irq", + .startup = vrc5477_irq_startup, + .shutdown = vrc5477_irq_shutdown, + .enable = vrc5477_irq_enable, + .disable = vrc5477_irq_disable, + .ack = vrc5477_irq_ack, + .end = vrc5477_irq_end }; void __init vrc5477_irq_init(u32 irq_base) Index: linux-2.6.14/arch/mips/ite-boards/generic/irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/ite-boards/generic/irq.c +++ linux-2.6.14/arch/mips/ite-boards/generic/irq.c @@ -138,14 +138,13 @@ static void end_ite_irq(unsigned int irq } static struct hw_interrupt_type it8172_irq_type = { - "ITE8172", - startup_ite_irq, - shutdown_ite_irq, - enable_it8172_irq, - disable_it8172_irq, - mask_and_ack_ite_irq, - end_ite_irq, - NULL + .typename = "ITE8172", + .startup = startup_ite_irq, + .shutdown = shutdown_ite_irq, + .enable = enable_it8172_irq, + .disable = disable_it8172_irq, + .ack = mask_and_ack_ite_irq, + .end = end_ite_irq, }; @@ -159,13 +158,13 @@ static void ack_none(unsigned int irq) { #define end_none enable_none static struct hw_interrupt_type cp0_irq_type = { - "CP0 Count", - startup_none, - shutdown_none, - enable_none, - disable_none, - ack_none, - end_none + .typename = "CP0 Count", + .startup = startup_none, + .shutdown = shutdown_none, + .enable = enable_none, + .disable = disable_none, + .ack = ack_none, + .end = end_none }; void enable_cpu_timer(void) Index: linux-2.6.14/arch/mips/jazz/irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/jazz/irq.c +++ linux-2.6.14/arch/mips/jazz/irq.c @@ -58,14 +58,13 @@ static void end_r4030_irq(unsigned int i } static struct hw_interrupt_type r4030_irq_type = { - "R4030", - startup_r4030_irq, - shutdown_r4030_irq, - enable_r4030_irq, - disable_r4030_irq, - mask_and_ack_r4030_irq, - end_r4030_irq, - NULL + .typename = "R4030", + .startup = startup_r4030_irq, + .shutdown = shutdown_r4030_irq, + .enable = enable_r4030_irq, + .disable = disable_r4030_irq, + .ack = mask_and_ack_r4030_irq, + .end = end_r4030_irq, }; void __init init_r4030_ints(void) Index: linux-2.6.14/arch/mips/jmr3927/rbhma3100/irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/jmr3927/rbhma3100/irq.c +++ linux-2.6.14/arch/mips/jmr3927/rbhma3100/irq.c @@ -412,13 +412,13 @@ void __init arch_init_irq(void) } static hw_irq_controller jmr3927_irq_controller = { - "jmr3927_irq", - jmr3927_irq_startup, - jmr3927_irq_shutdown, - jmr3927_irq_enable, - jmr3927_irq_disable, - jmr3927_irq_ack, - jmr3927_irq_end, + .typename = "jmr3927_irq", + .startup = jmr3927_irq_startup, + .shutdown = jmr3927_irq_shutdown, + .enable = jmr3927_irq_enable, + .disable = jmr3927_irq_disable, + .ack = jmr3927_irq_ack, + .end = jmr3927_irq_end, }; void jmr3927_irq_init(u32 irq_base) Index: linux-2.6.14/arch/mips/kernel/i8259.c =================================================================== --- linux-2.6.14.orig/arch/mips/kernel/i8259.c +++ linux-2.6.14/arch/mips/kernel/i8259.c @@ -52,14 +52,13 @@ static unsigned int startup_8259A_irq(un } static struct hw_interrupt_type i8259A_irq_type = { - "XT-PIC", - startup_8259A_irq, - shutdown_8259A_irq, - enable_8259A_irq, - disable_8259A_irq, - mask_and_ack_8259A, - end_8259A_irq, - NULL + .typename = "XT-PIC", + .startup = startup_8259A_irq, + .shutdown = shutdown_8259A_irq, + .enable = enable_8259A_irq, + .disable = disable_8259A_irq, + .ack = mask_and_ack_8259A, + .end = end_8259A_irq, }; /* Index: linux-2.6.14/arch/mips/kernel/irq-msc01.c =================================================================== --- linux-2.6.14.orig/arch/mips/kernel/irq-msc01.c +++ linux-2.6.14/arch/mips/kernel/irq-msc01.c @@ -129,25 +129,23 @@ msc_bind_eic_interrupt (unsigned int irq #define shutdown_msc_irq disable_msc_irq struct hw_interrupt_type msc_levelirq_type = { - "SOC-it-Level", - startup_msc_irq, - shutdown_msc_irq, - enable_msc_irq, - disable_msc_irq, - level_mask_and_ack_msc_irq, - end_msc_irq, - NULL + .typename = "SOC-it-Level", + .startup = startup_msc_irq, + .shutdown = shutdown_msc_irq, + .enable = enable_msc_irq, + .disable = disable_msc_irq, + .ack = level_mask_and_ack_msc_irq, + .end = end_msc_irq, }; struct hw_interrupt_type msc_edgeirq_type = { - "SOC-it-Edge", - startup_msc_irq, - shutdown_msc_irq, - enable_msc_irq, - disable_msc_irq, - edge_mask_and_ack_msc_irq, - end_msc_irq, - NULL + .typename = "SOC-it-Edge", + .startup =startup_msc_irq, + .shutdown = shutdown_msc_irq, + .enable = enable_msc_irq, + .disable = disable_msc_irq, + .ack = edge_mask_and_ack_msc_irq, + .end = end_msc_irq, }; Index: linux-2.6.14/arch/mips/kernel/irq-mv6434x.c =================================================================== --- linux-2.6.14.orig/arch/mips/kernel/irq-mv6434x.c +++ linux-2.6.14/arch/mips/kernel/irq-mv6434x.c @@ -135,14 +135,13 @@ void ll_mv64340_irq(struct pt_regs *regs #define shutdown_mv64340_irq disable_mv64340_irq struct hw_interrupt_type mv64340_irq_type = { - "MV-64340", - startup_mv64340_irq, - shutdown_mv64340_irq, - enable_mv64340_irq, - disable_mv64340_irq, - mask_and_ack_mv64340_irq, - end_mv64340_irq, - NULL + .typename = "MV-64340", + .startup = startup_mv64340_irq, + .shutdown = shutdown_mv64340_irq, + .enable = enable_mv64340_irq, + .disable = disable_mv64340_irq, + .ack = mask_and_ack_mv64340_irq, + .end = end_mv64340_irq, }; void __init mv64340_irq_init(unsigned int base) Index: linux-2.6.14/arch/mips/kernel/irq-rm7000.c =================================================================== --- linux-2.6.14.orig/arch/mips/kernel/irq-rm7000.c +++ linux-2.6.14/arch/mips/kernel/irq-rm7000.c @@ -72,13 +72,13 @@ static void rm7k_cpu_irq_end(unsigned in } static hw_irq_controller rm7k_irq_controller = { - "RM7000", - rm7k_cpu_irq_startup, - rm7k_cpu_irq_shutdown, - rm7k_cpu_irq_enable, - rm7k_cpu_irq_disable, - rm7k_cpu_irq_ack, - rm7k_cpu_irq_end, + .typename = "RM7000", + .startup = rm7k_cpu_irq_startup, + .shutdown = rm7k_cpu_irq_shutdown, + .enable = rm7k_cpu_irq_enable, + .disable = rm7k_cpu_irq_disable, + .ack = rm7k_cpu_irq_ack, + .end = rm7k_cpu_irq_end, }; void __init rm7k_cpu_irq_init(int base) Index: linux-2.6.14/arch/mips/kernel/irq-rm9000.c =================================================================== --- linux-2.6.14.orig/arch/mips/kernel/irq-rm9000.c +++ linux-2.6.14/arch/mips/kernel/irq-rm9000.c @@ -106,23 +106,23 @@ static void rm9k_cpu_irq_end(unsigned in } static hw_irq_controller rm9k_irq_controller = { - "RM9000", - rm9k_cpu_irq_startup, - rm9k_cpu_irq_shutdown, - rm9k_cpu_irq_enable, - rm9k_cpu_irq_disable, - rm9k_cpu_irq_ack, - rm9k_cpu_irq_end, + .typename = "RM9000", + .startup = rm9k_cpu_irq_startup, + .shutdown = rm9k_cpu_irq_shutdown, + .enable = rm9k_cpu_irq_enable, + .disable = rm9k_cpu_irq_disable, + .ack = rm9k_cpu_irq_ack, + .end = rm9k_cpu_irq_end, }; static hw_irq_controller rm9k_perfcounter_irq = { - "RM9000", - rm9k_perfcounter_irq_startup, - rm9k_perfcounter_irq_shutdown, - rm9k_cpu_irq_enable, - rm9k_cpu_irq_disable, - rm9k_cpu_irq_ack, - rm9k_cpu_irq_end, + .typename = "RM9000", + .startup = rm9k_perfcounter_irq_startup, + .shutdown = rm9k_perfcounter_irq_shutdown, + .enable = rm9k_cpu_irq_enable, + .disable = rm9k_cpu_irq_disable, + .ack = rm9k_cpu_irq_ack, + .end = rm9k_cpu_irq_end, }; unsigned int rm9000_perfcount_irq; Index: linux-2.6.14/arch/mips/kernel/irq_cpu.c =================================================================== --- linux-2.6.14.orig/arch/mips/kernel/irq_cpu.c +++ linux-2.6.14/arch/mips/kernel/irq_cpu.c @@ -92,14 +92,13 @@ static void mips_cpu_irq_end(unsigned in } static hw_irq_controller mips_cpu_irq_controller = { - "MIPS", - mips_cpu_irq_startup, - mips_cpu_irq_shutdown, - mips_cpu_irq_enable, - mips_cpu_irq_disable, - mips_cpu_irq_ack, - mips_cpu_irq_end, - NULL /* no affinity stuff for UP */ + .typename = "MIPS", + .startup = mips_cpu_irq_startup, + .shutdown = mips_cpu_irq_shutdown, + .enable = mips_cpu_irq_enable, + .disable = mips_cpu_irq_disable, + .ack = mips_cpu_irq_ack, + .end = mips_cpu_irq_end, }; Index: linux-2.6.14/arch/mips/lasat/interrupt.c =================================================================== --- linux-2.6.14.orig/arch/mips/lasat/interrupt.c +++ linux-2.6.14/arch/mips/lasat/interrupt.c @@ -71,14 +71,13 @@ static void end_lasat_irq(unsigned int i } static struct hw_interrupt_type lasat_irq_type = { - "Lasat", - startup_lasat_irq, - shutdown_lasat_irq, - enable_lasat_irq, - disable_lasat_irq, - mask_and_ack_lasat_irq, - end_lasat_irq, - NULL + .typename = "Lasat", + .startup = startup_lasat_irq, + .shutdown = shutdown_lasat_irq, + .enable = enable_lasat_irq, + .disable = disable_lasat_irq, + .ack = mask_and_ack_lasat_irq, + .end = end_lasat_irq, }; static inline int ls1bit32(unsigned int x) Index: linux-2.6.14/arch/mips/mips-boards/atlas/atlas_int.c =================================================================== --- linux-2.6.14.orig/arch/mips/mips-boards/atlas/atlas_int.c +++ linux-2.6.14/arch/mips/mips-boards/atlas/atlas_int.c @@ -76,14 +76,13 @@ static void end_atlas_irq(unsigned int i } static struct hw_interrupt_type atlas_irq_type = { - "Atlas", - startup_atlas_irq, - shutdown_atlas_irq, - enable_atlas_irq, - disable_atlas_irq, - mask_and_ack_atlas_irq, - end_atlas_irq, - NULL + .typename = "Atlas", + .startup = startup_atlas_irq, + .shutdown = shutdown_atlas_irq, + .enable = enable_atlas_irq, + .disable = disable_atlas_irq, + .ack = mask_and_ack_atlas_irq, + .end = end_atlas_irq, }; static inline int ls1bit32(unsigned int x) Index: linux-2.6.14/arch/mips/momentum/ocelot_c/cpci-irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/momentum/ocelot_c/cpci-irq.c +++ linux-2.6.14/arch/mips/momentum/ocelot_c/cpci-irq.c @@ -129,14 +129,13 @@ void ll_cpci_irq(struct pt_regs *regs) #define shutdown_cpci_irq disable_cpci_irq struct hw_interrupt_type cpci_irq_type = { - "CPCI/FPGA", - startup_cpci_irq, - shutdown_cpci_irq, - enable_cpci_irq, - disable_cpci_irq, - mask_and_ack_cpci_irq, - end_cpci_irq, - NULL + .typename = "CPCI/FPGA", + .startup = startup_cpci_irq, + .shutdown = shutdown_cpci_irq, + .enable = enable_cpci_irq, + .disable = disable_cpci_irq, + .ack = mask_and_ack_cpci_irq, + .end = end_cpci_irq, }; void cpci_irq_init(void) Index: linux-2.6.14/arch/mips/momentum/ocelot_c/uart-irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/momentum/ocelot_c/uart-irq.c +++ linux-2.6.14/arch/mips/momentum/ocelot_c/uart-irq.c @@ -122,14 +122,13 @@ void ll_uart_irq(struct pt_regs *regs) #define shutdown_uart_irq disable_uart_irq struct hw_interrupt_type uart_irq_type = { - "UART/FPGA", - startup_uart_irq, - shutdown_uart_irq, - enable_uart_irq, - disable_uart_irq, - mask_and_ack_uart_irq, - end_uart_irq, - NULL + .typename = "UART/FPGA", + .startup = startup_uart_irq, + .shutdown = shutdown_uart_irq, + .enable = enable_uart_irq, + .disable = disable_uart_irq, + .ack = mask_and_ack_uart_irq, + .end = end_uart_irq, }; void uart_irq_init(void) Index: linux-2.6.14/arch/mips/sgi-ip32/ip32-irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/sgi-ip32/ip32-irq.c +++ linux-2.6.14/arch/mips/sgi-ip32/ip32-irq.c @@ -163,14 +163,13 @@ static void end_cpu_irq(unsigned int irq #define mask_and_ack_cpu_irq disable_cpu_irq static struct hw_interrupt_type ip32_cpu_interrupt = { - "IP32 CPU", - startup_cpu_irq, - shutdown_cpu_irq, - enable_cpu_irq, - disable_cpu_irq, - mask_and_ack_cpu_irq, - end_cpu_irq, - NULL + .typename = "IP32 CPU", + .startup = startup_cpu_irq, + .shutdown = shutdown_cpu_irq, + .enable = enable_cpu_irq, + .disable = disable_cpu_irq, + .ack = mask_and_ack_cpu_irq, + .end = end_cpu_irq, }; /* @@ -234,14 +233,13 @@ static void end_crime_irq(unsigned int i #define shutdown_crime_irq disable_crime_irq static struct hw_interrupt_type ip32_crime_interrupt = { - "IP32 CRIME", - startup_crime_irq, - shutdown_crime_irq, - enable_crime_irq, - disable_crime_irq, - mask_and_ack_crime_irq, - end_crime_irq, - NULL + .typename = "IP32 CRIME", + .startup = startup_crime_irq, + .shutdown = shutdown_crime_irq, + .enable = enable_crime_irq, + .disable = disable_crime_irq, + .ack = mask_and_ack_crime_irq, + .end = end_crime_irq, }; /* @@ -294,14 +292,13 @@ static void end_macepci_irq(unsigned int #define mask_and_ack_macepci_irq disable_macepci_irq static struct hw_interrupt_type ip32_macepci_interrupt = { - "IP32 MACE PCI", - startup_macepci_irq, - shutdown_macepci_irq, - enable_macepci_irq, - disable_macepci_irq, - mask_and_ack_macepci_irq, - end_macepci_irq, - NULL + .typename = "IP32 MACE PCI", + .startup = startup_macepci_irq, + .shutdown = shutdown_macepci_irq, + .enable = enable_macepci_irq, + .disable = disable_macepci_irq, + .ack = mask_and_ack_macepci_irq, + .end = end_macepci_irq, }; /* This is used for MACE ISA interrupts. That means bits 4-6 in the @@ -425,14 +422,13 @@ static void end_maceisa_irq(unsigned irq #define shutdown_maceisa_irq disable_maceisa_irq static struct hw_interrupt_type ip32_maceisa_interrupt = { - "IP32 MACE ISA", - startup_maceisa_irq, - shutdown_maceisa_irq, - enable_maceisa_irq, - disable_maceisa_irq, - mask_and_ack_maceisa_irq, - end_maceisa_irq, - NULL + .typename = "IP32 MACE ISA", + .startup = startup_maceisa_irq, + .shutdown = shutdown_maceisa_irq, + .enable = enable_maceisa_irq, + .disable = disable_maceisa_irq, + .ack = mask_and_ack_maceisa_irq, + .end = end_maceisa_irq, }; /* This is used for regular non-ISA, non-PCI MACE interrupts. That means @@ -476,14 +472,13 @@ static void end_mace_irq(unsigned int ir #define mask_and_ack_mace_irq disable_mace_irq static struct hw_interrupt_type ip32_mace_interrupt = { - "IP32 MACE", - startup_mace_irq, - shutdown_mace_irq, - enable_mace_irq, - disable_mace_irq, - mask_and_ack_mace_irq, - end_mace_irq, - NULL + .typename = "IP32 MACE", + .startup = startup_mace_irq, + .shutdown = shutdown_mace_irq, + .enable = enable_mace_irq, + .disable = disable_mace_irq, + .ack = mask_and_ack_mace_irq, + .end = end_mace_irq, }; static void ip32_unknown_interrupt(struct pt_regs *regs) Index: linux-2.6.14/arch/mips/sibyte/sb1250/irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/sibyte/sb1250/irq.c +++ linux-2.6.14/arch/mips/sibyte/sb1250/irq.c @@ -71,17 +71,15 @@ extern char sb1250_duart_present[]; #endif static struct hw_interrupt_type sb1250_irq_type = { - "SB1250-IMR", - startup_sb1250_irq, - shutdown_sb1250_irq, - enable_sb1250_irq, - disable_sb1250_irq, - ack_sb1250_irq, - end_sb1250_irq, + .typename = "SB1250-IMR", + .startup = startup_sb1250_irq, + .shutdown = shutdown_sb1250_irq, + .enable = enable_sb1250_irq, + .disable = disable_sb1250_irq, + .ack = ack_sb1250_irq, + .end = end_sb1250_irq, #ifdef CONFIG_SMP - sb1250_set_affinity -#else - NULL + .set_affinity = sb1250_set_affinity #endif }; Index: linux-2.6.14/arch/mips/sni/irq.c =================================================================== --- linux-2.6.14.orig/arch/mips/sni/irq.c +++ linux-2.6.14/arch/mips/sni/irq.c @@ -58,14 +58,13 @@ static void end_pciasic_irq(unsigned int } static struct hw_interrupt_type pciasic_irq_type = { - "ASIC-PCI", - startup_pciasic_irq, - shutdown_pciasic_irq, - enable_pciasic_irq, - disable_pciasic_irq, - mask_and_ack_pciasic_irq, - end_pciasic_irq, - NULL + .typename = "ASIC-PCI", + .startup = startup_pciasic_irq, + .shutdown = shutdown_pciasic_irq, + .enable = enable_pciasic_irq, + .disable = disable_pciasic_irq, + .ack = mask_and_ack_pciasic_irq, + .end = end_pciasic_irq, }; /* Index: linux-2.6.14/Documentation/DocBook/Makefile =================================================================== --- linux-2.6.14.orig/Documentation/DocBook/Makefile +++ linux-2.6.14/Documentation/DocBook/Makefile @@ -10,7 +10,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mc kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ procfs-guide.xml writing_usb_driver.xml \ sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \ - gadget.xml libata.xml mtdnand.xml librs.xml + gadget.xml libata.xml mtdnand.xml librs.xml genericirq.xml ### # The build process is as follows (targets): Index: linux-2.6.14/Documentation/DocBook/genericirq.tmpl =================================================================== --- /dev/null +++ linux-2.6.14/Documentation/DocBook/genericirq.tmpl @@ -0,0 +1,560 @@ + + + + + + Linux generic IRQ handling + + + + Thomas + Gleixner + +
+ tglx@linutronix.de +
+
+
+ + Ingo + Molnar + +
+ mingo@elte.hu +
+
+
+
+ + + 2005 + Thomas Gleixner + + + 2005 + Ingo Molnar + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + + + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + The generic interrupt handling layer is designed to provide a + complete abstraction of interrupt handling for device drivers + and is able to handle all different types of interrupt controller + hardware. Device drivers use generic API function to request, enable, + disable and free interrupts. The drivers do not have to know anything + about interrupt hardware, so they can be used on different hardware + platforms without code changes. + + + This documentation is provided for developers who want to implement + architecture interrupt support based on the Generic IRQ handling layer. + + + + + Rationale + + The original implementation of interrupt handling in Linux is using + the __do_IRQ() super-handler, which must be able to deal with every + type of interrupt logic. This is achieved by an 'interrupt type' + structure and runtime flags to handle special cases. + Furthermore the superhandler assumed a certain type of interrupt + handling hardware and turned out to be not capable of handling all + kind of interrupt controller hardware which can be found through + the architectures. The all in one approach also adds unnecessary + complexity for every user. + + + Originally, Russell King identified different types of handlers to + build a quite universal set for the ARM interrupt handler + implementation in Linux 2.5/2.6. He distiguished between: + + Level type + Edge type + Simple type + + In the SMP world of the __do_IRQ() super-handler another type + was identified: + + Per CPU type + + + + This split implementation of handlers allows to optimize the flow + of the interrupt handling for each specific interrupt type. + This reduces complexitiy in that particular code path and allows + the optimized handling of a given type. + + + The original general implementation uses interrupt_type structures + to differentiate the flow control in the super-handler. This + leads to a mix of flow logic and code related to hardware details. + Russell Kings ARM implementation which replaced the type by a chip + abstraction did the mix the other way around. + + + The natural conclusion was a clean seperation of the 'type flow' + and the 'chip'. Analysing a couple of architecture implementations + reveals that many of them can use a generic set of 'type flow' + implementations and only need to add the chip level specific code. + The seperation is also valuable for the (sub)architectures, + which need specific quirks in the type flow itself, because it + provides a more transparent design. + + + Each interrupt type implementation has assigned its own flow + handler, which should be normally one of the generic + implementations. The flow handler implementation makes it + simple to provide demultiplexing handlers which can be found in + embedded platforms on various architectures. + + + The seperation makes the generic interrupt handling more flexible + and extensible. An (sub)architecture can use a generic type flow + implementation for e.g. 'level type' interrupts and add a + (sub)architecture specific 'edge type' implementation. + + + To make the transition to the new model easier and prevent the + breakage of existing implementations the __do_IRQ() super-handler + is still available. This leads to a kind of duality for the time + being. Over time the new model should achieve a homogeneous + implementation scheme over all architectures with enhanced + maintainability and cleanliness. + + + + Known Bugs And Assumptions + + None (hopefully). + + + + + Abstraction layers + + There are three main levels of abstraction in the interrupt code: + + Highlevel driver API + Abstract interrupt type + Chiplevel hardware encapsulation + + + + The seperation of interrupt type and chip level functionality + provides the most flexible design. This implementation can handle + all kinds of interrupt hardware and the necessary workarounds for + the interrupt types without the need of redundant implementations. + The seperation handles also edge and level type interrupts + on the same hardware chip. + + + Interrupt control flow + + Each interrupt is described by an interrupt description structure + irq_desc. The interrupt is referenced by an 'unsigned int' numeric + value which selects the corresponding interrupt decription structure + in the description structures array. + The description structure contains status information and pointers + to the interrupt type structure and the interrupt chip structure + which are assigned to this interrupt. + + + Whenever an interrupt triggers, the lowlevel arch code calls into + the generic interrupt code by calling desc->handler->handle_irq(). + This highlevel IRQ handling function only uses other + desc->handler primitives which describe the control flow operation + necessary for the interrupt type. These operations are calling + the chip primitives referenced by the assigned chip description + structure. + + + + Highlevel Driver API + + The highlevel Driver API consists of following functions: + + request_irq() + free_irq() + disable_irq() + enable_irq() + disable_irq_nosync() (SMP only) + synchronize_irq() (SMP only) + set_irq_type() + set_irq_wake() + set_irq_data() + set_irq_chip() + set_irq_chip_data() + + See the autogenerated function documentation for details. + + + + Abstract interrupt type + + The 'interrupt type' (struct irq_type) abstraction mainly consists of + methods which implement the 'interrupt handling flow'. The generic + layer provides a set of pre-defined types: + + default_level_type + default_edge_type + default_simple_type + default_percpu_type + + The default type implementations use the generic type handlers. + + handle_level_type + handle_edge_type + handle_simple_type + handle_percpu_type + + The interrupt types (either predefined or architecture specific) are + assigned to specific interrupts by the architecture either during + bootup or during device initialization. + + + Default type implementations + + Helper functions + + The helper functions call the chip primitives and + are used by the default type implementations. + Following helper functions are implemented (simplified excerpt): + +default_enable(irq) +{ + desc->chip->unmask(irq); +} + +default_disable(irq) +{ + desc->chip->mask(irq); +} + +default_ack(irq) +{ + chip->ack(irq); +} + +default_mask_ack(irq) +{ + if (chip->mask_ack) { + chip->mask_ack(irq); + } else { + chip->mask(irq); + chip->ack(irq); + } +} + +noop(irq) +{ +} + +default_set_type(irq, type) +{ + if (desc->chip->set_type) { + if (desc->chip->set_type(irq, type)) + return NULL; + } + + return default_handler for type; +} + + + + + Default Level IRQ type + + The default Level IRQ type implements the functions + + enabledefault_enable + disabledefault_disable + startdefault_mask_ack + enddefault_enable + handle_irqhandle_level_irq + set_typedefault_set_type + + + + + Default Edge IRQ type + + The default Edge IRQ type implements the functions + + enabledefault_enable + disabledefault_disable + startdefault_ack + holddefault_mask_ack + endnoop + handle_irqhandle_edge_irq + set_typedefault_set_type + + + + + Default simple IRQ type + + The default simple IRQ type implements the functions + + enablenoop + disablenoop + handle_irqhandle_simple_irq + + + + + Default per CPU IRQ type + + The default per CPU IRQ type implements the functions + + enabledefault_enable + disabledefault_disable + startdefault_ack + enddefault_enable + handle_irqhandle_percpu_irq + + + + + + Default type handler implementations + + Default Level IRQ type handler + + handle_level_type provides a generic implementation + for level type interrupts. + + + Following control flow is implemented (simplified excerpt): + +desc->handler->start(); +handle_IRQ_event(desc->action); +desc->handler->end(); + + + + + Default Edge IRQ type handler + + handle_edge_type provides a generic implementation + for edge type interrupts. + + + Following control flow is implemented (simplified excerpt): + +if (desc->status & running) { + desc->handler->hold(); + desc->status |= pending | masked; + return; +} +desc->handler->start(); +desc->status |= running; +do { + if (desc->status & masked) + desc->handler->enable(); + desc-status &= ~pending; + handle_IRQ_event(desc->action); +} while (status & pending); +desc-status &= ~running; +desc->handler->end(); + + + + + Default simple IRQ type handler + + handle_simple_type provides a generic implementation + for simple type interrupts. + + + Note: The simple type handler does not call any + handler/chip primitives. + + + Following control flow is implemented (simplified excerpt): + +handle_IRQ_event(desc->action); + + + + + Default per CPU type handler + + handle_percpu_type provides a generic implementation + for per CPU type interrupts. + + + Per CPU interrupts are only available on SMP and + the handler provides a simplified version without + locking. + + + Following control flow is implemented (simplified excerpt): + +desc->handler->start(); +handle_IRQ_event(desc->action); +desc->handler->end(); + + + + + + Architecture specific type implementation + + If an architecture needs to implement its own type structures, then + the following primitives have to be implemented: + + handle_irq() - The handle_irq function pointer should preferably point to + one of the generic type handler functions + startup() - Optional + shutdown() - Optional + enable() + disable() + start() + hold() - For edge type interupts only + end() + set_type - Optional + set_affinity - SMP only + + + + + Quirks and optimizations + + The generic functions are intended for 'clean' architectures and chips, + which have no platform-specific IRQ handling quirks. If an architecture + needs to implement quirks on the 'flow' level then it can do so by + overriding the irqtype. This is also done for compatibility reasons, as + most architectures use irqtypes only at the moment. + + + An architecture could implement all of its IRQ logic via pushing + chip handling details into the irqtype's ->start()/->end()/->hold() + functions. This is only recommended when the underlying primitives + are pure chip primitives without additional quirks. The direct pointer + to the chip functions reduces the indirection level by one. + + + + + Chiplevel hardware encapsulation + + The chip level hardware description structure irq_chip + contains all the direct chip relevant functions, which + can be utilized by the irq_type implementations. + + ack() + mask_ack() - Optional, recommended for performance + mask() + unmask() + retrigger() - Optional + set_type() - Optional + set_wake() - Optional + + These primitives are strictly intended to mean what they say: ack means + ACK, masking means masking of an IRQ line, etc. It is up to the flow + handler(s) to use these basic units of lowlevel functionality. + + + + + + __do_IRQ entry point + + The original implementation __do_IRQ() is an alternative entry + point for all types of interrupts. + + + This handler turned out to be not suitable for all + interrupt hardware and was therefor reimplemented with split + functionality for egde/level/simple/percpu interrupts. This is not + only a functional optimization. It also shortenes code pathes for + interrupts. + + + To make use of the split implementation, replace the call to + __do_IRQ by a call to desc->handler->handle_irq() and associate + the appropriate handler function to desc->handler->handle_irq(). + In most cases the generic type and handler implementations should + be sufficient. + + + + + Locking on SMP + + The locking of chip registers is up to the architecture that + defines the chip primitives. There is a chip->lock field that can be used + for serialization, but the generic layer does not touch it. The per-irq + structure is protected via desc->lock, by the generic layer. + + + + Structures + + This chapter contains the autogenerated documentation of the structures which are + used in the generic IRQ layer. + +!Iinclude/linux/irq.h + + + + Public Functions Provided + + This chapter contains the autogenerated documentation of the kernel API functions + which are exported. + +!Ekernel/irq/manage.c + + + + Internal Functions Provided + + This chapter contains the autogenerated documentation of the internal functions. + +!Ikernel/irq/handle.c + + + + Credits + + The following people have contributed to this document: + + Thomas Gleixnertglx@linutronix.de + Ingo Molnarmingo@elte.hu + + + +
Index: linux-2.6.14/include/linux/irq.h =================================================================== --- linux-2.6.14.orig/include/linux/irq.h +++ linux-2.6.14/include/linux/irq.h @@ -1,14 +1,6 @@ #ifndef __irq_h #define __irq_h -/* - * Please do not include this file in generic code. There is currently - * no requirement for any architecture to implement anything held - * within this file. - * - * Thanks. --rmk - */ - #include #if !defined(CONFIG_ARCH_S390) @@ -39,48 +31,141 @@ # define CHECK_IRQ_PER_CPU(var) 0 #endif +#define IRQ_NOPROBE 512 /* IRQ is not valid for probing */ +#define IRQ_NOREQUEST 1024 /* IRQ cannot be requested */ + /* - * Interrupt controller descriptor. This is all we need - * to describe about the low-level hardware. + * IRQ types + */ +#define IRQ_TYPE_NONE 0x0000 /* Default, unspecified type */ +#define IRQ_TYPE_EDGEL 0x0001 /* Edge low/falling type */ +#define IRQ_TYPE_EDGEH 0x0002 /* Edge high/rising type */ +#define IRQ_TYPE_EDGEB \ + (IRQ_TYPE_EDGEL | IRQ_TYPE_EDGEH) /* Edge low+high/both type */ +#define IRQ_TYPE_LEVELL 0x0004 /* Level low type */ +#define IRQ_TYPE_LEVELH 0x0008 /* Level high type */ +#define IRQ_TYPE_SIMPLE 0x0010 /* Simple type */ + + +/* + * IRQ wakeup control modes + */ +#define IRQ_WAKE_NORESUME 0x0000 /* Do not resume on this irq */ +#define IRQ_WAKE_RESUME 0x0001 /* Enable resume on this irq */ + +/** + * struct irq_chip - Low level interrupt controller hardware descriptor + * + * @ack: acknowledge IRQ + * @mask: mask the IRQ + * @mask_ack: acknowledge and mask the IRQ + * @unmask: unmask the IRQ + * @retrigger: retrigger the IRQ in hardware, if possible. Return 0 on success. + * @set_type: set the IRQ type (level, edge[high,low,both]) + * @set_wake: Set the IRQ PM-wakeup function + * @options: option field to store type, wake information + * @lock: locking for SMP + * @chip_data: platform-specific private data for the chip + */ +struct irq_chip { + spinlock_t lock; + void (*ack)(unsigned int irq); + void (*mask)(unsigned int irq); + void (*mask_ack)(unsigned int irq); + void (*unmask)(unsigned int irq); + int (*retrigger)(unsigned int irq); + int (*set_type)(unsigned int irq, unsigned int hw_type); + int (*set_wake)(unsigned int irq, unsigned int mode); + unsigned long options; + void *chip_data; +}; + +struct irq_desc; +struct irq_type; + +/** + * struct irq_type - high level hardware interrupt type descriptor + * + * @typename: name for /proc/interrupts + * @startup: start up the interrupt (defaults to ->enable if NULL) + * @shutdown: shut down the interrupt (defaults to ->disable if NULL) + * @enable: enable the interrupt (defaults to chip->unmask if NULL) + * @disable: disable the interrupt (defaults to chip->mask if NULL) + * @handle_irq: irq flow handler called from the arch IRQ glue code + * @ack: start of new interrupt. (Note: This will be renamed to 'start') + * @hold: same interrupt while the handler is running + * @end: end of interrupt + * @set_affinity: set the CPU affinity on SMP machines + * @set_type: set the interrupt type (level, edge[high,low,both]), + * returns a pointer to the irq_type structure which can + * handle the requested type or NULL, if the type cannot + * be handled. */ -struct hw_interrupt_type { - const char * typename; - unsigned int (*startup)(unsigned int irq); - void (*shutdown)(unsigned int irq); - void (*enable)(unsigned int irq); - void (*disable)(unsigned int irq); - void (*ack)(unsigned int irq); - void (*end)(unsigned int irq); - void (*set_affinity)(unsigned int irq, cpumask_t dest); +struct irq_type { + const char *typename; + unsigned int (*startup)(unsigned int irq); + void (*shutdown)(unsigned int irq); + void (*enable)(unsigned int irq); + void (*disable)(unsigned int irq); + + void (*handle_irq)(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs); + + /* (*start) Will be renamed */ + void (*ack)(unsigned int irq); + void (*hold)(unsigned int irq); + void (*end)(unsigned int irq); + void (*set_affinity)(unsigned int irq, cpumask_t dest); + struct irq_type *(*set_type)(unsigned int irq, unsigned int type); /* Currently used only by UML, might disappear one day.*/ #ifdef CONFIG_IRQ_RELEASE_METHOD void (*release)(unsigned int irq, void *dev_id); #endif }; -typedef struct hw_interrupt_type hw_irq_controller; - -/* - * This is the "IRQ descriptor", which contains various information - * about the irq, including what kind of hardware handling it has, - * whether it is disabled etc etc. +/** + * struct irq_desc - interrupt descriptor + * + * @handler: interrupt type dependent handler functions, + * (this should be renamed to 'type') + * @handler_data: data for the type handlers + * @chip: low level hardware access functions - comes from type + * @action: the irq action chain + * @status: status information + * @depth: disable-depth, for nested irq_disable() calls + * @irq_count: stats field to detect stalled irqs + * @irqs_unhandled: stats field for spurious unhandled interrupts + * @lock: locking for SMP + * @move_irq: Flag need to re-target interrupt destination * * Pad this out to 32 bytes for cache and indexing reasons. */ typedef struct irq_desc { - 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; - spinlock_t lock; + struct irq_type *handler; + void *handler_data; + struct irq_chip *chip; + struct irqaction *action; + unsigned int status; + + unsigned int depth; + unsigned int irq_count; + unsigned int irqs_unhandled; + spinlock_t lock; #if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE) - unsigned int move_irq; /* Flag need to re-target intr dest*/ + unsigned int move_irq; #endif } ____cacheline_aligned irq_desc_t; + +/* + * Migration helpers for obsolete names, they will go away: + */ +#define irqdesc irq_desc +#define irqchip irq_chip +#define hw_interrupt_type irq_type +#define set_irq_type set_hwirq_type +typedef struct irq_type hw_irq_controller; + extern irq_desc_t irq_desc [NR_IRQS]; /* Return a pointer to the irq descriptor for IRQ. */ @@ -210,16 +295,73 @@ static inline void set_irq_info(int irq, #endif // CONFIG_SMP extern int no_irq_affinity; -extern int noirqdebug_setup(char *str); +/* Handle irq action chains */ extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, - struct irqaction *action); + struct irqaction *action); + +/* + * Built-in IRQ handlers for various IRQ types, + * callable via desc->handler->handle_irq() + */ +extern void handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); +extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); +extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); +extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); +extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs); + +#define desc_handle_irq(irq, desc, regs) \ +do { \ + spin_lock(&(desc)->lock); \ + (desc)->handler->handle_irq(irq, (desc), regs); \ + spin_unlock(&(desc)->lock); \ +} while(0) + +/* Monolithic do_IRQ implementation */ extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); + +/* Handling of unhandled and spurious interrupts */ extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret, struct pt_regs *regs); -extern int can_request_irq(unsigned int irq, unsigned long irqflags); +/* Resending of interrupts */ +void check_irq_resend(irq_desc_t *desc, unsigned int irq); + +/* Proc filesystem */ extern void init_irq_proc(void); + +/* Enable/disable irq debugging output */ +extern int noirqdebug_setup(char *str); + +/* Set/get irq type */ +extern int set_irq_type(unsigned int irq, unsigned int type); +extern int get_irq_type(unsigned int irq, unsigned int type); + +/* Irq wakeup (PM) control) */ +extern int set_irq_wake(unsigned int irq, unsigned int mode); +#define enable_irq_wake(irq) set_irq_wake(irq, IRQ_WAKE_RESUME) +#define disable_irq_wake(irq) set_irq_wake(irq, IRQ_WAKE_NORESUME) + +/* Checks whether the interrupt can be requested by request_irq() */ +extern int can_request_irq(unsigned int irq, unsigned long irqflags); + +/* Set type control/chip/data for an interrupt */ +extern int generic_set_irq_type(unsigned int irq, struct irq_type *type); +extern int set_irq_data(unsigned int irq, void *data); +extern int set_irq_chip(unsigned int irq, struct irq_chip *chip); +extern int set_irq_chip_data(unsigned int irq, void *data); + +/* Get chip/data for an interrupt */ +#define get_irq_chip(irq) (irq_desc[irq].chip) +#define get_irq_chip_data(irq) (irq_desc[irq].chip->chip_data) + +/* Interrupt type default implementations */ +extern struct irq_type no_irq_type; +extern struct irq_type default_edge_type; +extern struct irq_type default_level_type; +extern struct irq_type default_simple_type; +extern struct irq_type default_percpu_type; + #endif extern hw_irq_controller no_irq_type; /* needed in every arch ? */ Index: linux-2.6.14/kernel/irq/Makefile =================================================================== --- linux-2.6.14.orig/kernel/irq/Makefile +++ linux-2.6.14/kernel/irq/Makefile @@ -1,5 +1,5 @@ -obj-y := handle.o manage.o spurious.o +obj-y := handle.o manage.o spurious.o resend.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o Index: linux-2.6.14/kernel/irq/handle.c =================================================================== --- linux-2.6.14.orig/kernel/irq/handle.c +++ linux-2.6.14/kernel/irq/handle.c @@ -1,9 +1,13 @@ /* * linux/kernel/irq/handle.c * - * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar + * Copyright (C) 1992, 1998-2005 Linus Torvalds, Ingo Molnar + * Copyright (C) 2005, Thomas Gleixner, Russell King * * This file contains the core interrupt handling code. + * + * Detailed information is available in Documentation/DocBook/genericirq + * */ #include @@ -12,57 +16,57 @@ #include #include +#if defined(CONFIG_NO_IDLE_HZ) +#include +#endif + #include "internals.h" /* - * Linux has a controller-independent interrupt architecture. - * Every controller has a 'controller-template', that is used - * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the apropriate - * controller. Thus drivers need not be aware of the - * interrupt-controller. - * - * The code is designed to be easily extended with new/different - * interrupt controllers, without having to do assembly magic or - * having to touch the generic code. - * - * Controller mappings for all interrupt sources: + * Default initialization for all interrupt sources */ irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { .status = IRQ_DISABLED, .handler = &no_irq_type, - .lock = SPIN_LOCK_UNLOCKED + .lock = SPIN_LOCK_UNLOCKED, + .depth = 1, } }; /* - * Generic 'no controller' code + * What should we do if we get a hw irq event on an illegal vector? + * Each architecture has to answer this themself. */ -static void end_none(unsigned int irq) { } -static void enable_none(unsigned int irq) { } -static void disable_none(unsigned int irq) { } -static void shutdown_none(unsigned int irq) { } -static unsigned int startup_none(unsigned int irq) { return 0; } - -static void ack_none(unsigned int irq) +static void ack_bad(unsigned int irq) { - /* - * 'what should we do if we get a hw irq event on an illegal vector'. - * each architecture has to answer this themself. - */ ack_bad_irq(irq); } -struct hw_interrupt_type no_irq_type = { +/* + * NOP functions + */ +static void noop(unsigned int irq) +{ +} + +static unsigned int noop_ret(unsigned int irq) +{ + return 0; +} + +/* + * Generic no controller implementation + */ +struct irq_type no_irq_type = { .typename = "none", - .startup = startup_none, - .shutdown = shutdown_none, - .enable = enable_none, - .disable = disable_none, - .ack = ack_none, - .end = end_none, - .set_affinity = NULL + .startup = noop_ret, + .shutdown = noop, + .enable = noop, + .disable = noop, + .ack = ack_bad, + .end = noop, + .handle_irq = handle_bad_irq, }; /* @@ -74,7 +78,148 @@ irqreturn_t no_action(int cpl, void *dev } /* - * Have got an event to handle: + * default ack function + */ +static void default_ack(unsigned int irq) +{ + irq_desc[irq].chip->ack(irq); +} + +/* + * default mask ack function + */ +static void default_mask_ack(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + + if (desc->chip->mask_ack) { + desc->chip->mask_ack(irq); + } else { + desc->chip->mask(irq); + desc->chip->ack(irq); + } +} + +/* + * default enable function + */ +static void default_enable(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + + desc->chip->unmask(irq); + desc->status &= ~IRQ_MASKED; +} + +/* + * default end function + */ +static void default_end(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + + if (!desc->depth) + desc->chip->unmask(irq); +} + +/* + * default disable function + */ +static void default_disable(unsigned int irq) +{ + irq_desc[irq].chip->mask(irq); +} + +/* + * Default set type function + */ +static struct irq_type *default_set_type(unsigned int irq, unsigned int type) +{ + irq_desc_t *desc = irq_desc + irq; + + if (desc->chip->set_type) + if (desc->chip->set_type(irq, type)) + return NULL; + + switch (type) { + case IRQ_TYPE_NONE: + return &no_irq_type; + + case IRQ_TYPE_EDGEL: + case IRQ_TYPE_EDGEH: + case IRQ_TYPE_EDGEB: + return &default_edge_type; + case IRQ_TYPE_LEVELL: + case IRQ_TYPE_LEVELH: + return &default_level_type; + case IRQ_TYPE_SIMPLE: + return &default_simple_type; + } + return NULL; +} + +/* + * Generic edge type interrupt + * + */ +struct irq_type default_edge_type = { + .typename = "default_edge", + .enable = default_enable, + .disable = default_disable, + .ack = default_ack, + .hold = default_mask_ack, + .end = noop, + .handle_irq = handle_edge_irq, + .set_type = default_set_type, +}; + +/* + * Generic level type interrupt + */ +struct irq_type default_level_type = { + .typename = "default_level", + .enable = default_enable, + .disable = default_disable, + .ack = default_mask_ack, + .end = default_end, + .handle_irq = handle_level_irq, + .set_type = default_set_type, +}; + +/* + * Generic simple type interrupt + * + * No hardware handling necessary + */ +struct irq_type default_simple_type = { + .typename = "default_simple", + .enable = default_enable, + .disable = default_disable, + .set_type = default_set_type, + .handle_irq = handle_simple_irq, +}; + +#ifdef CONFIG_SMP +/* + * Generic per cpu type interrupt + */ +struct irq_type default_percpu_type = { + .typename = "default_percpu", + .enable = default_enable, + .disable = default_disable, + .ack = default_ack, + .end = default_end, + .handle_irq = handle_percpu_irq, +}; +#endif + +/** + * handle_IRQ_event - irq action chain handler + * @irq: the interrupt number + * @regs: pointer to a register structure + * @action: the interrupt action chain for this irq + * + * Handles the action chain of an irq event */ fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action) @@ -84,6 +229,15 @@ fastcall int handle_IRQ_event(unsigned i if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); +#if defined(CONFIG_NO_IDLE_HZ) + if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { + write_seqlock(&xtime_lock); + if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) + system_timer->dyn_tick->handler(irq, 0, regs); + write_sequnlock(&xtime_lock); + } +#endif + do { ret = action->handler(irq, action->dev_id, regs); if (ret == IRQ_HANDLED) @@ -99,10 +253,208 @@ fastcall int handle_IRQ_event(unsigned i return retval; } -/* - * do_IRQ handles all normal device IRQ's (the special +/** + * handle_bad_irq - handle spurious and unhandled irqs + * @irq: the interrupt number + * @desc: the interrupt description structure for this irq + * @regs: pointer to a register structure + */ +void handle_bad_irq(unsigned int irq, irq_desc_t *desc, struct pt_regs *regs) +{ +} + +/** + * handle_simple_irq - Simple and software-decoded IRQs. + * @irq: the interrupt number + * @desc: the interrupt description structure for this irq + * @regs: pointer to a register structure + * + * Simple interrupts are either sent from a demultiplexing interrupt + * handler or come from hardware, where no interrupt hardware control + * is necessary. + * + * Note: The caller is expected to handle the ack, clear, mask and + * unmask issues if necessary. + * + * Must be called with the irq_desc->lock held + */ +void handle_simple_irq(unsigned int irq, irq_desc_t *desc, struct pt_regs *regs) +{ + struct irqaction *action; + irqreturn_t action_ret; + const unsigned int cpu = smp_processor_id(); + + kstat_cpu(cpu).irqs[irq]++; + + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); + + action = desc->action; + if (unlikely(!action || desc->depth)) + return; + + desc->status |= IRQ_INPROGRESS; + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, regs, action); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret, regs); + spin_lock(&desc->lock); + desc->status &= ~IRQ_INPROGRESS; +} + +/** + * handle_level_irq - Level type irq handler + * @irq: the interrupt number + * @desc: the interrupt description structure for this irq + * @regs: pointer to a register structure + * + * Level type interrupts are active as long as the hardware line has + * the active level. This may require to mask the interrupt and unmask it + * after the associated handler has acknowledged the device, so the + * interrupt line is back to inactive. + * + * Must be called with the irq_desc->lock held + */ +void handle_level_irq(unsigned int irq, irq_desc_t *desc, struct pt_regs *regs) +{ + struct irqaction *action; + irqreturn_t action_ret; + const unsigned int cpu = smp_processor_id(); + + kstat_cpu(cpu).irqs[irq]++; + + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); + + desc->handler->ack(irq); + + /* + * If its disabled or no action available + * keep it masked and get out of here + */ + action = desc->action; + if (unlikely(!action || desc->depth)) + goto out; + + desc->status |= IRQ_INPROGRESS; + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, regs, action); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret, regs); + spin_lock(&desc->lock); + + desc->status &= ~IRQ_INPROGRESS; +out: + desc->handler->end(irq); +} + +/** + * handle_edge_irq - edge type IRQ handler + * @irq: the interrupt number + * @desc: the interrupt description structure for this irq + * @regs: pointer to a register structure + * + * Interrupt occures on the falling and/or rising edge of a hardware + * signal. The occurence is latched into the irq controller hardware + * and must be acked in order to be reenabled. After the ack another + * interrupt can happen on the same source even before the first one + * is handled by the assosiacted event handler. If this happens it + * might be necessary to disable (mask) the interrupt depending on the + * controller hardware. This requires to reenable the interrupt inside + * of the loop which handles the interrupts which have arrived while + * the handler was running. If all pending interrupts are handled, the + * loop is left and depending on the hardware controller some final + * ack might be necessary. + * + * Must be called with the irq_desc->lock held + */ +void handle_edge_irq(unsigned int irq, irq_desc_t *desc, struct pt_regs *regs) +{ + const unsigned int cpu = smp_processor_id(); + + kstat_cpu(cpu).irqs[irq]++; + + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); + + /* + * If we're currently running this IRQ, or its disabled, + * we shouldn't process the IRQ. Mark it pending, handle + * the necessary masking and go out + */ + if (unlikely((desc->status & IRQ_INPROGRESS) || desc->depth || + !desc->action)) { + desc->status |= (IRQ_PENDING | IRQ_MASKED); + desc->handler->hold(irq); + return; + } + + /* Start handling the irq */ + desc->handler->ack(irq); + + /* Mark the IRQ currently in progress.*/ + desc->status |= IRQ_INPROGRESS; + + do { + struct irqaction *action = desc->action; + irqreturn_t action_ret; + + if (unlikely(!action)) { + desc->handler->disable(irq); + return; + } + + /* + * When another irq arrived while we were handling + * one, we could have masked the irq. + * Renable it, if it was not disabled in meantime. + */ + if (unlikely(((desc->status & (IRQ_PENDING | IRQ_MASKED)) == + (IRQ_PENDING | IRQ_MASKED)) && !desc->depth)) + desc->handler->enable(irq); + + desc->status &= ~IRQ_PENDING; + spin_unlock(&desc->lock); + action_ret = handle_IRQ_event(irq, regs, action); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret, regs); + spin_lock(&desc->lock); + + } while ((desc->status & IRQ_PENDING) && !desc->depth); + + desc->status &= ~IRQ_INPROGRESS; + desc->handler->end(irq); +} + +#ifdef CONFIG_SMP +/** + * handle_percpu_IRQ - Per CPU local irq handler + * @irq: the interrupt number + * @desc: the interrupt description structure for this irq + * @regs: pointer to a register structure + * + * Per CPU interrupts on SMP machines without locking requirements + */ +void handle_percpu_irq(unsigned int irq, irq_desc_t *desc, struct pt_regs *regs) +{ + irqreturn_t action_ret; + + kstat_this_cpu.irqs[irq]++; + desc->handler->ack(irq); + action_ret = handle_IRQ_event(irq, regs, desc->action); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret, regs); + desc->handler->end(irq); +} +#endif /* CONFIG_SMP */ + +/** + * __do_IRQ - original all in one handler + * @irq: the interrupt number + * @regs: pointer to a register structure + * + * __do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific - * handlers). + * handlers). * This is the original x86 implementation which is used for every + * type of interrupt. + * */ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) { Index: linux-2.6.14/kernel/irq/manage.c =================================================================== --- linux-2.6.14.orig/kernel/irq/manage.c +++ linux-2.6.14/kernel/irq/manage.c @@ -1,7 +1,8 @@ /* * linux/kernel/irq/manage.c * - * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar + * Copyright (C) 1992, 1998-2005 Linus Torvalds, Ingo Molnar + * Copyright (C) 2005, Thomas Gleixner * * This file contains driver APIs to the irq subsystem. */ @@ -24,6 +25,7 @@ cpumask_t __cacheline_aligned pending_ir /** * synchronize_irq - wait for pending IRQ handlers (on other CPUs) + * @irq: Interrupt to synchronize * * This function waits for any pending IRQ handlers for this interrupt * to complete before returning. If you use this function while @@ -115,11 +117,9 @@ void enable_irq(unsigned int irq) case 1: { unsigned int status = desc->status & ~IRQ_DISABLED; - desc->status = status; - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - desc->status = status | IRQ_REPLAY; - hw_resend_irq(desc->handler,irq); - } + /* Prevent probing on this irq */ + desc->status = status | IRQ_NOPROBE; + check_irq_resend(desc, irq); desc->handler->enable(irq); /* fall-through */ } @@ -131,6 +131,28 @@ void enable_irq(unsigned int irq) EXPORT_SYMBOL(enable_irq); +/** + * set_irq_wake - control irq power management wakeup + * @irq: Interrupt to control + * @mode: power management wakeup mode + * + * Enable/disable power management wakeup mode + */ +int set_irq_wake(unsigned int irq, unsigned int mode) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + int ret = -ENXIO; + + spin_lock_irqsave(&desc->lock, flags); + if (desc->chip && desc->chip->set_wake) + ret = desc->chip->set_wake(irq, mode); + spin_unlock_irqrestore(&desc->lock, flags); + return ret; +} + +EXPORT_SYMBOL(set_irq_wake); + /* * Internal function that tells the architecture code whether a * particular irq has been exclusively allocated or is available @@ -140,7 +162,7 @@ int can_request_irq(unsigned int irq, un { struct irqaction *action; - if (irq >= NR_IRQS) + if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST) return 0; action = irq_desc[irq].action; @@ -184,12 +206,12 @@ int setup_irq(unsigned int irq, struct i /* * The following block of code has to be executed atomically */ - spin_lock_irqsave(&desc->lock,flags); + spin_lock_irqsave(&desc->lock, flags); p = &desc->action; if ((old = *p) != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&desc->lock,flags); + spin_unlock_irqrestore(&desc->lock, flags); return -EBUSY; } @@ -212,7 +234,7 @@ int setup_irq(unsigned int irq, struct i else desc->handler->enable(irq); } - spin_unlock_irqrestore(&desc->lock,flags); + spin_unlock_irqrestore(&desc->lock, flags); new->irq = irq; register_irq_proc(irq); @@ -246,7 +268,7 @@ void free_irq(unsigned int irq, void *de return; desc = irq_desc + irq; - spin_lock_irqsave(&desc->lock,flags); + spin_lock_irqsave(&desc->lock, flags); p = &desc->action; for (;;) { struct irqaction * action = *p; @@ -274,7 +296,7 @@ void free_irq(unsigned int irq, void *de else desc->handler->disable(irq); } - spin_unlock_irqrestore(&desc->lock,flags); + spin_unlock_irqrestore(&desc->lock, flags); unregister_handler_proc(irq, action); /* Make sure it's not being used on another CPU */ @@ -282,8 +304,8 @@ void free_irq(unsigned int irq, void *de kfree(action); return; } - printk(KERN_ERR "Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&desc->lock,flags); + printk(KERN_ERR "Trying to free free IRQ%d\n", irq); + spin_unlock_irqrestore(&desc->lock, flags); return; } } @@ -336,6 +358,8 @@ int request_irq(unsigned int irq, return -EINVAL; if (irq >= NR_IRQS) return -EINVAL; + if (irq_desc[irq].status & IRQ_NOREQUEST) + return -EINVAL; if (!handler) return -EINVAL; @@ -359,3 +383,145 @@ int request_irq(unsigned int irq, EXPORT_SYMBOL(request_irq); +/** + * generic_set_irq_type - set the hardware irq type structure for an irq + * @irq: Interrupt number + * @type: Pointer to irq_type structure + */ +int generic_set_irq_type(unsigned int irq, struct irq_type *type) +{ + irq_desc_t *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to install type for IRQ%d\n", irq); + return -EINVAL; + } + + if (!type) + type = &no_irq_type; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + desc->handler = type; + spin_unlock_irqrestore(&desc->lock, flags); + + return 0; +} + +EXPORT_SYMBOL(generic_set_irq_type); + +/** + * set_irq_data - set irq type data for an irq + * @irq: Interrupt number + * @data: Pointer to interrupt specific data + * + * Set the hardware irq controller data for an irq + */ +int set_irq_data(unsigned int irq, void *data) +{ + irq_desc_t *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to install controller data for IRQ%d\n", irq); + return -EINVAL; + } + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + desc->handler_data = data; + spin_unlock_irqrestore(&desc->lock, flags); + return 0; +} + +EXPORT_SYMBOL(set_irq_data); + +/** + * set_irq_chip - set irq chip for an IRQ + * @irq: Interrupt number + * @chip: Pointer to irq_chip structure + * + * Set the hardware chip structure for an IRQ + */ +int set_irq_chip(unsigned int irq, struct irq_chip *chip) +{ + irq_desc_t *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); + return -EINVAL; + } + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + desc->chip = chip; + spin_unlock_irqrestore(&desc->lock, flags); + return 0; +} + +EXPORT_SYMBOL(set_irq_chip); + +/** + * set_irq_chip_data - set irq chip data for an irq + * @irq: Interrupt number + * @data: Pointer to chip specific data + * + * Set the hardware irq chip data for an irq + */ +int set_irq_chip_data(unsigned int irq, void *data) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + if (irq >= NR_IRQS || !desc->handler || !desc->chip) { + printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq); + return -EINVAL; + } + + spin_lock_irqsave(&desc->lock, flags); + desc->chip->chip_data = data; + spin_unlock_irqrestore(&desc->lock, flags); + + return 0; +} + +EXPORT_SYMBOL(set_irq_chip_data); + +/* + * set_hwirq_type - Set the irq type (level/edge/simple/percpu) + * @irq: Interrupt number + * @hw_type: interrupt type (see constants in include/linux/irq.h) + * + * Called from device drivers to configure GPIO interrupts + * according to their requirements. The set_type function of the + * handler returns a pointer to an irq_type structure which is + * able to handle this interrupt type. The handler in the irq + * descriptor structure is set to the new handler type. + * + */ +int set_hwirq_type(unsigned int irq, unsigned int hw_type) +{ + struct irq_type *type = NULL; + unsigned long flags; + irq_desc_t *desc; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); + return -ENODEV; + } + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + if (desc->handler->set_type) { + type = desc->handler->set_type(irq, hw_type); + if (type) + desc->handler = type; + } + spin_unlock_irqrestore(&desc->lock, flags); + return type ? -ENXIO : 0; +} + +EXPORT_SYMBOL(set_hwirq_type); + Index: linux-2.6.14/kernel/irq/resend.c =================================================================== --- /dev/null +++ linux-2.6.14/kernel/irq/resend.c @@ -0,0 +1,82 @@ +/* + * linux/kernel/irq/resend.c + * + * Copyright (C) 1992, 1998-2005 Linus Torvalds, Ingo Molnar + * Copyright (C) 2005, Thomas Gleixner + * + * This file contains the tasklet-based IRQ-resend code + */ + +#include +#include +#include +#include + +#include "internals.h" + +/* Bitmap to handle software resend of interrupts: */ +static DECLARE_BITMAP(irqs_resend, NR_IRQS); + +/* + * Run software resends of IRQ's + */ +static void resend_irqs(unsigned long arg) +{ + unsigned long flags; + int irq; + + for (;;) { + if (bitmap_empty(irqs_resend, NR_IRQS)) + break; + irq = find_first_bit(irqs_resend, NR_IRQS); + clear_bit(irq, irqs_resend); + local_irq_save(flags); + desc_handle_irq(irq, (irq_desc + irq), NULL); + local_irq_restore(flags); + } +} + +/* Tasklet to handle resend: */ +static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); + +/* + * Handle irq resend + * + * If the interrupt is waiting to be processed, try to re-run it. We + * can't directly run it from here since the caller might be in an + * interrupt-protected region. Not all irq controller chips can + * retrigger interrupts at hardware level. For edge type interrupts it + * is necessary to resend them by software. At the moment the pending + * list is handled at the end of asm_do_IRQ. That means the next + * interrupt (on any irq line) will invoke the do_pending function. It + * could also be done by a thread which is woken up by the + * check_irq_resend function. + * + * Is called with interrupts disabled and desc->lock held + */ +void check_irq_resend(irq_desc_t *desc, unsigned int irq) +{ + + /* Chipless implementation. This should vanish in the long run */ + if (!desc->chip) { + unsigned int status = desc->status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler, irq); + } + return; + } + + /* Chip based implementation */ + if ((desc->status & IRQ_PENDING) && !test_bit(irq, irqs_resend)) { + desc->status &= ~IRQ_PENDING; + /* Try to retrigger it in hardware */ + if (!desc->chip || !desc->chip->retrigger || + desc->chip->retrigger(irq)) { + /* Mark it pending */ + set_bit(irq, irqs_resend); + tasklet_schedule(&resend_tasklet); + } + } +} + Index: linux-2.6.14/arch/arm/Kconfig =================================================================== --- linux-2.6.14.orig/arch/arm/Kconfig +++ linux-2.6.14/arch/arm/Kconfig @@ -50,6 +50,10 @@ config UID16 bool default y +config GENERIC_HARDIRQS + bool + default y + config RWSEM_GENERIC_SPINLOCK bool default y Index: linux-2.6.14/arch/arm/kernel/fiq.c =================================================================== --- linux-2.6.14.orig/arch/arm/kernel/fiq.c +++ linux-2.6.14/arch/arm/kernel/fiq.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/kernel/irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/kernel/irq.c +++ linux-2.6.14/arch/arm/kernel/irq.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -38,193 +39,11 @@ #include #include -#include #include -#include #include -/* - * Maximum IRQ count. Currently, this is arbitary. However, it should - * not be set too low to prevent false triggering. Conversely, if it - * is set too high, then you could miss a stuck IRQ. - * - * Maybe we ought to set a timer and re-enable the IRQ at a later time? - */ -#define MAX_IRQ_CNT 100000 - -static int noirqdebug; -static volatile unsigned long irq_err_count; -static DEFINE_SPINLOCK(irq_controller_lock); -static LIST_HEAD(irq_pending); - -struct irqdesc irq_desc[NR_IRQS]; void (*init_arch_irq)(void) __initdata = NULL; -/* - * No architecture-specific irq_finish function defined in arm/arch/irqs.h. - */ -#ifndef irq_finish -#define irq_finish(irq) do { } while (0) -#endif - -/* - * Dummy mask/unmask handler - */ -void dummy_mask_unmask_irq(unsigned int irq) -{ -} - -irqreturn_t no_action(int irq, void *dev_id, struct pt_regs *regs) -{ - return IRQ_NONE; -} - -void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) -{ - irq_err_count += 1; - printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); -} - -static struct irqchip bad_chip = { - .ack = dummy_mask_unmask_irq, - .mask = dummy_mask_unmask_irq, - .unmask = dummy_mask_unmask_irq, -}; - -static struct irqdesc bad_irq_desc = { - .chip = &bad_chip, - .handle = do_bad_IRQ, - .pend = LIST_HEAD_INIT(bad_irq_desc.pend), - .disable_depth = 1, -}; - -#ifdef CONFIG_SMP -void synchronize_irq(unsigned int irq) -{ - struct irqdesc *desc = irq_desc + irq; - - while (desc->running) - barrier(); -} -EXPORT_SYMBOL(synchronize_irq); - -#define smp_set_running(desc) do { desc->running = 1; } while (0) -#define smp_clear_running(desc) do { desc->running = 0; } while (0) -#else -#define smp_set_running(desc) do { } while (0) -#define smp_clear_running(desc) do { } while (0) -#endif - -/** - * disable_irq_nosync - disable an irq without waiting - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Enables and disables - * are nested. We do this lazily. - * - * This function may be called from IRQ context. - */ -void disable_irq_nosync(unsigned int irq) -{ - struct irqdesc *desc = irq_desc + irq; - unsigned long flags; - - spin_lock_irqsave(&irq_controller_lock, flags); - desc->disable_depth++; - list_del_init(&desc->pend); - spin_unlock_irqrestore(&irq_controller_lock, flags); -} -EXPORT_SYMBOL(disable_irq_nosync); - -/** - * disable_irq - disable an irq and wait for completion - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Enables and disables - * are nested. This functions waits for any pending IRQ - * handlers for this interrupt to complete before returning. - * If you use this function while holding a resource the IRQ - * handler may need you will deadlock. - * - * This function may be called - with care - from IRQ context. - */ -void disable_irq(unsigned int irq) -{ - struct irqdesc *desc = irq_desc + irq; - - disable_irq_nosync(irq); - if (desc->action) - synchronize_irq(irq); -} -EXPORT_SYMBOL(disable_irq); - -/** - * enable_irq - enable interrupt handling on an irq - * @irq: Interrupt to enable - * - * Re-enables the processing of interrupts on this IRQ line. - * Note that this may call the interrupt handler, so you may - * get unexpected results if you hold IRQs disabled. - * - * This function may be called from IRQ context. - */ -void enable_irq(unsigned int irq) -{ - struct irqdesc *desc = irq_desc + irq; - unsigned long flags; - - spin_lock_irqsave(&irq_controller_lock, flags); - if (unlikely(!desc->disable_depth)) { - printk("enable_irq(%u) unbalanced from %p\n", irq, - __builtin_return_address(0)); - } else if (!--desc->disable_depth) { - desc->probing = 0; - desc->chip->unmask(irq); - - /* - * If the interrupt is waiting to be processed, - * try to re-run it. We can't directly run it - * from here since the caller might be in an - * interrupt-protected region. - */ - if (desc->pending && list_empty(&desc->pend)) { - desc->pending = 0; - if (!desc->chip->retrigger || - desc->chip->retrigger(irq)) - list_add(&desc->pend, &irq_pending); - } - } - spin_unlock_irqrestore(&irq_controller_lock, flags); -} -EXPORT_SYMBOL(enable_irq); - -/* - * Enable wake on selected irq - */ -void enable_irq_wake(unsigned int irq) -{ - struct irqdesc *desc = irq_desc + irq; - unsigned long flags; - - spin_lock_irqsave(&irq_controller_lock, flags); - if (desc->chip->set_wake) - desc->chip->set_wake(irq, 1); - spin_unlock_irqrestore(&irq_controller_lock, flags); -} -EXPORT_SYMBOL(enable_irq_wake); - -void disable_irq_wake(unsigned int irq) -{ - struct irqdesc *desc = irq_desc + irq; - unsigned long flags; - - spin_lock_irqsave(&irq_controller_lock, flags); - if (desc->chip->set_wake) - desc->chip->set_wake(irq, 0); - spin_unlock_irqrestore(&irq_controller_lock, flags); -} -EXPORT_SYMBOL(disable_irq_wake); - int show_interrupts(struct seq_file *p, void *v) { int i = *(loff_t *) v, cpu; @@ -243,7 +62,7 @@ int show_interrupts(struct seq_file *p, } if (i < NR_IRQS) { - spin_lock_irqsave(&irq_controller_lock, flags); + spin_lock_irqsave(&irq_desc[i].lock, flags); action = irq_desc[i].action; if (!action) goto unlock; @@ -257,7 +76,7 @@ int show_interrupts(struct seq_file *p, seq_putc(p, '\n'); unlock: - spin_unlock_irqrestore(&irq_controller_lock, flags); + spin_unlock_irqrestore(&irq_desc[i].lock, flags); } else if (i == NR_IRQS) { #ifdef CONFIG_ARCH_ACORN show_fiq_list(p, v); @@ -265,270 +84,21 @@ unlock: #ifdef CONFIG_SMP show_ipi_list(p); #endif +#ifdef FIXME_TGLX seq_printf(p, "Err: %10lu\n", irq_err_count); - } - return 0; -} - -/* - * IRQ lock detection. - * - * Hopefully, this should get us out of a few locked situations. - * However, it may take a while for this to happen, since we need - * a large number if IRQs to appear in the same jiffie with the - * same instruction pointer (or within 2 instructions). - */ -static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) -{ - unsigned long instr_ptr = instruction_pointer(regs); - - if (desc->lck_jif == jiffies && - desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) { - desc->lck_cnt += 1; - - if (desc->lck_cnt > MAX_IRQ_CNT) { - printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); - return 1; - } - } else { - desc->lck_cnt = 0; - desc->lck_pc = instruction_pointer(regs); - desc->lck_jif = jiffies; - } - return 0; -} - -static void -report_bad_irq(unsigned int irq, struct pt_regs *regs, struct irqdesc *desc, int ret) -{ - static int count = 100; - struct irqaction *action; - - if (!count || noirqdebug) - return; - - count--; - - if (ret != IRQ_HANDLED && ret != IRQ_NONE) { - printk("irq%u: bogus retval mask %x\n", irq, ret); - } else { - printk("irq%u: nobody cared\n", irq); - } - show_regs(regs); - dump_stack(); - printk(KERN_ERR "handlers:"); - action = desc->action; - do { - printk("\n" KERN_ERR "[<%p>]", action->handler); - print_symbol(" (%s)", (unsigned long)action->handler); - action = action->next; - } while (action); - printk("\n"); -} - -static int -__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) -{ - unsigned int status; - int ret, retval = 0; - - spin_unlock(&irq_controller_lock); - -#ifdef CONFIG_NO_IDLE_HZ - if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { - write_seqlock(&xtime_lock); - if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) - system_timer->dyn_tick->handler(irq, 0, regs); - write_sequnlock(&xtime_lock); - } #endif - - if (!(action->flags & SA_INTERRUPT)) - local_irq_enable(); - - status = 0; - do { - ret = action->handler(irq, action->dev_id, regs); - if (ret == IRQ_HANDLED) - status |= action->flags; - retval |= ret; - action = action->next; - } while (action); - - if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - - spin_lock_irq(&irq_controller_lock); - - return retval; -} - -/* - * This is for software-decoded IRQs. The caller is expected to - * handle the ack, clear, mask and unmask issues. - */ -void -do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) -{ - struct irqaction *action; - const unsigned int cpu = smp_processor_id(); - - desc->triggered = 1; - - kstat_cpu(cpu).irqs[irq]++; - - smp_set_running(desc); - - action = desc->action; - if (action) { - int ret = __do_irq(irq, action, regs); - if (ret != IRQ_HANDLED) - report_bad_irq(irq, regs, desc, ret); - } - - smp_clear_running(desc); -} - -/* - * Most edge-triggered IRQ implementations seem to take a broken - * approach to this. Hence the complexity. - */ -void -do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) -{ - const unsigned int cpu = smp_processor_id(); - - desc->triggered = 1; - - /* - * If we're currently running this IRQ, or its disabled, - * we shouldn't process the IRQ. Instead, turn on the - * hardware masks. - */ - if (unlikely(desc->running || desc->disable_depth)) - goto running; - - /* - * Acknowledge and clear the IRQ, but don't mask it. - */ - desc->chip->ack(irq); - - /* - * Mark the IRQ currently in progress. - */ - desc->running = 1; - - kstat_cpu(cpu).irqs[irq]++; - - do { - struct irqaction *action; - - action = desc->action; - if (!action) - break; - - if (desc->pending && !desc->disable_depth) { - desc->pending = 0; - desc->chip->unmask(irq); - } - - __do_irq(irq, action, regs); - } while (desc->pending && !desc->disable_depth); - - desc->running = 0; - - /* - * If we were disabled or freed, shut down the handler. - */ - if (likely(desc->action && !check_irq_lock(desc, irq, regs))) - return; - - running: - /* - * We got another IRQ while this one was masked or - * currently running. Delay it. - */ - desc->pending = 1; - desc->chip->mask(irq); - desc->chip->ack(irq); -} - -/* - * Level-based IRQ handler. Nice and simple. - */ -void -do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) -{ - struct irqaction *action; - const unsigned int cpu = smp_processor_id(); - - desc->triggered = 1; - - /* - * Acknowledge, clear _AND_ disable the interrupt. - */ - desc->chip->ack(irq); - - if (likely(!desc->disable_depth)) { - kstat_cpu(cpu).irqs[irq]++; - - smp_set_running(desc); - - /* - * Return with this interrupt masked if no action - */ - action = desc->action; - if (action) { - int ret = __do_irq(irq, desc->action, regs); - - if (ret != IRQ_HANDLED) - report_bad_irq(irq, regs, desc, ret); - - if (likely(!desc->disable_depth && - !check_irq_lock(desc, irq, regs))) - desc->chip->unmask(irq); - } - - smp_clear_running(desc); } + return 0; } -static void do_pending_irqs(struct pt_regs *regs) -{ - struct list_head head, *l, *n; - - do { - struct irqdesc *desc; - - /* - * First, take the pending interrupts off the list. - * The act of calling the handlers may add some IRQs - * back onto the list. - */ - head = irq_pending; - INIT_LIST_HEAD(&irq_pending); - head.next->prev = &head; - head.prev->next = &head; - - /* - * Now run each entry. We must delete it from our - * list before calling the handler. - */ - list_for_each_safe(l, n, &head) { - desc = list_entry(l, struct irqdesc, pend); - list_del_init(&desc->pend); - desc_handle_irq(desc - irq_desc, desc, regs); - } - - /* - * The list must be empty. - */ - BUG_ON(!list_empty(&head)); - } while (!list_empty(&irq_pending)); -} +/* Handle bad interrupts */ +static struct irq_desc bad_irq = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED +}; /* - * do_IRQ handles all hardware IRQ's. Decoded IRQs should not + * asm_do_IRQ handles all hardware IRQ's. Decoded IRQs should not * come via this function. Instead, they should provide their * own 'handler' */ @@ -541,98 +111,54 @@ asmlinkage void asm_do_IRQ(unsigned int * than crashing, do something sensible. */ if (irq >= NR_IRQS) - desc = &bad_irq_desc; + desc = &bad_irq; irq_enter(); - spin_lock(&irq_controller_lock); - desc_handle_irq(irq, desc, regs); - /* - * Now re-run any pending interrupts. - */ - if (!list_empty(&irq_pending)) - do_pending_irqs(regs); - - irq_finish(irq); + desc_handle_irq(irq, desc, regs); - spin_unlock(&irq_controller_lock); irq_exit(); } -void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained) +void __set_irq_handler(unsigned int irq, struct irq_type *type, int is_chained) { struct irqdesc *desc; unsigned long flags; if (irq >= NR_IRQS) { - printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq); + printk(KERN_ERR "Trying to install type control for IRQ%d\n", irq); return; } - if (handle == NULL) - handle = do_bad_IRQ; - desc = irq_desc + irq; - if (is_chained && desc->chip == &bad_chip) - printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq); - - spin_lock_irqsave(&irq_controller_lock, flags); - if (handle == do_bad_IRQ) { - desc->chip->mask(irq); - desc->chip->ack(irq); - desc->disable_depth = 1; - } - desc->handle = handle; - if (handle != do_bad_IRQ && is_chained) { - desc->valid = 0; - desc->probe_ok = 0; - desc->disable_depth = 0; - desc->chip->unmask(irq); + /* Uninstall ? */ + if (type == NULL || type == &no_irq_type) { + spin_lock_irqsave(&desc->lock, flags); + if (desc->chip) { + desc->chip->mask(irq); + desc->chip->ack(irq); + } + desc->depth = 1; + spin_unlock_irqrestore(&desc->lock, flags); } - spin_unlock_irqrestore(&irq_controller_lock, flags); -} -void set_irq_chip(unsigned int irq, struct irqchip *chip) -{ - struct irqdesc *desc; - unsigned long flags; - - if (irq >= NR_IRQS) { - printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); + /* Install the irq_type */ + if (generic_set_irq_type(irq, type)) return; - } - - if (chip == NULL) - chip = &bad_chip; - - desc = irq_desc + irq; - spin_lock_irqsave(&irq_controller_lock, flags); - desc->chip = chip; - spin_unlock_irqrestore(&irq_controller_lock, flags); -} -int set_irq_type(unsigned int irq, unsigned int type) -{ - struct irqdesc *desc; - unsigned long flags; - int ret = -ENXIO; + spin_lock_irqsave(&desc->lock, flags); + if (is_chained && (desc->handler == &no_irq_type || !desc->chip)) + printk(KERN_WARNING "Trying to install chained interrupt type for IRQ%d\n", irq); - if (irq >= NR_IRQS) { - printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); - return -ENODEV; - } - - desc = irq_desc + irq; - if (desc->chip->set_type) { - spin_lock_irqsave(&irq_controller_lock, flags); - ret = desc->chip->set_type(irq, type); - spin_unlock_irqrestore(&irq_controller_lock, flags); + if (type != NULL && is_chained) { + desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; + desc->depth = 0; + if (desc->chip) + desc->chip->unmask(irq); } - - return ret; + spin_unlock_irqrestore(&desc->lock, flags); } -EXPORT_SYMBOL(set_irq_type); void set_irq_flags(unsigned int irq, unsigned int iflags) { @@ -645,408 +171,28 @@ void set_irq_flags(unsigned int irq, uns } desc = irq_desc + irq; - spin_lock_irqsave(&irq_controller_lock, flags); - desc->valid = (iflags & IRQF_VALID) != 0; - desc->probe_ok = (iflags & IRQF_PROBE) != 0; - desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0; - spin_unlock_irqrestore(&irq_controller_lock, flags); -} - -int setup_irq(unsigned int irq, struct irqaction *new) -{ - int shared = 0; - struct irqaction *old, **p; - unsigned long flags; - struct irqdesc *desc; - - /* - * Some drivers like serial.c use request_irq() heavily, - * so we have to be careful not to interfere with a - * running system. - */ - if (new->flags & SA_SAMPLE_RANDOM) { - /* - * This function might sleep, we want to call it first, - * outside of the atomic block. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(irq); - } - - /* - * The following block of code has to be executed atomically - */ - desc = irq_desc + irq; - spin_lock_irqsave(&irq_controller_lock, flags); - p = &desc->action; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&irq_controller_lock, flags); - return -EBUSY; - } - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; - } - - *p = new; - - if (!shared) { - desc->probing = 0; - desc->running = 0; - desc->pending = 0; - desc->disable_depth = 1; - if (!desc->noautoenable) { - desc->disable_depth = 0; - desc->chip->unmask(irq); - } - } - - spin_unlock_irqrestore(&irq_controller_lock, flags); - return 0; -} - -/** - * request_irq - allocate an interrupt line - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs - * @irqflags: Interrupt type flags - * @devname: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * This call allocates interrupt resources and enables the - * interrupt line and IRQ handling. From the point this - * call is made your handler function may be invoked. Since - * your handler function must clear any interrupt the board - * raises, you must take care both to initialise your hardware - * and to set up the interrupt handler in the right order. - * - * Dev_id must be globally unique. Normally the address of the - * device data structure is used as the cookie. Since the handler - * receives this value it makes sense to use it. - * - * If your interrupt is shared you must pass a non NULL dev_id - * as this is required when freeing the interrupt. - * - * Flags: - * - * SA_SHIRQ Interrupt is shared - * - * SA_INTERRUPT Disable local interrupts while processing - * - * SA_SAMPLE_RANDOM The interrupt can be used for entropy - * - */ -int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irq_flags, const char * devname, void *dev_id) -{ - unsigned long retval; - struct irqaction *action; - - if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler || - (irq_flags & SA_SHIRQ && !dev_id)) - return -EINVAL; - - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irq_flags; - cpus_clear(action->mask); - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = setup_irq(irq, action); - - if (retval) - kfree(action); - return retval; -} - -EXPORT_SYMBOL(request_irq); - -/** - * free_irq - free an interrupt - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * Remove an interrupt handler. The handler is removed and if the - * interrupt line is no longer in use by any driver it is disabled. - * On a shared IRQ the caller must ensure the interrupt is disabled - * on the card it drives before calling this function. - * - * This function must not be called from interrupt context. - */ -void free_irq(unsigned int irq, void *dev_id) -{ - struct irqaction * action, **p; - unsigned long flags; - - if (irq >= NR_IRQS || !irq_desc[irq].valid) { - printk(KERN_ERR "Trying to free IRQ%d\n",irq); - dump_stack(); - return; - } - - spin_lock_irqsave(&irq_controller_lock, flags); - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; - - /* Found it - now free it */ - *p = action->next; - break; - } - spin_unlock_irqrestore(&irq_controller_lock, flags); - - if (!action) { - printk(KERN_ERR "Trying to free free IRQ%d\n",irq); - dump_stack(); - } else { - synchronize_irq(irq); - kfree(action); - } -} - -EXPORT_SYMBOL(free_irq); - -static DECLARE_MUTEX(probe_sem); - -/* Start the interrupt probing. Unlike other architectures, - * we don't return a mask of interrupts from probe_irq_on, - * but return the number of interrupts enabled for the probe. - * The interrupts which have been enabled for probing is - * instead recorded in the irq_desc structure. - */ -unsigned long probe_irq_on(void) -{ - unsigned int i, irqs = 0; - unsigned long delay; - - down(&probe_sem); - - /* - * first snaffle up any unassigned but - * probe-able interrupts - */ - spin_lock_irq(&irq_controller_lock); - for (i = 0; i < NR_IRQS; i++) { - if (!irq_desc[i].probe_ok || irq_desc[i].action) - continue; - - irq_desc[i].probing = 1; - irq_desc[i].triggered = 0; - if (irq_desc[i].chip->set_type) - irq_desc[i].chip->set_type(i, IRQT_PROBE); - irq_desc[i].chip->unmask(i); - irqs += 1; - } - spin_unlock_irq(&irq_controller_lock); - - /* - * wait for spurious interrupts to mask themselves out again - */ - for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) - /* min 100ms delay */; - - /* - * now filter out any obviously spurious interrupts - */ - spin_lock_irq(&irq_controller_lock); - for (i = 0; i < NR_IRQS; i++) { - if (irq_desc[i].probing && irq_desc[i].triggered) { - irq_desc[i].probing = 0; - irqs -= 1; - } - } - spin_unlock_irq(&irq_controller_lock); - - return irqs; -} - -EXPORT_SYMBOL(probe_irq_on); - -unsigned int probe_irq_mask(unsigned long irqs) -{ - unsigned int mask = 0, i; - - spin_lock_irq(&irq_controller_lock); - for (i = 0; i < 16 && i < NR_IRQS; i++) - if (irq_desc[i].probing && irq_desc[i].triggered) - mask |= 1 << i; - spin_unlock_irq(&irq_controller_lock); - - up(&probe_sem); - - return mask; -} -EXPORT_SYMBOL(probe_irq_mask); - -/* - * Possible return values: - * >= 0 - interrupt number - * -1 - no interrupt/many interrupts - */ -int probe_irq_off(unsigned long irqs) -{ - unsigned int i; - int irq_found = NO_IRQ; - - /* - * look at the interrupts, and find exactly one - * that we were probing has been triggered - */ - spin_lock_irq(&irq_controller_lock); - for (i = 0; i < NR_IRQS; i++) { - if (irq_desc[i].probing && - irq_desc[i].triggered) { - if (irq_found != NO_IRQ) { - irq_found = NO_IRQ; - goto out; - } - irq_found = i; - } - } - - if (irq_found == -1) - irq_found = NO_IRQ; -out: - spin_unlock_irq(&irq_controller_lock); - - up(&probe_sem); - - return irq_found; -} - -EXPORT_SYMBOL(probe_irq_off); - -#ifdef CONFIG_SMP -static void route_irq(struct irqdesc *desc, unsigned int irq, unsigned int cpu) -{ - pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu); - - spin_lock_irq(&irq_controller_lock); - desc->cpu = cpu; - desc->chip->set_cpu(desc, irq, cpu); - spin_unlock_irq(&irq_controller_lock); -} - -#ifdef CONFIG_PROC_FS -static int -irq_affinity_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct irqdesc *desc = irq_desc + ((int)data); - int len = cpumask_scnprintf(page, count, desc->affinity); - - if (count - len < 2) - return -EINVAL; - page[len++] = '\n'; - page[len] = '\0'; - - return len; -} - -static int -irq_affinity_write_proc(struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - unsigned int irq = (unsigned int)data; - struct irqdesc *desc = irq_desc + irq; - cpumask_t affinity, tmp; - int ret = -EIO; - - if (!desc->chip->set_cpu) - goto out; - - ret = cpumask_parse(buffer, count, affinity); - if (ret) - goto out; - - cpus_and(tmp, affinity, cpu_online_map); - if (cpus_empty(tmp)) { - ret = -EINVAL; - goto out; - } - - desc->affinity = affinity; - route_irq(desc, irq, first_cpu(tmp)); - ret = count; - - out: - return ret; -} -#endif -#endif - -void __init init_irq_proc(void) -{ -#if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS) - struct proc_dir_entry *dir; - int irq; - - dir = proc_mkdir("irq", 0); - if (!dir) - return; - - for (irq = 0; irq < NR_IRQS; irq++) { - struct proc_dir_entry *entry; - struct irqdesc *desc; - char name[16]; - - desc = irq_desc + irq; - memset(name, 0, sizeof(name)); - snprintf(name, sizeof(name) - 1, "%u", irq); - - desc->procdir = proc_mkdir(name, dir); - if (!desc->procdir) - continue; - - entry = create_proc_entry("smp_affinity", 0600, desc->procdir); - if (entry) { - entry->nlink = 1; - entry->data = (void *)irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; - } - } -#endif + spin_lock_irqsave(&desc->lock, flags); + desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; + if (iflags & IRQF_VALID) + desc->status &= ~IRQ_NOREQUEST; + if (iflags & IRQF_PROBE) + desc->status &= ~IRQ_NOPROBE; + spin_unlock_irqrestore(&desc->lock, flags); } void __init init_IRQ(void) { - struct irqdesc *desc; extern void init_dma(void); int irq; + for (irq = 0; irq < NR_IRQS; irq++) + irq_desc[irq].status |= IRQ_NOREQUEST; + #ifdef CONFIG_SMP bad_irq_desc.affinity = CPU_MASK_ALL; bad_irq_desc.cpu = smp_processor_id(); #endif - for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) { - *desc = bad_irq_desc; - INIT_LIST_HEAD(&desc->pend); - } - init_arch_irq(); init_dma(); } - -static int __init noirqdebug_setup(char *str) -{ - noirqdebug = 1; - return 1; -} - -__setup("noirqdebug", noirqdebug_setup); Index: linux-2.6.14/include/asm-arm/dyntick.h =================================================================== --- /dev/null +++ linux-2.6.14/include/asm-arm/dyntick.h @@ -0,0 +1,6 @@ +#ifndef _ASMARM_DYNTICK_H +#define _ASMARM_DYNTICK_H + +#include + +#endif /* _ASMARM_DYNTICK_H */ Index: linux-2.6.14/include/asm-arm/hw_irq.h =================================================================== --- /dev/null +++ linux-2.6.14/include/asm-arm/hw_irq.h @@ -0,0 +1,9 @@ +/* + * Nothing to see here yet + */ +#ifndef _ARCH_ARM_HW_IRQ_H +#define _ARCH_ARM_HW_IRQ_H + +#include + +#endif Index: linux-2.6.14/include/asm-arm/irq.h =================================================================== --- linux-2.6.14.orig/include/asm-arm/irq.h +++ linux-2.6.14/include/asm-arm/irq.h @@ -19,16 +19,10 @@ #define NO_IRQ ((unsigned int)(-1)) #endif -struct irqaction; - -extern void disable_irq_nosync(unsigned int); -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -#define __IRQT_FALEDGE (1 << 0) -#define __IRQT_RISEDGE (1 << 1) -#define __IRQT_LOWLVL (1 << 2) -#define __IRQT_HIGHLVL (1 << 3) +#define __IRQT_FALEDGE IRQ_TYPE_EDGEL +#define __IRQT_RISEDGE IRQ_TYPE_EDGEH +#define __IRQT_LOWLVL IRQ_TYPE_LEVELL +#define __IRQT_HIGHLVL IRQ_TYPE_LEVELH #define IRQT_NOEDGE (0) #define IRQT_RISING (__IRQT_RISEDGE) @@ -36,16 +30,9 @@ extern void enable_irq(unsigned int); #define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE) #define IRQT_LOW (__IRQT_LOWLVL) #define IRQT_HIGH (__IRQT_HIGHLVL) -#define IRQT_PROBE (1 << 4) - -int set_irq_type(unsigned int irq, unsigned int type); -void disable_irq_wake(unsigned int irq); -void enable_irq_wake(unsigned int irq); -int setup_irq(unsigned int, struct irqaction *); -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); +/* FIXME_TGLX */ +#define IRQT_PROBE (1 << 7) #endif Index: linux-2.6.14/include/asm-arm/mach/irq.h =================================================================== --- linux-2.6.14.orig/include/asm-arm/mach/irq.h +++ linux-2.6.14/include/asm-arm/mach/irq.h @@ -10,94 +10,9 @@ #ifndef __ASM_ARM_MACH_IRQ_H #define __ASM_ARM_MACH_IRQ_H -struct irqdesc; -struct pt_regs; -struct seq_file; - -typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *); -typedef void (*irq_control_t)(unsigned int); +#include -struct irqchip { - /* - * Acknowledge the IRQ. - * If this is a level-based IRQ, then it is expected to mask the IRQ - * as well. - */ - void (*ack)(unsigned int); - /* - * Mask the IRQ in hardware. - */ - void (*mask)(unsigned int); - /* - * Unmask the IRQ in hardware. - */ - void (*unmask)(unsigned int); - /* - * Ask the hardware to re-trigger the IRQ. - * Note: This method _must_ _not_ call the interrupt handler. - * If you are unable to retrigger the interrupt, do not - * provide a function, or if you do, return non-zero. - */ - int (*retrigger)(unsigned int); - /* - * Set the type of the IRQ. - */ - int (*set_type)(unsigned int, unsigned int); - /* - * Set wakeup-enable on the selected IRQ - */ - int (*set_wake)(unsigned int, unsigned int); - -#ifdef CONFIG_SMP - /* - * Route an interrupt to a CPU - */ - void (*set_cpu)(struct irqdesc *desc, unsigned int irq, unsigned int cpu); -#endif -}; - -struct irqdesc { - irq_handler_t handle; - struct irqchip *chip; - struct irqaction *action; - struct list_head pend; - void *chipdata; - void *data; - unsigned int disable_depth; - - unsigned int triggered: 1; /* IRQ has occurred */ - unsigned int running : 1; /* IRQ is running */ - unsigned int pending : 1; /* IRQ is pending */ - unsigned int probing : 1; /* IRQ in use for a probe */ - unsigned int probe_ok : 1; /* IRQ can be used for probe */ - unsigned int valid : 1; /* IRQ claimable */ - unsigned int noautoenable : 1; /* don't automatically enable IRQ */ - unsigned int unused :25; - - struct proc_dir_entry *procdir; - -#ifdef CONFIG_SMP - cpumask_t affinity; - unsigned int cpu; -#endif - - /* - * IRQ lock detection - */ - unsigned int lck_cnt; - unsigned int lck_pc; - unsigned int lck_jif; -}; - -extern struct irqdesc irq_desc[]; - -/* - * Helpful inline function for calling irq descriptor handlers. - */ -static inline void desc_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) -{ - desc->handle(irq, desc, regs); -} +struct seq_file; /* * This is internal. Do not use it. @@ -105,31 +20,52 @@ static inline void desc_handle_irq(unsig extern void (*init_arch_irq)(void); extern void init_FIQ(void); extern int show_fiq_list(struct seq_file *, void *); -void __set_irq_handler(unsigned int irq, irq_handler_t, int); +void __set_irq_handler(unsigned int irq, struct irq_type *, int); /* * External stuff. */ #define set_irq_handler(irq,handler) __set_irq_handler(irq,handler,0) -#define set_irq_chained_handler(irq,handler) __set_irq_handler(irq,handler,1) -#define set_irq_data(irq,d) do { irq_desc[irq].data = d; } while (0) -#define set_irq_chipdata(irq,d) do { irq_desc[irq].chipdata = d; } while (0) -#define get_irq_chipdata(irq) (irq_desc[irq].chipdata) -void set_irq_chip(unsigned int irq, struct irqchip *); + +#define set_irq_chipdata(irq,d) set_irq_chip_data(irq, d) +#define get_irq_chipdata(irq) get_irq_chip_data(irq) + void set_irq_flags(unsigned int irq, unsigned int flags); #define IRQF_VALID (1 << 0) #define IRQF_PROBE (1 << 1) #define IRQF_NOAUTOEN (1 << 2) +/* ARM uses the retrigger functions in desc->chip or software retrigger */ +static inline void hw_resend_irq(struct irq_type *t, unsigned int i) {} + /* - * Built-in IRQ handlers. + * Hack alert. This is for easy migration, but should be changed in the source */ -void do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); -void do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); -void do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); -void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); -void dummy_mask_unmask_irq(unsigned int irq); +#define do_level_IRQ (&default_level_type) +#define do_edge_IRQ (&default_edge_type) +#define do_simple_IRQ (&default_simple_type) + +/* Hack to get around set_irq_chained_handler(nr,NULL) problem */ +#define irq_NULL_type no_irq_type +#define set_irq_chained_handler(irq,handler) \ + __set_irq_handler(irq,&irq_##handler##_type,1) + +#define DEFINE_IRQ_CHAINED_TYPE(function) \ +struct irq_type irq_##function##_type = { \ + .typename = #function"-chained_type", \ + .handle_irq = function, \ +} + +#define do_bad_IRQ(irq,desc,regs) \ +do { \ + spin_lock(&desc->lock); \ + handle_bad_irq(irq, desc, regs); \ + spin_unlock(&desc->lock); \ +} while(0) + +/* FIXME */ +#define ack_bad_irq(irq) do {} while (0) #endif Index: linux-2.6.14/arch/arm/common/locomo.c =================================================================== --- linux-2.6.14.orig/arch/arm/common/locomo.c +++ linux-2.6.14/arch/arm/common/locomo.c @@ -425,6 +425,12 @@ static struct irqchip locomo_spi_chip = .unmask = locomo_spi_unmask_irq, }; +static DEFINE_IRQ_CHAINED_TYPE(locomo_handler); +static DEFINE_IRQ_CHAINED_TYPE(locomo_key_handler); +static DEFINE_IRQ_CHAINED_TYPE(locomo_gpio_handler); +static DEFINE_IRQ_CHAINED_TYPE(locomo_lt_handler); +static DEFINE_IRQ_CHAINED_TYPE(locomo_spi_handler); + static void locomo_setup_irq(struct locomo *lchip) { int irq; Index: linux-2.6.14/arch/arm/common/sa1111.c =================================================================== --- linux-2.6.14.orig/arch/arm/common/sa1111.c +++ linux-2.6.14/arch/arm/common/sa1111.c @@ -141,7 +141,7 @@ static void sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { unsigned int stat0, stat1, i; - void __iomem *base = desc->data; + void __iomem *base = desc->handler_data; stat0 = sa1111_readl(base + SA1111_INTSTATCLR0); stat1 = sa1111_readl(base + SA1111_INTSTATCLR1); @@ -159,11 +159,11 @@ sa1111_irq_handler(unsigned int irq, str for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) if (stat0 & 1) - do_edge_IRQ(i, irq_desc + i, regs); + handle_edge_irq(i, irq_desc + i, regs); for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) if (stat1 & 1) - do_edge_IRQ(i, irq_desc + i, regs); + handle_edge_irq(i, irq_desc + i, regs); /* For level-based interrupts */ desc->chip->unmask(irq); @@ -368,6 +368,8 @@ static struct irqchip sa1111_high_chip = .set_wake = sa1111_wake_highirq, }; +static DEFINE_IRQ_CHAINED_TYPE(sa1111_irq_handler); + static void sa1111_setup_irq(struct sa1111 *sachip) { void __iomem *irqbase = sachip->base + SA1111_INTC; Index: linux-2.6.14/arch/arm/common/time-acorn.c =================================================================== --- linux-2.6.14.orig/arch/arm/common/time-acorn.c +++ linux-2.6.14/arch/arm/common/time-acorn.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/kernel/ecard.c =================================================================== --- linux-2.6.14.orig/arch/arm/kernel/ecard.c +++ linux-2.6.14/arch/arm/kernel/ecard.c @@ -619,7 +619,7 @@ ecard_irqexp_handler(unsigned int irq, s ecard_t *ec = slot_to_ecard(slot); if (ec->claimed) { - struct irqdesc *d = irqdesc + ec->irq; + struct irqdesc *d = irq_desc + ec->irq; /* * this ugly code is so that we can operate a * prioritorising system: @@ -1052,6 +1052,9 @@ ecard_probe(int slot, card_type_t type) return rc; } +static DEFINE_IRQ_CHAINED_TYPE(ecard_irqexp_handler); +static DEFINE_IRQ_CHAINED_TYPE(ecard_irq_handler); + /* * Initialise the expansion card system. * Locate all hardware - interrupt management and @@ -1081,8 +1084,10 @@ static int __init ecard_init(void) irqhw = ecard_probeirqhw(); - set_irq_chained_handler(IRQ_EXPANSIONCARD, - irqhw ? ecard_irqexp_handler : ecard_irq_handler); + if (irqhw) + set_irq_chained_handler(IRQ_EXPANSIONCARD, ecard_irqexp_handler); + else + set_irq_chained_handler(IRQ_EXPANSIONCARD, ecard_irq_handler); ecard_proc_init(); Index: linux-2.6.14/arch/arm/mach-clps711x/time.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-clps711x/time.c +++ linux-2.6.14/arch/arm/mach-clps711x/time.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-clps7500/core.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-clps7500/core.c +++ linux-2.6.14/arch/arm/mach-clps7500/core.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include Index: linux-2.6.14/arch/arm/mach-footbridge/dc21285-timer.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-footbridge/dc21285-timer.c +++ linux-2.6.14/arch/arm/mach-footbridge/dc21285-timer.c @@ -6,6 +6,7 @@ */ #include #include +#include #include Index: linux-2.6.14/arch/arm/mach-footbridge/isa-irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-footbridge/isa-irq.c +++ linux-2.6.14/arch/arm/mach-footbridge/isa-irq.c @@ -102,6 +102,17 @@ static struct irqaction irq_cascade = { static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; +static DEFINE_IRQ_CHAINED_TYPE(isa_irq_handler); + +static unsigned int startup_irq_disabled(unsigned int irq) +{ + return 0; +} + +/* Interrupt type for irqs which must not be + * automatically enabled in reqeust_irq */ +static struct irq_type level_type_nostart; + void __init isa_init_irq(unsigned int host_irq) { unsigned int irq; @@ -159,9 +170,11 @@ void __init isa_init_irq(unsigned int ho * There appears to be a missing pull-up * resistor on this line. */ - if (machine_is_netwinder()) - set_irq_flags(_ISA_IRQ(11), IRQF_VALID | - IRQF_PROBE | IRQF_NOAUTOEN); + if (machine_is_netwinder()) { + level_type_nostart = default_level_type; + level_type_nostart.startup = startup_irq_disabled; + set_irq_handler(_ISA_IRQ(11), &level_type_nostart); + } } } Index: linux-2.6.14/arch/arm/mach-footbridge/isa-timer.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-footbridge/isa-timer.c +++ linux-2.6.14/arch/arm/mach-footbridge/isa-timer.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-h720x/common.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-h720x/common.c +++ linux-2.6.14/arch/arm/mach-h720x/common.c @@ -163,6 +163,11 @@ h720x_gpiod_demux_handler(unsigned int i h720x_gpio_handler(mask, irq, desc, regs); } +static DEFINE_IRQ_CHAINED_TYPE(h720x_gpioa_demux_handler); +static DEFINE_IRQ_CHAINED_TYPE(h720x_gpiob_demux_handler); +static DEFINE_IRQ_CHAINED_TYPE(h720x_gpioc_demux_handler); +static DEFINE_IRQ_CHAINED_TYPE(h720x_gpiod_demux_handler); + #ifdef CONFIG_CPU_H7202 static void h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc, @@ -175,6 +180,7 @@ h720x_gpioe_demux_handler(unsigned int i IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq); h720x_gpio_handler(mask, irq, desc, regs); } +static DEFINE_IRQ_CHAINED_TYPE(h720x_gpioe_demux_handler); #endif static struct irqchip h720x_global_chip = { Index: linux-2.6.14/arch/arm/mach-h720x/cpu-h7202.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-h720x/cpu-h7202.c +++ linux-2.6.14/arch/arm/mach-h720x/cpu-h7202.c @@ -175,6 +175,8 @@ static struct irqaction h7202_timer_irq .handler = h7202_timer_interrupt, }; +static DEFINE_IRQ_CHAINED_TYPE(h7202_timerx_demux_handler); + /* * Setup TIMER0 as system timer */ Index: linux-2.6.14/arch/arm/mach-imx/irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-imx/irq.c +++ linux-2.6.14/arch/arm/mach-imx/irq.c @@ -217,6 +217,11 @@ static struct irqchip imx_gpio_chip = { .set_type = imx_gpio_irq_type, }; +static DEFINE_IRQ_CHAINED_TYPE(imx_gpioa_demux_handler); +static DEFINE_IRQ_CHAINED_TYPE(imx_gpiob_demux_handler); +static DEFINE_IRQ_CHAINED_TYPE(imx_gpioc_demux_handler); +static DEFINE_IRQ_CHAINED_TYPE(imx_gpiod_demux_handler); + void __init imx_init_irq(void) { Index: linux-2.6.14/arch/arm/mach-imx/time.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-imx/time.c +++ linux-2.6.14/arch/arm/mach-imx/time.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-integrator/core.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-integrator/core.c +++ linux-2.6.14/arch/arm/mach-integrator/core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-ixp2000/core.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-ixp2000/core.c +++ linux-2.6.14/arch/arm/mach-ixp2000/core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -288,7 +289,7 @@ void gpio_line_config(int line, int dire local_irq_save(flags); if (direction == GPIO_OUT) { - irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0; + set_irq_flags(line + IRQ_IXP2000_GPIO0, 0); /* if it's an output, it ain't an interrupt anymore */ GPIO_IRQ_falling_edge &= ~(1 << line); @@ -354,8 +355,7 @@ static int ixp2000_GPIO_irq_type(unsigne /* * Finally, mark the corresponding IRQ as valid. */ - irq_desc[irq].valid = 1; - + set_irq_flags(irq, IRQF_VALID); return 0; } @@ -425,6 +425,8 @@ static struct irqchip ixp2000_irq_chip = .unmask = ixp2000_irq_unmask }; +static DEFINE_IRQ_CHAINED_TYPE(ixp2000_GPIO_irq_handler); + void __init ixp2000_init_irq(void) { int irq; Index: linux-2.6.14/arch/arm/mach-ixp2000/ixdp2x00.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-ixp2000/ixdp2x00.c +++ linux-2.6.14/arch/arm/mach-ixp2000/ixdp2x00.c @@ -146,6 +146,8 @@ static struct irqchip ixdp2x00_cpld_irq_ .unmask = ixdp2x00_irq_unmask }; +static DEFINE_IRQ_CHAINED_TYPE(ixdp2x00_irq_handler); + void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs) { unsigned int irq; @@ -168,7 +170,7 @@ void ixdp2x00_init_irq(volatile unsigned } /* Hook into PCI interrupt */ - set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x00_irq_handler); + set_irq_chained_handler(IRQ_IXP2000_PCIB, ixdp2x00_irq_handler); } /************************************************************************* Index: linux-2.6.14/arch/arm/mach-ixp2000/ixdp2x01.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-ixp2000/ixdp2x01.c +++ linux-2.6.14/arch/arm/mach-ixp2000/ixdp2x01.c @@ -95,6 +95,8 @@ static struct irqchip ixdp2x01_irq_chip .unmask = ixdp2x01_irq_unmask }; +static DEFINE_IRQ_CHAINED_TYPE(ixdp2x01_irq_handler); + /* * We only do anything if we are the master NPU on the board. * The slave NPU only has the ethernet chip going directly to @@ -127,7 +129,7 @@ void __init ixdp2x01_init_irq(void) } /* Hook into PCI interrupts */ - set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler); + set_irq_chained_handler(IRQ_IXP2000_PCIB, ixdp2x01_irq_handler); } Index: linux-2.6.14/arch/arm/mach-ixp4xx/coyote-pci.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-ixp4xx/coyote-pci.c +++ linux-2.6.14/arch/arm/mach-ixp4xx/coyote-pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-ixp4xx/ixdp425-pci.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-ixp4xx/ixdp425-pci.c +++ linux-2.6.14/arch/arm/mach-ixp4xx/ixdp425-pci.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include Index: linux-2.6.14/arch/arm/mach-l7200/core.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-l7200/core.c +++ linux-2.6.14/arch/arm/mach-l7200/core.c @@ -7,6 +7,7 @@ */ #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-lh7a40x/arch-kev7a400.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-lh7a40x/arch-kev7a400.c +++ linux-2.6.14/arch/arm/mach-lh7a40x/arch-kev7a400.c @@ -72,6 +72,8 @@ static void kev7a400_cpld_handler (unsig } } +static DEFINE_IRQ_CHAINED_TYPE(kev7a400_cpld_handler); + void __init lh7a40x_init_board_irq (void) { int irq; Index: linux-2.6.14/arch/arm/mach-lh7a40x/arch-lpd7a40x.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ linux-2.6.14/arch/arm/mach-lh7a40x/arch-lpd7a40x.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -173,6 +174,7 @@ static void lpd7a40x_cpld_handler (unsig desc->chip->unmask (irq); /* Level-triggered need this */ } +static DEFINE_IRQ_CHAINED_TYPE(lpd7a40x_cpld_handler); void __init lh7a40x_init_board_irq (void) { Index: linux-2.6.14/arch/arm/mach-lh7a40x/irq-kev7a400.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-lh7a40x/irq-kev7a400.c +++ linux-2.6.14/arch/arm/mach-lh7a40x/irq-kev7a400.c @@ -60,6 +60,8 @@ lh7a400_cpld_handler (unsigned int irq, } } +static DEFINE_IRQ_CHAINED_TYPE(kev7a400_cpld_handler); + /* IRQ initialization */ void __init Index: linux-2.6.14/arch/arm/mach-lh7a40x/irq-lpd7a40x.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-lh7a40x/irq-lpd7a40x.c +++ linux-2.6.14/arch/arm/mach-lh7a40x/irq-lpd7a40x.c @@ -71,6 +71,7 @@ static void lh7a40x_cpld_handler (unsign desc->chip->unmask (irq); /* Level-triggered need this */ } +static DEFINE_IRQ_CHAINED_TYPE(lh7a40x_cpld_handler); /* IRQ initialization */ Index: linux-2.6.14/arch/arm/mach-lh7a40x/time.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-lh7a40x/time.c +++ linux-2.6.14/arch/arm/mach-lh7a40x/time.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-omap1/fpga.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-omap1/fpga.c +++ linux-2.6.14/arch/arm/mach-omap1/fpga.c @@ -120,6 +120,8 @@ static struct irqchip omap_fpga_irq = { .unmask = fpga_unmask_irq, }; +static DEFINE_IRQ_CHAINED_TYPE(innovator_fpga_IRQ_demux); + /* * All of the FPGA interrupt request inputs except for the touchscreen are * edge-sensitive; the touchscreen is level-sensitive. The edge-sensitive Index: linux-2.6.14/arch/arm/mach-omap1/serial.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-omap1/serial.c +++ linux-2.6.14/arch/arm/mach-omap1/serial.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include Index: linux-2.6.14/arch/arm/mach-pxa/idp.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-pxa/idp.c +++ linux-2.6.14/arch/arm/mach-pxa/idp.c @@ -18,6 +18,7 @@ #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-pxa/irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-pxa/irq.c +++ linux-2.6.14/arch/arm/mach-pxa/irq.c @@ -244,6 +244,7 @@ static struct irqchip pxa_muxed_gpio_chi .set_type = pxa_gpio_irq_type, }; +static DEFINE_IRQ_CHAINED_TYPE(pxa_gpio_demux_handler); void __init pxa_init_irq(void) { Index: linux-2.6.14/arch/arm/mach-pxa/lubbock.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-pxa/lubbock.c +++ linux-2.6.14/arch/arm/mach-pxa/lubbock.c @@ -90,6 +90,8 @@ static void lubbock_irq_handler(unsigned } while (pending); } +static DEFINE_IRQ_CHAINED_TYPE(lubbock_irq_handler); + static void __init lubbock_init_irq(void) { int irq; Index: linux-2.6.14/arch/arm/mach-pxa/mainstone.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-pxa/mainstone.c +++ linux-2.6.14/arch/arm/mach-pxa/mainstone.c @@ -78,6 +78,8 @@ static void mainstone_irq_handler(unsign } while (pending); } +static DEFINE_IRQ_CHAINED_TYPE(mainstone_irq_handler); + static void __init mainstone_init_irq(void) { int irq; Index: linux-2.6.14/arch/arm/mach-rpc/irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-rpc/irq.c +++ linux-2.6.14/arch/arm/mach-rpc/irq.c @@ -112,6 +112,15 @@ static struct irqchip iomd_fiq_chip = { .unmask = iomd_unmask_irq_fiq, }; +static unsigned int startup_irq_disabled(unsigned int irq) +{ + return 0; +} + +/* Interrupt type for irqs which must not be + * automatically enabled in reqeust_irq */ +static struct irq_type level_type_nostart; + void __init rpc_init_irq(void) { unsigned int irq, flags; @@ -121,16 +130,15 @@ void __init rpc_init_irq(void) iomd_writeb(0, IOMD_FIQMASK); iomd_writeb(0, IOMD_DMAMASK); + level_type_nostart = default_level_type; + level_type_nostart.startup = startup_irq_disabled; + for (irq = 0; irq < NR_IRQS; irq++) { flags = IRQF_VALID; if (irq <= 6 || (irq >= 9 && irq <= 15)) flags |= IRQF_PROBE; - if (irq == 21 || (irq >= 16 && irq <= 19) || - irq == IRQ_KEYBOARDTX) - flags |= IRQF_NOAUTOEN; - switch (irq) { case 0 ... 7: set_irq_chip(irq, &iomd_a_chip); @@ -155,6 +163,10 @@ void __init rpc_init_irq(void) set_irq_flags(irq, IRQF_VALID); break; } + + if (irq == 21 || (irq >= 16 && irq <= 19) || + irq == IRQ_KEYBOARDTX) + set_irq_handler(irq, &level_type_nostart); } init_FIQ(); Index: linux-2.6.14/arch/arm/mach-s3c2410/bast-irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-s3c2410/bast-irq.c +++ linux-2.6.14/arch/arm/mach-s3c2410/bast-irq.c @@ -136,13 +136,15 @@ bast_irq_pc104_demux(unsigned int irq, for (i = 0; stat != 0; i++, stat >>= 1) { if (stat & 1) { irqno = bast_pc104_irqs[i]; - - desc_handle_irq(irqno, irq_desc + irqno, regs); + desc = irq_desc + irqno; + desc_handle_irq(irqno, desc, regs); } } } } +DEFINE_IRQ_CHAINED_TYPE(bast_irq_pc104_demux); + static __init int bast_irq_init(void) { unsigned int i; @@ -156,7 +158,7 @@ static __init int bast_irq_init(void) set_irq_chained_handler(IRQ_ISA, bast_irq_pc104_demux); - /* reigster our IRQs */ + /* register our IRQs */ for (i = 0; i < 4; i++) { unsigned int irqno = bast_pc104_irqs[i]; Index: linux-2.6.14/arch/arm/mach-s3c2410/irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-s3c2410/irq.c +++ linux-2.6.14/arch/arm/mach-s3c2410/irq.c @@ -573,6 +573,11 @@ s3c_irq_demux_uart2(unsigned int irq, } +static DEFINE_IRQ_CHAINED_TYPE(s3c_irq_demux_uart0); +static DEFINE_IRQ_CHAINED_TYPE(s3c_irq_demux_uart1); +static DEFINE_IRQ_CHAINED_TYPE(s3c_irq_demux_uart2); +static DEFINE_IRQ_CHAINED_TYPE(s3c_irq_demux_adc); + /* s3c24xx_init_irq * * Initialise S3C2410 IRQ system Index: linux-2.6.14/arch/arm/mach-s3c2410/s3c2440-irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-s3c2410/s3c2440-irq.c +++ linux-2.6.14/arch/arm/mach-s3c2410/s3c2440-irq.c @@ -157,6 +157,9 @@ static struct irqchip s3c_irq_cam = { .ack = s3c_irq_cam_ack, }; +static DEFINE_IRQ_CHAINED_TYPE(s3c_irq_demux_wdtac97); +static DEFINE_IRQ_CHAINED_TYPE(s3c_irq_demux_cam); + static int s3c2440_irq_add(struct sys_device *sysdev) { unsigned int irqno; Index: linux-2.6.14/arch/arm/mach-s3c2410/time.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-s3c2410/time.c +++ linux-2.6.14/arch/arm/mach-s3c2410/time.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-sa1100/cerf.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-sa1100/cerf.c +++ linux-2.6.14/arch/arm/mach-sa1100/cerf.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-sa1100/h3600.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-sa1100/h3600.c +++ linux-2.6.14/arch/arm/mach-sa1100/h3600.c @@ -788,6 +788,8 @@ static void h3800_unmask_gpio_irq(unsign H3800_ASIC2_GPIINTSTAT |= mask; } +static DEFINE_IRQ_CHAINED_TYPE(h3800_IRQ_demux); + static void __init h3800_init_irq(void) { int i; @@ -826,7 +828,7 @@ static void __init h3800_init_irq(void) } #endif set_irq_type(IRQ_GPIO_H3800_ASIC, IRQT_RISING); - set_irq_chained_handler(IRQ_GPIO_H3800_ASIC, &h3800_IRQ_demux); + set_irq_chained_handler(IRQ_GPIO_H3800_ASIC, h3800_IRQ_demux); } Index: linux-2.6.14/arch/arm/mach-sa1100/irq.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-sa1100/irq.c +++ linux-2.6.14/arch/arm/mach-sa1100/irq.c @@ -11,12 +11,13 @@ */ #include #include +#include +#include #include #include #include #include -#include #include #include "generic.h" @@ -281,6 +282,8 @@ static int __init sa1100irq_init_devicef return sysdev_register(&sa1100irq_device); } +static DEFINE_IRQ_CHAINED_TYPE(sa1100_high_gpio_handler); + device_initcall(sa1100irq_init_devicefs); void __init sa1100_init_irq(void) Index: linux-2.6.14/arch/arm/mach-sa1100/neponset.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-sa1100/neponset.c +++ linux-2.6.14/arch/arm/mach-sa1100/neponset.c @@ -137,6 +137,8 @@ static struct sa1100_port_fns neponset_p .get_mctrl = neponset_get_mctrl, }; +static DEFINE_IRQ_CHAINED_TYPE(neponset_irq_handler); + static int neponset_probe(struct device *dev) { sa1100_register_uart_fns(&neponset_port_fns); Index: linux-2.6.14/arch/arm/mach-sa1100/pleb.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-sa1100/pleb.c +++ linux-2.6.14/arch/arm/mach-sa1100/pleb.c @@ -7,6 +7,7 @@ #include #include #include +#include #include Index: linux-2.6.14/arch/arm/mach-sa1100/time.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-sa1100/time.c +++ linux-2.6.14/arch/arm/mach-sa1100/time.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-shark/core.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-shark/core.c +++ linux-2.6.14/arch/arm/mach-shark/core.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/arch/arm/mach-versatile/core.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-versatile/core.c +++ linux-2.6.14/arch/arm/mach-versatile/core.c @@ -112,6 +112,8 @@ sic_handle_irq(unsigned int irq, struct } while (status); } +static DEFINE_IRQ_CHAINED_TYPE(sic_handle_irq); + #if 1 #define IRQ_MMCI0A IRQ_VICSOURCE22 #define IRQ_AACI IRQ_VICSOURCE24 @@ -161,7 +163,7 @@ void __init versatile_init_irq(void) } } - set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq); + set_irq_chained_handler(IRQ_VICSOURCE31, sic_handle_irq); vic_unmask_irq(IRQ_VICSOURCE31); /* Do second interrupt controller */ Index: linux-2.6.14/arch/arm/plat-omap/gpio.c =================================================================== --- linux-2.6.14.orig/arch/arm/plat-omap/gpio.c +++ linux-2.6.14/arch/arm/plat-omap/gpio.c @@ -736,7 +736,7 @@ static void gpio_irq_handler(unsigned in desc->chip->ack(irq); - bank = (struct gpio_bank *) desc->data; + bank = (struct gpio_bank *) desc->handler_data; if (bank->method == METHOD_MPUIO) isr_reg = bank->base + OMAP_MPUIO_GPIO_INT; #ifdef CONFIG_ARCH_OMAP1510 @@ -837,6 +837,8 @@ static struct irqchip mpuio_irq_chip = { .unmask = mpuio_unmask_irq }; +static DEFINE_IRQ_CHAINED_TYPE(gpio_irq_handler); + static int initialized = 0; static struct clk * gpio_ck = NULL; Index: linux-2.6.14/arch/arm/mach-ixp4xx/gtwx5715-pci.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-ixp4xx/gtwx5715-pci.c +++ linux-2.6.14/arch/arm/mach-ixp4xx/gtwx5715-pci.c @@ -25,9 +25,9 @@ #include #include #include +#include #include #include -#include #include #include Index: linux-2.6.14/arch/arm/mach-ixp4xx/ixdpg425-pci.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-ixp4xx/ixdpg425-pci.c +++ linux-2.6.14/arch/arm/mach-ixp4xx/ixdpg425-pci.c @@ -16,10 +16,10 @@ #include #include #include +#include #include #include -#include #include Index: linux-2.6.14/arch/arm/mach-omap1/board-osk.c =================================================================== --- linux-2.6.14.orig/arch/arm/mach-omap1/board-osk.c +++ linux-2.6.14/arch/arm/mach-omap1/board-osk.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include Index: linux-2.6.14/drivers/char/s3c2410-rtc.c =================================================================== --- linux-2.6.14.orig/drivers/char/s3c2410-rtc.c +++ linux-2.6.14/drivers/char/s3c2410-rtc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/drivers/i2c/chips/tps65010.c =================================================================== --- linux-2.6.14.orig/drivers/i2c/chips/tps65010.c +++ linux-2.6.14/drivers/i2c/chips/tps65010.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include -#include #include #include Index: linux-2.6.14/drivers/input/serio/sa1111ps2.c =================================================================== --- linux-2.6.14.orig/drivers/input/serio/sa1111ps2.c +++ linux-2.6.14/drivers/input/serio/sa1111ps2.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include Index: linux-2.6.14/drivers/net/smc91x.c =================================================================== --- linux-2.6.14.orig/drivers/net/smc91x.c +++ linux-2.6.14/drivers/net/smc91x.c @@ -74,6 +74,7 @@ static const char version[] = #include #include #include +#include #include #include #include @@ -1998,7 +1999,7 @@ static int __init smc_probe(struct net_d if (retval) goto err_out; - set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE); + SMC_SET_IRQ_TYPE(dev->irq, SMC_IRQ_TRIGGER_TYPE); #ifdef SMC_USE_PXA_DMA { Index: linux-2.6.14/drivers/net/smc91x.h =================================================================== --- linux-2.6.14.orig/drivers/net/smc91x.h +++ linux-2.6.14/drivers/net/smc91x.h @@ -90,7 +90,7 @@ __l--; \ } \ } while (0) -#define set_irq_type(irq, type) +#define SMC_SET_IRQ_TYPE(irq, type) #elif defined(CONFIG_SA1100_PLEB) /* We can only do 16-bit reads and writes in the static memory space. */ @@ -109,7 +109,7 @@ #define SMC_outw(v, a, r) outw(v, (a) + (r)) #define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) -#define set_irq_type(irq, type) do {} while (0) +#define SMC_SET_IRQ_TYPE(irq, type) do {} while (0) #elif defined(CONFIG_SA1100_ASSABET) @@ -209,7 +209,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, #define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) -#define set_irq_type(irq, type) do {} while(0) +#define SMC_SET_IRQ_TYPE(irq, type) do {} while(0) #elif defined(CONFIG_ISA) @@ -237,7 +237,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, #define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) -#define set_irq_type(irq, type) do {} while(0) +#define SMC_SET_IRQ_TYPE(irq, type) do {} while(0) #define RPC_LSA_DEFAULT RPC_LED_TX_RX #define RPC_LSB_DEFAULT RPC_LED_100_10 @@ -310,6 +310,10 @@ static inline void SMC_outsw (unsigned l #endif +#ifndef SMC_SET_IRQ_TYPE +#define SMC_SET_IRQ_TYPE set_irq_type +#endif + #ifndef SMC_IRQ_TRIGGER_TYPE #define SMC_IRQ_TRIGGER_TYPE IRQT_RISING #endif Index: linux-2.6.14/drivers/pcmcia/soc_common.c =================================================================== --- linux-2.6.14.orig/drivers/pcmcia/soc_common.c +++ linux-2.6.14/drivers/pcmcia/soc_common.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include Index: linux-2.6.14/drivers/input/keyboard/corgikbd.c =================================================================== --- linux-2.6.14.orig/drivers/input/keyboard/corgikbd.c +++ linux-2.6.14/drivers/input/keyboard/corgikbd.c @@ -16,10 +16,11 @@ #include #include #include +#include +#include #include #include #include -#include #include #include Index: linux-2.6.14/drivers/input/keyboard/spitzkbd.c =================================================================== --- linux-2.6.14.orig/drivers/input/keyboard/spitzkbd.c +++ linux-2.6.14/drivers/input/keyboard/spitzkbd.c @@ -16,10 +16,10 @@ #include #include #include +#include #include #include #include -#include #include #include Index: linux-2.6.14/drivers/input/touchscreen/corgi_ts.c =================================================================== --- linux-2.6.14.orig/drivers/input/touchscreen/corgi_ts.c +++ linux-2.6.14/drivers/input/touchscreen/corgi_ts.c @@ -15,9 +15,9 @@ #include #include #include +#include #include #include -#include #include #include Index: linux-2.6.14/drivers/serial/imx.c =================================================================== --- linux-2.6.14.orig/drivers/serial/imx.c +++ linux-2.6.14/drivers/serial/imx.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include Index: linux-2.6.14/Makefile =================================================================== --- linux-2.6.14.orig/Makefile +++ linux-2.6.14/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 14 -EXTRAVERSION = +EXTRAVERSION =-armirq3 NAME=Affluent Albatross # *DOCUMENTATION*