root/drivers/parisc/gsc.c

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

DEFINITIONS

This source file includes following definitions.
  1. gsc_alloc_irq
  2. gsc_claim_irq
  3. gsc_asic_intr
  4. gsc_find_local_irq
  5. gsc_asic_mask_irq
  6. gsc_asic_unmask_irq
  7. gsc_assign_irq
  8. gsc_asic_assign_irq
  9. gsc_fixup_irqs_callback
  10. gsc_fixup_irqs
  11. gsc_common_setup
  12. gsc_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Interrupt management for most GSC and related devices.
   4  *
   5  * (c) Copyright 1999 Alex deVries for The Puffin Group
   6  * (c) Copyright 1999 Grant Grundler for Hewlett-Packard
   7  * (c) Copyright 1999 Matthew Wilcox
   8  * (c) Copyright 2000 Helge Deller
   9  * (c) Copyright 2001 Matthew Wilcox for Hewlett-Packard
  10  */
  11 
  12 #include <linux/bitops.h>
  13 #include <linux/errno.h>
  14 #include <linux/init.h>
  15 #include <linux/interrupt.h>
  16 #include <linux/ioport.h>
  17 #include <linux/module.h>
  18 #include <linux/types.h>
  19 
  20 #include <asm/hardware.h>
  21 #include <asm/io.h>
  22 
  23 #include "gsc.h"
  24 
  25 #undef DEBUG
  26 
  27 #ifdef DEBUG
  28 #define DEBPRINTK printk
  29 #else
  30 #define DEBPRINTK(x,...)
  31 #endif
  32 
  33 int gsc_alloc_irq(struct gsc_irq *i)
  34 {
  35         int irq = txn_alloc_irq(GSC_EIM_WIDTH);
  36         if (irq < 0) {
  37                 printk("cannot get irq\n");
  38                 return irq;
  39         }
  40 
  41         i->txn_addr = txn_alloc_addr(irq);
  42         i->txn_data = txn_alloc_data(irq);
  43         i->irq = irq;
  44 
  45         return irq;
  46 }
  47 
  48 int gsc_claim_irq(struct gsc_irq *i, int irq)
  49 {
  50         int c = irq;
  51 
  52         irq += CPU_IRQ_BASE; /* virtualize the IRQ first */
  53 
  54         irq = txn_claim_irq(irq);
  55         if (irq < 0) {
  56                 printk("cannot claim irq %d\n", c);
  57                 return irq;
  58         }
  59 
  60         i->txn_addr = txn_alloc_addr(irq);
  61         i->txn_data = txn_alloc_data(irq);
  62         i->irq = irq;
  63 
  64         return irq;
  65 }
  66 
  67 EXPORT_SYMBOL(gsc_alloc_irq);
  68 EXPORT_SYMBOL(gsc_claim_irq);
  69 
  70 /* Common interrupt demultiplexer used by Asp, Lasi & Wax.  */
  71 irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev)
  72 {
  73         unsigned long irr;
  74         struct gsc_asic *gsc_asic = dev;
  75 
  76         irr = gsc_readl(gsc_asic->hpa + OFFSET_IRR);
  77         if (irr == 0)
  78                 return IRQ_NONE;
  79 
  80         DEBPRINTK("%s intr, mask=0x%x\n", gsc_asic->name, irr);
  81 
  82         do {
  83                 int local_irq = __ffs(irr);
  84                 unsigned int irq = gsc_asic->global_irq[local_irq];
  85                 generic_handle_irq(irq);
  86                 irr &= ~(1 << local_irq);
  87         } while (irr);
  88 
  89         return IRQ_HANDLED;
  90 }
  91 
  92 int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
  93 {
  94         int local_irq;
  95 
  96         for (local_irq = 0; local_irq < limit; local_irq++) {
  97                 if (global_irqs[local_irq] == irq)
  98                         return local_irq;
  99         }
 100 
 101         return NO_IRQ;
 102 }
 103 
 104 static void gsc_asic_mask_irq(struct irq_data *d)
 105 {
 106         struct gsc_asic *irq_dev = irq_data_get_irq_chip_data(d);
 107         int local_irq = gsc_find_local_irq(d->irq, irq_dev->global_irq, 32);
 108         u32 imr;
 109 
 110         DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, d->irq,
 111                         irq_dev->name, imr);
 112 
 113         /* Disable the IRQ line by clearing the bit in the IMR */
 114         imr = gsc_readl(irq_dev->hpa + OFFSET_IMR);
 115         imr &= ~(1 << local_irq);
 116         gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
 117 }
 118 
 119 static void gsc_asic_unmask_irq(struct irq_data *d)
 120 {
 121         struct gsc_asic *irq_dev = irq_data_get_irq_chip_data(d);
 122         int local_irq = gsc_find_local_irq(d->irq, irq_dev->global_irq, 32);
 123         u32 imr;
 124 
 125         DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, d->irq,
 126                         irq_dev->name, imr);
 127 
 128         /* Enable the IRQ line by setting the bit in the IMR */
 129         imr = gsc_readl(irq_dev->hpa + OFFSET_IMR);
 130         imr |= 1 << local_irq;
 131         gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
 132         /*
 133          * FIXME: read IPR to make sure the IRQ isn't already pending.
 134          *   If so, we need to read IRR and manually call do_irq().
 135          */
 136 }
 137 
 138 static struct irq_chip gsc_asic_interrupt_type = {
 139         .name           =       "GSC-ASIC",
 140         .irq_unmask     =       gsc_asic_unmask_irq,
 141         .irq_mask       =       gsc_asic_mask_irq,
 142 };
 143 
 144 int gsc_assign_irq(struct irq_chip *type, void *data)
 145 {
 146         static int irq = GSC_IRQ_BASE;
 147 
 148         if (irq > GSC_IRQ_MAX)
 149                 return NO_IRQ;
 150 
 151         irq_set_chip_and_handler(irq, type, handle_simple_irq);
 152         irq_set_chip_data(irq, data);
 153 
 154         return irq++;
 155 }
 156 
 157 void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp)
 158 {
 159         int irq = asic->global_irq[local_irq];
 160         
 161         if (irq <= 0) {
 162                 irq = gsc_assign_irq(&gsc_asic_interrupt_type, asic);
 163                 if (irq == NO_IRQ)
 164                         return;
 165 
 166                 asic->global_irq[local_irq] = irq;
 167         }
 168         *irqp = irq;
 169 }
 170 
 171 struct gsc_fixup_struct {
 172         void (*choose_irq)(struct parisc_device *, void *);
 173         void *ctrl;
 174 };
 175 
 176 static int gsc_fixup_irqs_callback(struct device *dev, void *data)
 177 {
 178         struct parisc_device *padev = to_parisc_device(dev);
 179         struct gsc_fixup_struct *gf = data;
 180 
 181         /* work-around for 715/64 and others which have parent
 182            at path [5] and children at path [5/0/x] */
 183         if (padev->id.hw_type == HPHW_FAULTY)
 184                 gsc_fixup_irqs(padev, gf->ctrl, gf->choose_irq);
 185         gf->choose_irq(padev, gf->ctrl);
 186 
 187         return 0;
 188 }
 189 
 190 void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
 191                         void (*choose_irq)(struct parisc_device *, void *))
 192 {
 193         struct gsc_fixup_struct data = {
 194                 .choose_irq     = choose_irq,
 195                 .ctrl           = ctrl,
 196         };
 197 
 198         device_for_each_child(&parent->dev, &data, gsc_fixup_irqs_callback);
 199 }
 200 
 201 int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic)
 202 {
 203         struct resource *res;
 204         int i;
 205 
 206         gsc_asic->gsc = parent;
 207 
 208         /* Initialise local irq -> global irq mapping */
 209         for (i = 0; i < 32; i++) {
 210                 gsc_asic->global_irq[i] = NO_IRQ;
 211         }
 212 
 213         /* allocate resource region */
 214         res = request_mem_region(gsc_asic->hpa, 0x100000, gsc_asic->name);
 215         if (res) {
 216                 res->flags = IORESOURCE_MEM;    /* do not mark it busy ! */
 217         }
 218 
 219 #if 0
 220         printk(KERN_WARNING "%s IRQ %d EIM 0x%x", gsc_asic->name,
 221                         parent->irq, gsc_asic->eim);
 222         if (gsc_readl(gsc_asic->hpa + OFFSET_IMR))
 223                 printk("  IMR is non-zero! (0x%x)",
 224                                 gsc_readl(gsc_asic->hpa + OFFSET_IMR));
 225         printk("\n");
 226 #endif
 227 
 228         return 0;
 229 }
 230 
 231 extern struct parisc_driver lasi_driver;
 232 extern struct parisc_driver asp_driver;
 233 extern struct parisc_driver wax_driver;
 234 
 235 void __init gsc_init(void)
 236 {
 237 #ifdef CONFIG_GSC_LASI
 238         register_parisc_driver(&lasi_driver);
 239         register_parisc_driver(&asp_driver);
 240 #endif
 241 #ifdef CONFIG_GSC_WAX
 242         register_parisc_driver(&wax_driver);
 243 #endif
 244 }

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