LCOV - code coverage report
Current view: top level - arch/x86/kernel - i8259.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 68 161 42.2 %
Date: 2021-04-22 12:43:58 Functions: 7 21 33.3 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/linkage.h>
       3             : #include <linux/errno.h>
       4             : #include <linux/signal.h>
       5             : #include <linux/sched.h>
       6             : #include <linux/ioport.h>
       7             : #include <linux/interrupt.h>
       8             : #include <linux/irq.h>
       9             : #include <linux/timex.h>
      10             : #include <linux/random.h>
      11             : #include <linux/init.h>
      12             : #include <linux/kernel_stat.h>
      13             : #include <linux/syscore_ops.h>
      14             : #include <linux/bitops.h>
      15             : #include <linux/acpi.h>
      16             : #include <linux/io.h>
      17             : #include <linux/delay.h>
      18             : #include <linux/pgtable.h>
      19             : 
      20             : #include <linux/atomic.h>
      21             : #include <asm/timer.h>
      22             : #include <asm/hw_irq.h>
      23             : #include <asm/desc.h>
      24             : #include <asm/apic.h>
      25             : #include <asm/i8259.h>
      26             : 
      27             : /*
      28             :  * This is the 'legacy' 8259A Programmable Interrupt Controller,
      29             :  * present in the majority of PC/AT boxes.
      30             :  * plus some generic x86 specific things if generic specifics makes
      31             :  * any sense at all.
      32             :  */
      33             : static void init_8259A(int auto_eoi);
      34             : 
      35             : static int i8259A_auto_eoi;
      36             : DEFINE_RAW_SPINLOCK(i8259A_lock);
      37             : 
      38             : /*
      39             :  * 8259A PIC functions to handle ISA devices:
      40             :  */
      41             : 
      42             : /*
      43             :  * This contains the irq mask for both 8259A irq controllers,
      44             :  */
      45             : unsigned int cached_irq_mask = 0xffff;
      46             : 
      47             : /*
      48             :  * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
      49             :  * boards the timer interrupt is not really connected to any IO-APIC pin,
      50             :  * it's fed to the master 8259A's IR0 line only.
      51             :  *
      52             :  * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
      53             :  * this 'mixed mode' IRQ handling costs nothing because it's only used
      54             :  * at IRQ setup time.
      55             :  */
      56             : unsigned long io_apic_irqs;
      57             : 
      58          18 : static void mask_8259A_irq(unsigned int irq)
      59             : {
      60          18 :         unsigned int mask = 1 << irq;
      61          18 :         unsigned long flags;
      62             : 
      63          18 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
      64          18 :         cached_irq_mask |= mask;
      65          18 :         if (irq & 8)
      66          10 :                 outb(cached_slave_mask, PIC_SLAVE_IMR);
      67             :         else
      68           8 :                 outb(cached_master_mask, PIC_MASTER_IMR);
      69          18 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
      70          18 : }
      71             : 
      72           0 : static void disable_8259A_irq(struct irq_data *data)
      73             : {
      74           0 :         mask_8259A_irq(data->irq);
      75           0 : }
      76             : 
      77           1 : static void unmask_8259A_irq(unsigned int irq)
      78             : {
      79           1 :         unsigned int mask = ~(1 << irq);
      80           1 :         unsigned long flags;
      81             : 
      82           1 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
      83           1 :         cached_irq_mask &= mask;
      84           1 :         if (irq & 8)
      85           0 :                 outb(cached_slave_mask, PIC_SLAVE_IMR);
      86             :         else
      87           1 :                 outb(cached_master_mask, PIC_MASTER_IMR);
      88           1 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
      89           1 : }
      90             : 
      91           1 : static void enable_8259A_irq(struct irq_data *data)
      92             : {
      93           1 :         unmask_8259A_irq(data->irq);
      94           1 : }
      95             : 
      96           3 : static int i8259A_irq_pending(unsigned int irq)
      97             : {
      98           3 :         unsigned int mask = 1<<irq;
      99           3 :         unsigned long flags;
     100           3 :         int ret;
     101             : 
     102           3 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
     103           3 :         if (irq < 8)
     104           1 :                 ret = inb(PIC_MASTER_CMD) & mask;
     105             :         else
     106           2 :                 ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
     107           3 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
     108             : 
     109           3 :         return ret;
     110             : }
     111             : 
     112           0 : static void make_8259A_irq(unsigned int irq)
     113             : {
     114           0 :         disable_irq_nosync(irq);
     115           0 :         io_apic_irqs &= ~(1<<irq);
     116           0 :         irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
     117           0 :         enable_irq(irq);
     118           0 :         lapic_assign_legacy_vector(irq, true);
     119           0 : }
     120             : 
     121             : /*
     122             :  * This function assumes to be called rarely. Switching between
     123             :  * 8259A registers is slow.
     124             :  * This has to be protected by the irq controller spinlock
     125             :  * before being called.
     126             :  */
     127           0 : static inline int i8259A_irq_real(unsigned int irq)
     128             : {
     129           0 :         int value;
     130           0 :         int irqmask = 1<<irq;
     131             : 
     132           0 :         if (irq < 8) {
     133           0 :                 outb(0x0B, PIC_MASTER_CMD);     /* ISR register */
     134           0 :                 value = inb(PIC_MASTER_CMD) & irqmask;
     135           0 :                 outb(0x0A, PIC_MASTER_CMD);     /* back to the IRR register */
     136           0 :                 return value;
     137             :         }
     138           0 :         outb(0x0B, PIC_SLAVE_CMD);      /* ISR register */
     139           0 :         value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
     140           0 :         outb(0x0A, PIC_SLAVE_CMD);      /* back to the IRR register */
     141           0 :         return value;
     142             : }
     143             : 
     144             : /*
     145             :  * Careful! The 8259A is a fragile beast, it pretty
     146             :  * much _has_ to be done exactly like this (mask it
     147             :  * first, _then_ send the EOI, and the order of EOI
     148             :  * to the two 8259s is important!
     149             :  */
     150           0 : static void mask_and_ack_8259A(struct irq_data *data)
     151             : {
     152           0 :         unsigned int irq = data->irq;
     153           0 :         unsigned int irqmask = 1 << irq;
     154           0 :         unsigned long flags;
     155             : 
     156           0 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
     157             :         /*
     158             :          * Lightweight spurious IRQ detection. We do not want
     159             :          * to overdo spurious IRQ handling - it's usually a sign
     160             :          * of hardware problems, so we only do the checks we can
     161             :          * do without slowing down good hardware unnecessarily.
     162             :          *
     163             :          * Note that IRQ7 and IRQ15 (the two spurious IRQs
     164             :          * usually resulting from the 8259A-1|2 PICs) occur
     165             :          * even if the IRQ is masked in the 8259A. Thus we
     166             :          * can check spurious 8259A IRQs without doing the
     167             :          * quite slow i8259A_irq_real() call for every IRQ.
     168             :          * This does not cover 100% of spurious interrupts,
     169             :          * but should be enough to warn the user that there
     170             :          * is something bad going on ...
     171             :          */
     172           0 :         if (cached_irq_mask & irqmask)
     173           0 :                 goto spurious_8259A_irq;
     174           0 :         cached_irq_mask |= irqmask;
     175             : 
     176           0 : handle_real_irq:
     177           0 :         if (irq & 8) {
     178           0 :                 inb(PIC_SLAVE_IMR);     /* DUMMY - (do we need this?) */
     179           0 :                 outb(cached_slave_mask, PIC_SLAVE_IMR);
     180             :                 /* 'Specific EOI' to slave */
     181           0 :                 outb(0x60+(irq&7), PIC_SLAVE_CMD);
     182             :                  /* 'Specific EOI' to master-IRQ2 */
     183           0 :                 outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD);
     184             :         } else {
     185           0 :                 inb(PIC_MASTER_IMR);    /* DUMMY - (do we need this?) */
     186           0 :                 outb(cached_master_mask, PIC_MASTER_IMR);
     187           0 :                 outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */
     188             :         }
     189           0 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
     190           0 :         return;
     191             : 
     192           0 : spurious_8259A_irq:
     193             :         /*
     194             :          * this is the slow path - should happen rarely.
     195             :          */
     196           0 :         if (i8259A_irq_real(irq))
     197             :                 /*
     198             :                  * oops, the IRQ _is_ in service according to the
     199             :                  * 8259A - not spurious, go handle it.
     200             :                  */
     201           0 :                 goto handle_real_irq;
     202             : 
     203             :         {
     204           0 :                 static int spurious_irq_mask;
     205             :                 /*
     206             :                  * At this point we can be sure the IRQ is spurious,
     207             :                  * lets ACK and report it. [once per IRQ]
     208             :                  */
     209           0 :                 if (!(spurious_irq_mask & irqmask)) {
     210           0 :                         printk_deferred(KERN_DEBUG
     211             :                                "spurious 8259A interrupt: IRQ%d.\n", irq);
     212           0 :                         spurious_irq_mask |= irqmask;
     213             :                 }
     214           0 :                 atomic_inc(&irq_err_count);
     215             :                 /*
     216             :                  * Theoretically we do not have to handle this IRQ,
     217             :                  * but in Linux this does not cause problems and is
     218             :                  * simpler for us.
     219             :                  */
     220           0 :                 goto handle_real_irq;
     221             :         }
     222             : }
     223             : 
     224             : struct irq_chip i8259A_chip = {
     225             :         .name           = "XT-PIC",
     226             :         .irq_mask       = disable_8259A_irq,
     227             :         .irq_disable    = disable_8259A_irq,
     228             :         .irq_unmask     = enable_8259A_irq,
     229             :         .irq_mask_ack   = mask_and_ack_8259A,
     230             : };
     231             : 
     232             : static char irq_trigger[2];
     233             : /**
     234             :  * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
     235             :  */
     236           0 : static void restore_ELCR(char *trigger)
     237             : {
     238           0 :         outb(trigger[0], 0x4d0);
     239           0 :         outb(trigger[1], 0x4d1);
     240             : }
     241             : 
     242           0 : static void save_ELCR(char *trigger)
     243             : {
     244             :         /* IRQ 0,1,2,8,13 are marked as reserved */
     245           0 :         trigger[0] = inb(0x4d0) & 0xF8;
     246           0 :         trigger[1] = inb(0x4d1) & 0xDE;
     247             : }
     248             : 
     249           0 : static void i8259A_resume(void)
     250             : {
     251           0 :         init_8259A(i8259A_auto_eoi);
     252           0 :         restore_ELCR(irq_trigger);
     253           0 : }
     254             : 
     255           0 : static int i8259A_suspend(void)
     256             : {
     257           0 :         save_ELCR(irq_trigger);
     258           0 :         return 0;
     259             : }
     260             : 
     261           0 : static void i8259A_shutdown(void)
     262             : {
     263             :         /* Put the i8259A into a quiescent state that
     264             :          * the kernel initialization code can get it
     265             :          * out of.
     266             :          */
     267           0 :         outb(0xff, PIC_MASTER_IMR);     /* mask all of 8259A-1 */
     268           0 :         outb(0xff, PIC_SLAVE_IMR);      /* mask all of 8259A-2 */
     269           0 : }
     270             : 
     271             : static struct syscore_ops i8259_syscore_ops = {
     272             :         .suspend = i8259A_suspend,
     273             :         .resume = i8259A_resume,
     274             :         .shutdown = i8259A_shutdown,
     275             : };
     276             : 
     277           0 : static void mask_8259A(void)
     278             : {
     279           0 :         unsigned long flags;
     280             : 
     281           0 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
     282             : 
     283           0 :         outb(0xff, PIC_MASTER_IMR);     /* mask all of 8259A-1 */
     284           0 :         outb(0xff, PIC_SLAVE_IMR);      /* mask all of 8259A-2 */
     285             : 
     286           0 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
     287           0 : }
     288             : 
     289           0 : static void unmask_8259A(void)
     290             : {
     291           0 :         unsigned long flags;
     292             : 
     293           0 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
     294             : 
     295           0 :         outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
     296           0 :         outb(cached_slave_mask, PIC_SLAVE_IMR);   /* restore slave IRQ mask */
     297             : 
     298           0 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
     299           0 : }
     300             : 
     301           1 : static int probe_8259A(void)
     302             : {
     303           1 :         unsigned long flags;
     304           1 :         unsigned char probe_val = ~(1 << PIC_CASCADE_IR);
     305           1 :         unsigned char new_val;
     306             :         /*
     307             :          * Check to see if we have a PIC.
     308             :          * Mask all except the cascade and read
     309             :          * back the value we just wrote. If we don't
     310             :          * have a PIC, we will read 0xff as opposed to the
     311             :          * value we wrote.
     312             :          */
     313           1 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
     314             : 
     315           1 :         outb(0xff, PIC_SLAVE_IMR);      /* mask all of 8259A-2 */
     316           1 :         outb(probe_val, PIC_MASTER_IMR);
     317           1 :         new_val = inb(PIC_MASTER_IMR);
     318           1 :         if (new_val != probe_val) {
     319           0 :                 printk(KERN_INFO "Using NULL legacy PIC\n");
     320           0 :                 legacy_pic = &null_legacy_pic;
     321             :         }
     322             : 
     323           1 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
     324           1 :         return nr_legacy_irqs();
     325             : }
     326             : 
     327           1 : static void init_8259A(int auto_eoi)
     328             : {
     329           1 :         unsigned long flags;
     330             : 
     331           1 :         i8259A_auto_eoi = auto_eoi;
     332             : 
     333           1 :         raw_spin_lock_irqsave(&i8259A_lock, flags);
     334             : 
     335           1 :         outb(0xff, PIC_MASTER_IMR);     /* mask all of 8259A-1 */
     336             : 
     337             :         /*
     338             :          * outb_pic - this has to work on a wide range of PC hardware.
     339             :          */
     340           1 :         outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
     341             : 
     342             :         /* ICW2: 8259A-1 IR0-7 mapped to ISA_IRQ_VECTOR(0) */
     343           1 :         outb_pic(ISA_IRQ_VECTOR(0), PIC_MASTER_IMR);
     344             : 
     345             :         /* 8259A-1 (the master) has a slave on IR2 */
     346           1 :         outb_pic(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);
     347             : 
     348           1 :         if (auto_eoi)   /* master does Auto EOI */
     349           0 :                 outb_pic(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
     350             :         else            /* master expects normal EOI */
     351           1 :                 outb_pic(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
     352             : 
     353           1 :         outb_pic(0x11, PIC_SLAVE_CMD);  /* ICW1: select 8259A-2 init */
     354             : 
     355             :         /* ICW2: 8259A-2 IR0-7 mapped to ISA_IRQ_VECTOR(8) */
     356           1 :         outb_pic(ISA_IRQ_VECTOR(8), PIC_SLAVE_IMR);
     357             :         /* 8259A-2 is a slave on master's IR2 */
     358           1 :         outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);
     359             :         /* (slave's support for AEOI in flat mode is to be investigated) */
     360           1 :         outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);
     361             : 
     362           1 :         if (auto_eoi)
     363             :                 /*
     364             :                  * In AEOI mode we just have to mask the interrupt
     365             :                  * when acking.
     366             :                  */
     367           0 :                 i8259A_chip.irq_mask_ack = disable_8259A_irq;
     368             :         else
     369           1 :                 i8259A_chip.irq_mask_ack = mask_and_ack_8259A;
     370             : 
     371           1 :         udelay(100);            /* wait for 8259A to initialize */
     372             : 
     373           1 :         outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
     374           1 :         outb(cached_slave_mask, PIC_SLAVE_IMR);   /* restore slave IRQ mask */
     375             : 
     376           1 :         raw_spin_unlock_irqrestore(&i8259A_lock, flags);
     377           1 : }
     378             : 
     379             : /*
     380             :  * make i8259 a driver so that we can select pic functions at run time. the goal
     381             :  * is to make x86 binary compatible among pc compatible and non-pc compatible
     382             :  * platforms, such as x86 MID.
     383             :  */
     384             : 
     385           0 : static void legacy_pic_noop(void) { };
     386           0 : static void legacy_pic_uint_noop(unsigned int unused) { };
     387           0 : static void legacy_pic_int_noop(int unused) { };
     388           0 : static int legacy_pic_irq_pending_noop(unsigned int irq)
     389             : {
     390           0 :         return 0;
     391             : }
     392           0 : static int legacy_pic_probe(void)
     393             : {
     394           0 :         return 0;
     395             : }
     396             : 
     397             : struct legacy_pic null_legacy_pic = {
     398             :         .nr_legacy_irqs = 0,
     399             :         .chip = &dummy_irq_chip,
     400             :         .mask = legacy_pic_uint_noop,
     401             :         .unmask = legacy_pic_uint_noop,
     402             :         .mask_all = legacy_pic_noop,
     403             :         .restore_mask = legacy_pic_noop,
     404             :         .init = legacy_pic_int_noop,
     405             :         .probe = legacy_pic_probe,
     406             :         .irq_pending = legacy_pic_irq_pending_noop,
     407             :         .make_irq = legacy_pic_uint_noop,
     408             : };
     409             : 
     410             : struct legacy_pic default_legacy_pic = {
     411             :         .nr_legacy_irqs = NR_IRQS_LEGACY,
     412             :         .chip  = &i8259A_chip,
     413             :         .mask = mask_8259A_irq,
     414             :         .unmask = unmask_8259A_irq,
     415             :         .mask_all = mask_8259A,
     416             :         .restore_mask = unmask_8259A,
     417             :         .init = init_8259A,
     418             :         .probe = probe_8259A,
     419             :         .irq_pending = i8259A_irq_pending,
     420             :         .make_irq = make_8259A_irq,
     421             : };
     422             : 
     423             : struct legacy_pic *legacy_pic = &default_legacy_pic;
     424             : EXPORT_SYMBOL(legacy_pic);
     425             : 
     426           1 : static int __init i8259A_init_ops(void)
     427             : {
     428           1 :         if (legacy_pic == &default_legacy_pic)
     429           1 :                 register_syscore_ops(&i8259_syscore_ops);
     430             : 
     431           1 :         return 0;
     432             : }
     433             : 
     434             : device_initcall(i8259A_init_ops);

Generated by: LCOV version 1.14