linux/arch/ppc/syslib/ppc8xx_pic.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/stddef.h>
   3#include <linux/init.h>
   4#include <linux/sched.h>
   5#include <linux/signal.h>
   6#include <linux/interrupt.h>
   7#include <asm/irq.h>
   8#include <asm/io.h>
   9#include <asm/8xx_immap.h>
  10#include <asm/mpc8xx.h>
  11#include "ppc8xx_pic.h"
  12
  13extern int cpm_get_irq(void);
  14
  15/* The 8xx internal interrupt controller.  It is usually
  16 * the only interrupt controller.  Some boards, like the MBX and
  17 * Sandpoint have the 8259 as a secondary controller.  Depending
  18 * upon the processor type, the internal controller can have as
  19 * few as 16 interrupts or as many as 64.  We could use  the
  20 * "clear_bit()" and "set_bit()" functions like other platforms,
  21 * but they are overkill for us.
  22 */
  23
  24static void m8xx_mask_irq(unsigned int irq_nr)
  25{
  26        int     bit, word;
  27
  28        bit = irq_nr & 0x1f;
  29        word = irq_nr >> 5;
  30
  31        ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
  32        out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
  33}
  34
  35static void m8xx_unmask_irq(unsigned int irq_nr)
  36{
  37        int     bit, word;
  38
  39        bit = irq_nr & 0x1f;
  40        word = irq_nr >> 5;
  41
  42        ppc_cached_irq_mask[word] |= (1 << (31-bit));
  43        out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
  44}
  45
  46static void m8xx_end_irq(unsigned int irq_nr)
  47{
  48        if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
  49                        && irq_desc[irq_nr].action) {
  50                int bit, word;
  51
  52                bit = irq_nr & 0x1f;
  53                word = irq_nr >> 5;
  54
  55                ppc_cached_irq_mask[word] |= (1 << (31-bit));
  56                out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
  57        }
  58}
  59
  60
  61static void m8xx_mask_and_ack(unsigned int irq_nr)
  62{
  63        int     bit, word;
  64
  65        bit = irq_nr & 0x1f;
  66        word = irq_nr >> 5;
  67
  68        ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
  69        out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
  70        out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend, 1 << (31-bit));
  71}
  72
  73struct hw_interrupt_type ppc8xx_pic = {
  74        .typename = " 8xx SIU  ",
  75        .enable = m8xx_unmask_irq,
  76        .disable = m8xx_mask_irq,
  77        .ack = m8xx_mask_and_ack,
  78        .end = m8xx_end_irq,
  79};
  80
  81/*
  82 * We either return a valid interrupt or -1 if there is nothing pending
  83 */
  84int
  85m8xx_get_irq(struct pt_regs *regs)
  86{
  87        int irq;
  88
  89        /* For MPC8xx, read the SIVEC register and shift the bits down
  90         * to get the irq number.
  91         */
  92        irq = in_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec) >> 26;
  93
  94        /*
  95         * When we read the sivec without an interrupt to process, we will
  96         * get back SIU_LEVEL7.  In this case, return -1
  97         */
  98        if (irq == CPM_INTERRUPT)
  99                irq = CPM_IRQ_OFFSET + cpm_get_irq();
 100#if defined(CONFIG_PCI)
 101        else if (irq == ISA_BRIDGE_INT) {
 102                int isa_irq;
 103
 104                if ((isa_irq = i8259_poll(regs)) >= 0)
 105                        irq = I8259_IRQ_OFFSET + isa_irq;
 106        }
 107#endif  /* CONFIG_PCI */
 108        else if (irq == SIU_LEVEL7)
 109                irq = -1;
 110
 111        return irq;
 112}
 113
 114#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
 115/* Only the MBX uses the external 8259.  This allows us to catch standard
 116 * drivers that may mess up the internal interrupt controllers, and also
 117 * allow them to run without modification on the MBX.
 118 */
 119void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
 120{
 121        /* This interrupt handler never actually gets called.  It is
 122         * installed only to unmask the 8259 cascade interrupt in the SIU
 123         * and to make the 8259 cascade interrupt visible in /proc/interrupts.
 124         */
 125}
 126#endif  /* CONFIG_PCI */
 127
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.