162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Code to handle x86 style IRQs plus some generic interrupt stuff. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 1992 Linus Torvalds 962306a36Sopenharmony_ci * Copyright (C) 1994 - 2000 Ralf Baechle 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/ioport.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/irqchip.h> 1662306a36Sopenharmony_ci#include <linux/irqdomain.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/of_irq.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <linux/syscore_ops.h> 2162306a36Sopenharmony_ci#include <linux/irq.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <asm/i8259.h> 2462306a36Sopenharmony_ci#include <asm/io.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * This is the 'legacy' 8259A Programmable Interrupt Controller, 2862306a36Sopenharmony_ci * present in the majority of PC/AT boxes. 2962306a36Sopenharmony_ci * plus some generic x86 specific things if generic specifics makes 3062306a36Sopenharmony_ci * any sense at all. 3162306a36Sopenharmony_ci * this file should become arch/i386/kernel/irq.c when the old irq.c 3262306a36Sopenharmony_ci * moves to arch independent land 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int i8259A_auto_eoi = -1; 3662306a36Sopenharmony_ciDEFINE_RAW_SPINLOCK(i8259A_lock); 3762306a36Sopenharmony_cistatic void disable_8259A_irq(struct irq_data *d); 3862306a36Sopenharmony_cistatic void enable_8259A_irq(struct irq_data *d); 3962306a36Sopenharmony_cistatic void mask_and_ack_8259A(struct irq_data *d); 4062306a36Sopenharmony_cistatic void init_8259A(int auto_eoi); 4162306a36Sopenharmony_cistatic int (*i8259_poll)(void) = i8259_irq; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic struct irq_chip i8259A_chip = { 4462306a36Sopenharmony_ci .name = "XT-PIC", 4562306a36Sopenharmony_ci .irq_mask = disable_8259A_irq, 4662306a36Sopenharmony_ci .irq_disable = disable_8259A_irq, 4762306a36Sopenharmony_ci .irq_unmask = enable_8259A_irq, 4862306a36Sopenharmony_ci .irq_mask_ack = mask_and_ack_8259A, 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * 8259A PIC functions to handle ISA devices: 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid i8259_set_poll(int (*poll)(void)) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci i8259_poll = poll; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * This contains the irq mask for both 8259A irq controllers, 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cistatic unsigned int cached_irq_mask = 0xffff; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define cached_master_mask (cached_irq_mask) 6662306a36Sopenharmony_ci#define cached_slave_mask (cached_irq_mask >> 8) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void disable_8259A_irq(struct irq_data *d) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; 7162306a36Sopenharmony_ci unsigned long flags; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci mask = 1 << irq; 7462306a36Sopenharmony_ci raw_spin_lock_irqsave(&i8259A_lock, flags); 7562306a36Sopenharmony_ci cached_irq_mask |= mask; 7662306a36Sopenharmony_ci if (irq & 8) 7762306a36Sopenharmony_ci outb(cached_slave_mask, PIC_SLAVE_IMR); 7862306a36Sopenharmony_ci else 7962306a36Sopenharmony_ci outb(cached_master_mask, PIC_MASTER_IMR); 8062306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&i8259A_lock, flags); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void enable_8259A_irq(struct irq_data *d) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; 8662306a36Sopenharmony_ci unsigned long flags; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci mask = ~(1 << irq); 8962306a36Sopenharmony_ci raw_spin_lock_irqsave(&i8259A_lock, flags); 9062306a36Sopenharmony_ci cached_irq_mask &= mask; 9162306a36Sopenharmony_ci if (irq & 8) 9262306a36Sopenharmony_ci outb(cached_slave_mask, PIC_SLAVE_IMR); 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci outb(cached_master_mask, PIC_MASTER_IMR); 9562306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&i8259A_lock, flags); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid make_8259A_irq(unsigned int irq) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci disable_irq_nosync(irq); 10162306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq); 10262306a36Sopenharmony_ci enable_irq(irq); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * This function assumes to be called rarely. Switching between 10762306a36Sopenharmony_ci * 8259A registers is slow. 10862306a36Sopenharmony_ci * This has to be protected by the irq controller spinlock 10962306a36Sopenharmony_ci * before being called. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_cistatic inline int i8259A_irq_real(unsigned int irq) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int value; 11462306a36Sopenharmony_ci int irqmask = 1 << irq; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (irq < 8) { 11762306a36Sopenharmony_ci outb(0x0B, PIC_MASTER_CMD); /* ISR register */ 11862306a36Sopenharmony_ci value = inb(PIC_MASTER_CMD) & irqmask; 11962306a36Sopenharmony_ci outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */ 12062306a36Sopenharmony_ci return value; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci outb(0x0B, PIC_SLAVE_CMD); /* ISR register */ 12362306a36Sopenharmony_ci value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); 12462306a36Sopenharmony_ci outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */ 12562306a36Sopenharmony_ci return value; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* 12962306a36Sopenharmony_ci * Careful! The 8259A is a fragile beast, it pretty 13062306a36Sopenharmony_ci * much _has_ to be done exactly like this (mask it 13162306a36Sopenharmony_ci * first, _then_ send the EOI, and the order of EOI 13262306a36Sopenharmony_ci * to the two 8259s is important! 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_cistatic void mask_and_ack_8259A(struct irq_data *d) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE; 13762306a36Sopenharmony_ci unsigned long flags; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci irqmask = 1 << irq; 14062306a36Sopenharmony_ci raw_spin_lock_irqsave(&i8259A_lock, flags); 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * Lightweight spurious IRQ detection. We do not want 14362306a36Sopenharmony_ci * to overdo spurious IRQ handling - it's usually a sign 14462306a36Sopenharmony_ci * of hardware problems, so we only do the checks we can 14562306a36Sopenharmony_ci * do without slowing down good hardware unnecessarily. 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * Note that IRQ7 and IRQ15 (the two spurious IRQs 14862306a36Sopenharmony_ci * usually resulting from the 8259A-1|2 PICs) occur 14962306a36Sopenharmony_ci * even if the IRQ is masked in the 8259A. Thus we 15062306a36Sopenharmony_ci * can check spurious 8259A IRQs without doing the 15162306a36Sopenharmony_ci * quite slow i8259A_irq_real() call for every IRQ. 15262306a36Sopenharmony_ci * This does not cover 100% of spurious interrupts, 15362306a36Sopenharmony_ci * but should be enough to warn the user that there 15462306a36Sopenharmony_ci * is something bad going on ... 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (cached_irq_mask & irqmask) 15762306a36Sopenharmony_ci goto spurious_8259A_irq; 15862306a36Sopenharmony_ci cached_irq_mask |= irqmask; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cihandle_real_irq: 16162306a36Sopenharmony_ci if (irq & 8) { 16262306a36Sopenharmony_ci inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ 16362306a36Sopenharmony_ci outb(cached_slave_mask, PIC_SLAVE_IMR); 16462306a36Sopenharmony_ci outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ 16562306a36Sopenharmony_ci outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ 16662306a36Sopenharmony_ci } else { 16762306a36Sopenharmony_ci inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ 16862306a36Sopenharmony_ci outb(cached_master_mask, PIC_MASTER_IMR); 16962306a36Sopenharmony_ci outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&i8259A_lock, flags); 17262306a36Sopenharmony_ci return; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cispurious_8259A_irq: 17562306a36Sopenharmony_ci /* 17662306a36Sopenharmony_ci * this is the slow path - should happen rarely. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci if (i8259A_irq_real(irq)) 17962306a36Sopenharmony_ci /* 18062306a36Sopenharmony_ci * oops, the IRQ _is_ in service according to the 18162306a36Sopenharmony_ci * 8259A - not spurious, go handle it. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci goto handle_real_irq; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci { 18662306a36Sopenharmony_ci static int spurious_irq_mask; 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * At this point we can be sure the IRQ is spurious, 18962306a36Sopenharmony_ci * lets ACK and report it. [once per IRQ] 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci if (!(spurious_irq_mask & irqmask)) { 19262306a36Sopenharmony_ci printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); 19362306a36Sopenharmony_ci spurious_irq_mask |= irqmask; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci atomic_inc(&irq_err_count); 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * Theoretically we do not have to handle this IRQ, 19862306a36Sopenharmony_ci * but in Linux this does not cause problems and is 19962306a36Sopenharmony_ci * simpler for us. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci goto handle_real_irq; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic void i8259A_resume(void) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci if (i8259A_auto_eoi >= 0) 20862306a36Sopenharmony_ci init_8259A(i8259A_auto_eoi); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void i8259A_shutdown(void) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci /* Put the i8259A into a quiescent state that 21462306a36Sopenharmony_ci * the kernel initialization code can get it 21562306a36Sopenharmony_ci * out of. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci if (i8259A_auto_eoi >= 0) { 21862306a36Sopenharmony_ci outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ 21962306a36Sopenharmony_ci outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic struct syscore_ops i8259_syscore_ops = { 22462306a36Sopenharmony_ci .resume = i8259A_resume, 22562306a36Sopenharmony_ci .shutdown = i8259A_shutdown, 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void init_8259A(int auto_eoi) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci unsigned long flags; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci i8259A_auto_eoi = auto_eoi; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci raw_spin_lock_irqsave(&i8259A_lock, flags); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ 23762306a36Sopenharmony_ci outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* 24062306a36Sopenharmony_ci * outb_p - this has to work on a wide range of PC hardware. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ci outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ 24362306a36Sopenharmony_ci outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ 24462306a36Sopenharmony_ci outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ 24562306a36Sopenharmony_ci if (auto_eoi) /* master does Auto EOI */ 24662306a36Sopenharmony_ci outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); 24762306a36Sopenharmony_ci else /* master expects normal EOI */ 24862306a36Sopenharmony_ci outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ 25162306a36Sopenharmony_ci outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ 25262306a36Sopenharmony_ci outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ 25362306a36Sopenharmony_ci outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ 25462306a36Sopenharmony_ci if (auto_eoi) 25562306a36Sopenharmony_ci /* 25662306a36Sopenharmony_ci * In AEOI mode we just have to mask the interrupt 25762306a36Sopenharmony_ci * when acking. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci i8259A_chip.irq_mask_ack = disable_8259A_irq; 26062306a36Sopenharmony_ci else 26162306a36Sopenharmony_ci i8259A_chip.irq_mask_ack = mask_and_ack_8259A; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci udelay(100); /* wait for 8259A to initialize */ 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ 26662306a36Sopenharmony_ci outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&i8259A_lock, flags); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic struct resource pic1_io_resource = { 27262306a36Sopenharmony_ci .name = "pic1", 27362306a36Sopenharmony_ci .start = PIC_MASTER_CMD, 27462306a36Sopenharmony_ci .end = PIC_MASTER_IMR, 27562306a36Sopenharmony_ci .flags = IORESOURCE_IO | IORESOURCE_BUSY 27662306a36Sopenharmony_ci}; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic struct resource pic2_io_resource = { 27962306a36Sopenharmony_ci .name = "pic2", 28062306a36Sopenharmony_ci .start = PIC_SLAVE_CMD, 28162306a36Sopenharmony_ci .end = PIC_SLAVE_IMR, 28262306a36Sopenharmony_ci .flags = IORESOURCE_IO | IORESOURCE_BUSY 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq, 28662306a36Sopenharmony_ci irq_hw_number_t hw) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq); 28962306a36Sopenharmony_ci irq_set_probe(virq); 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic const struct irq_domain_ops i8259A_ops = { 29462306a36Sopenharmony_ci .map = i8259A_irq_domain_map, 29562306a36Sopenharmony_ci .xlate = irq_domain_xlate_onecell, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* 29962306a36Sopenharmony_ci * On systems with i8259-style interrupt controllers we assume for 30062306a36Sopenharmony_ci * driver compatibility reasons interrupts 0 - 15 to be the i8259 30162306a36Sopenharmony_ci * interrupts even if the hardware uses a different interrupt numbering. 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_cistruct irq_domain * __init __init_i8259_irqs(struct device_node *node) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci /* 30662306a36Sopenharmony_ci * PIC_CASCADE_IR is cascade interrupt to second interrupt controller 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci int irq = I8259A_IRQ_BASE + PIC_CASCADE_IR; 30962306a36Sopenharmony_ci struct irq_domain *domain; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci insert_resource(&ioport_resource, &pic1_io_resource); 31262306a36Sopenharmony_ci insert_resource(&ioport_resource, &pic2_io_resource); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci init_8259A(0); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0, 31762306a36Sopenharmony_ci &i8259A_ops, NULL); 31862306a36Sopenharmony_ci if (!domain) 31962306a36Sopenharmony_ci panic("Failed to add i8259 IRQ domain"); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL)) 32262306a36Sopenharmony_ci pr_err("Failed to register cascade interrupt\n"); 32362306a36Sopenharmony_ci register_syscore_ops(&i8259_syscore_ops); 32462306a36Sopenharmony_ci return domain; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_civoid __init init_i8259_irqs(void) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci __init_i8259_irqs(NULL); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic void i8259_irq_dispatch(struct irq_desc *desc) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct irq_domain *domain = irq_desc_get_handler_data(desc); 33562306a36Sopenharmony_ci int hwirq = i8259_poll(); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (hwirq < 0) 33862306a36Sopenharmony_ci return; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci generic_handle_domain_irq(domain, hwirq); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int __init i8259_of_init(struct device_node *node, struct device_node *parent) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct irq_domain *domain; 34662306a36Sopenharmony_ci unsigned int parent_irq; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci domain = __init_i8259_irqs(node); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci parent_irq = irq_of_parse_and_map(node, 0); 35162306a36Sopenharmony_ci if (!parent_irq) { 35262306a36Sopenharmony_ci pr_err("Failed to map i8259 parent IRQ\n"); 35362306a36Sopenharmony_ci irq_domain_remove(domain); 35462306a36Sopenharmony_ci return -ENODEV; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci irq_set_chained_handler_and_data(parent_irq, i8259_irq_dispatch, 35862306a36Sopenharmony_ci domain); 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ciIRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init); 362