root/arch/powerpc/sysdev/ge/ge_pic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gef_pic_cascade
  2. gef_pic_mask
  3. gef_pic_mask_ack
  4. gef_pic_unmask
  5. gef_pic_host_map
  6. gef_pic_host_xlate
  7. gef_pic_init
  8. gef_pic_get_irq

   1 /*
   2  * Interrupt handling for GE FPGA based PIC
   3  *
   4  * Author: Martyn Welch <martyn.welch@ge.com>
   5  *
   6  * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
   7  *
   8  * This file is licensed under the terms of the GNU General Public License
   9  * version 2.  This program is licensed "as is" without any warranty of any
  10  * kind, whether express or implied.
  11  */
  12 
  13 #include <linux/stddef.h>
  14 #include <linux/kernel.h>
  15 #include <linux/init.h>
  16 #include <linux/irq.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/spinlock.h>
  19 
  20 #include <asm/byteorder.h>
  21 #include <asm/io.h>
  22 #include <asm/prom.h>
  23 #include <asm/irq.h>
  24 
  25 #include "ge_pic.h"
  26 
  27 #define DEBUG
  28 #undef DEBUG
  29 
  30 #ifdef DEBUG
  31 #define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
  32 #else
  33 #define DBG(fmt...) do { } while (0)
  34 #endif
  35 
  36 #define GEF_PIC_NUM_IRQS        32
  37 
  38 /* Interrupt Controller Interface Registers */
  39 #define GEF_PIC_INTR_STATUS     0x0000
  40 
  41 #define GEF_PIC_INTR_MASK(cpu)  (0x0010 + (0x4 * cpu))
  42 #define GEF_PIC_CPU0_INTR_MASK  GEF_PIC_INTR_MASK(0)
  43 #define GEF_PIC_CPU1_INTR_MASK  GEF_PIC_INTR_MASK(1)
  44 
  45 #define GEF_PIC_MCP_MASK(cpu)   (0x0018 + (0x4 * cpu))
  46 #define GEF_PIC_CPU0_MCP_MASK   GEF_PIC_MCP_MASK(0)
  47 #define GEF_PIC_CPU1_MCP_MASK   GEF_PIC_MCP_MASK(1)
  48 
  49 
  50 static DEFINE_RAW_SPINLOCK(gef_pic_lock);
  51 
  52 static void __iomem *gef_pic_irq_reg_base;
  53 static struct irq_domain *gef_pic_irq_host;
  54 static int gef_pic_cascade_irq;
  55 
  56 /*
  57  * Interrupt Controller Handling
  58  *
  59  * The interrupt controller handles interrupts for most on board interrupts,
  60  * apart from PCI interrupts. For example on SBC610:
  61  *
  62  * 17:31 RO Reserved
  63  * 16    RO PCI Express Doorbell 3 Status
  64  * 15    RO PCI Express Doorbell 2 Status
  65  * 14    RO PCI Express Doorbell 1 Status
  66  * 13    RO PCI Express Doorbell 0 Status
  67  * 12    RO Real Time Clock Interrupt Status
  68  * 11    RO Temperature Interrupt Status
  69  * 10    RO Temperature Critical Interrupt Status
  70  * 9     RO Ethernet PHY1 Interrupt Status
  71  * 8     RO Ethernet PHY3 Interrupt Status
  72  * 7     RO PEX8548 Interrupt Status
  73  * 6     RO Reserved
  74  * 5     RO Watchdog 0 Interrupt Status
  75  * 4     RO Watchdog 1 Interrupt Status
  76  * 3     RO AXIS Message FIFO A Interrupt Status
  77  * 2     RO AXIS Message FIFO B Interrupt Status
  78  * 1     RO AXIS Message FIFO C Interrupt Status
  79  * 0     RO AXIS Message FIFO D Interrupt Status
  80  *
  81  * Interrupts can be forwarded to one of two output lines. Nothing
  82  * clever is done, so if the masks are incorrectly set, a single input
  83  * interrupt could generate interrupts on both output lines!
  84  *
  85  * The dual lines are there to allow the chained interrupts to be easily
  86  * passed into two different cores. We currently do not use this functionality
  87  * in this driver.
  88  *
  89  * Controller can also be configured to generate Machine checks (MCP), again on
  90  * two lines, to be attached to two different cores. It is suggested that these
  91  * should be masked out.
  92  */
  93 
  94 static void gef_pic_cascade(struct irq_desc *desc)
  95 {
  96         struct irq_chip *chip = irq_desc_get_chip(desc);
  97         unsigned int cascade_irq;
  98 
  99         /*
 100          * See if we actually have an interrupt, call generic handling code if
 101          * we do.
 102          */
 103         cascade_irq = gef_pic_get_irq();
 104 
 105         if (cascade_irq)
 106                 generic_handle_irq(cascade_irq);
 107 
 108         chip->irq_eoi(&desc->irq_data);
 109 }
 110 
 111 static void gef_pic_mask(struct irq_data *d)
 112 {
 113         unsigned long flags;
 114         unsigned int hwirq = irqd_to_hwirq(d);
 115         u32 mask;
 116 
 117         raw_spin_lock_irqsave(&gef_pic_lock, flags);
 118         mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
 119         mask &= ~(1 << hwirq);
 120         out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
 121         raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
 122 }
 123 
 124 static void gef_pic_mask_ack(struct irq_data *d)
 125 {
 126         /* Don't think we actually have to do anything to ack an interrupt,
 127          * we just need to clear down the devices interrupt and it will go away
 128          */
 129         gef_pic_mask(d);
 130 }
 131 
 132 static void gef_pic_unmask(struct irq_data *d)
 133 {
 134         unsigned long flags;
 135         unsigned int hwirq = irqd_to_hwirq(d);
 136         u32 mask;
 137 
 138         raw_spin_lock_irqsave(&gef_pic_lock, flags);
 139         mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
 140         mask |= (1 << hwirq);
 141         out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
 142         raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
 143 }
 144 
 145 static struct irq_chip gef_pic_chip = {
 146         .name           = "gefp",
 147         .irq_mask       = gef_pic_mask,
 148         .irq_mask_ack   = gef_pic_mask_ack,
 149         .irq_unmask     = gef_pic_unmask,
 150 };
 151 
 152 
 153 /* When an interrupt is being configured, this call allows some flexibilty
 154  * in deciding which irq_chip structure is used
 155  */
 156 static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
 157                           irq_hw_number_t hwirq)
 158 {
 159         /* All interrupts are LEVEL sensitive */
 160         irq_set_status_flags(virq, IRQ_LEVEL);
 161         irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
 162 
 163         return 0;
 164 }
 165 
 166 static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
 167                             const u32 *intspec, unsigned int intsize,
 168                             irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 169 {
 170 
 171         *out_hwirq = intspec[0];
 172         if (intsize > 1)
 173                 *out_flags = intspec[1];
 174         else
 175                 *out_flags = IRQ_TYPE_LEVEL_HIGH;
 176 
 177         return 0;
 178 }
 179 
 180 static const struct irq_domain_ops gef_pic_host_ops = {
 181         .map    = gef_pic_host_map,
 182         .xlate  = gef_pic_host_xlate,
 183 };
 184 
 185 
 186 /*
 187  * Initialisation of PIC, this should be called in BSP
 188  */
 189 void __init gef_pic_init(struct device_node *np)
 190 {
 191         unsigned long flags;
 192 
 193         /* Map the devices registers into memory */
 194         gef_pic_irq_reg_base = of_iomap(np, 0);
 195 
 196         raw_spin_lock_irqsave(&gef_pic_lock, flags);
 197 
 198         /* Initialise everything as masked. */
 199         out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
 200         out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
 201 
 202         out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
 203         out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
 204 
 205         raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
 206 
 207         /* Map controller */
 208         gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
 209         if (!gef_pic_cascade_irq) {
 210                 printk(KERN_ERR "SBC610: failed to map cascade interrupt");
 211                 return;
 212         }
 213 
 214         /* Setup an irq_domain structure */
 215         gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
 216                                           &gef_pic_host_ops, NULL);
 217         if (gef_pic_irq_host == NULL)
 218                 return;
 219 
 220         /* Chain with parent controller */
 221         irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
 222 }
 223 
 224 /*
 225  * This is called when we receive an interrupt with apparently comes from this
 226  * chip - check, returning the highest interrupt generated or return 0.
 227  */
 228 unsigned int gef_pic_get_irq(void)
 229 {
 230         u32 cause, mask, active;
 231         unsigned int virq = 0;
 232         int hwirq;
 233 
 234         cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
 235 
 236         mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
 237 
 238         active = cause & mask;
 239 
 240         if (active) {
 241                 for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
 242                         if (active & (0x1 << hwirq))
 243                                 break;
 244                 }
 245                 virq = irq_linear_revmap(gef_pic_irq_host,
 246                         (irq_hw_number_t)hwirq);
 247         }
 248 
 249         return virq;
 250 }
 251 

/* [<][>][^][v][top][bottom][index][help] */