Home | History | Annotate | Line # | Download | only in ppc
hw_opic.c revision 1.1.1.2
      1 /*  This file is part of the program psim.
      2 
      3     Copyright (C) 1994-1996, Andrew Cagney <cagney (at) highland.com.au>
      4 
      5     This program is free software; you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation; either version 3 of the License, or
      8     (at your option) any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 
     15     You should have received a copy of the GNU General Public License
     16     along with this program; if not, see <http://www.gnu.org/licenses/>.
     17 
     18     */
     19 
     20 
     21 #ifndef _HW_OPIC_C_
     22 #define _HW_OPIC_C_
     23 
     24 #include "device_table.h"
     25 
     26 #ifdef HAVE_STRING_H
     27 #include <string.h>
     28 #else
     29 #ifdef HAVE_STRINGS_H
     30 #include <strings.h>
     31 #endif
     32 #endif
     33 
     34 
     35 /* DEVICE
     36 
     37 
     38    opic - Open Programmable Interrupt Controller (OpenPIC)
     39 
     40 
     41    DESCRIPTION
     42 
     43 
     44    This device implements the core of the OpenPIC interrupt controller
     45    as described in the OpenPIC specification 1.2 and other related
     46    documents.
     47 
     48    The model includes:
     49 
     50    o	Up to 2048 external interrupt sources
     51 
     52    o	The four count down timers
     53 
     54    o	The four interprocessor multicast interrupts
     55 
     56    o	multiprocessor support
     57 
     58    o	Full tracing to assist help debugging
     59 
     60    o	Support for all variations of edge/level x high/low polarity.
     61 
     62 
     63 
     64    PROPERTIES
     65 
     66 
     67    reg = <address> <size> ... (required)
     68 
     69    Determine where the device lives in the parents address space.  The
     70    first <<address>> <<size>> pair specifies the address of the
     71    interrupt destination unit (which might contain an interrupt source
     72    unit) while successive reg entries specify additional interrupt
     73    source units.
     74 
     75    Note that for an <<opic>> device attached to a <<pci>> bus, the
     76    first <<reg>> entry may need to be ignored it will be the address
     77    of the devices configuration registers.
     78 
     79 
     80    interrupt-ranges = <int-number> <range> ... (required)
     81 
     82    A list of pairs.  Each pair corresponds to a block of interrupt
     83    source units (the address of which being specified by the
     84    corresponding reg tupple).  <<int-number>> is the number of the
     85    first interrupt in the block while <<range>> is the number of
     86    interrupts in the block.
     87 
     88 
     89    timer-frequency = <integer>  (optional)
     90 
     91    If present, specifies the default value of the timer frequency
     92    reporting register.  By default a value of 1 HZ is used.  The value
     93    is arbitrary, the timers are always updated once per machine cycle.
     94 
     95 
     96    vendor-identification = <integer>  (optional)
     97 
     98    If present, specifies the value to be returned when the vendor
     99    identification register is read.
    100 
    101 
    102    EXAMPLES
    103 
    104 
    105    See the test suite directory:
    106 
    107    |  psim-test/hw-opic
    108 
    109 
    110    BUGS
    111 
    112    For an OPIC controller attached to a PCI bus, it is not clear what
    113    the value of the <<reg>> and <<interrupt-ranges>> properties should
    114    be.  In particular, the PCI firmware bindings require the first
    115    value of the <<reg>> property to specify the devices configuration
    116    address while the OpenPIC bindings require that same entry to
    117    specify the address of the Interrupt Delivery Unit.  This
    118    implementation checks for and, if present, ignores any
    119    configuration address (and its corresponding <<interrupt-ranges>>
    120    entry).
    121 
    122    The OpenPIC specification requires the controller to be fair when
    123    distributing interrupts between processors.  At present the
    124    algorithm used isn't fair.  It is biased towards processor zero.
    125 
    126    The OpenPIC specification includes a 8259 pass through mode.  This
    127    is not supported.
    128 
    129 
    130    REFERENCES
    131 
    132 
    133    PowerPC Multiprocessor Interrupt Controller (MPIC), January 19,
    134    1996. Available from IBM.
    135 
    136 
    137    The Open Programmable Interrupt Controller (PIC) Register Interface
    138    Specification Revision 1.2.  Issue Date: Opctober 1995.  Available
    139    somewhere on AMD's web page (http://www.amd.com/)
    140 
    141 
    142    PowerPC Microprocessor Common Hardware Reference Platform (CHRP)
    143    System bindings to: IEEE Std 1275-1994 Standard for Boot
    144    (Initialization, Configuration) Firmware.  Revision 1.2b (INTERIM
    145    DRAFT).  April 22, 1996.  Available on the Open Firmware web site
    146    http://playground.sun.com/p1275/.
    147 
    148 
    149    */
    150 
    151 
    152 /* forward types */
    153 
    154 typedef struct _hw_opic_device hw_opic_device;
    155 
    156 
    157 /* bounds */
    158 
    159 enum {
    160   max_nr_interrupt_sources = 2048,
    161   max_nr_interrupt_destinations = 32,
    162   max_nr_task_priorities = 16,
    163 };
    164 
    165 
    166 enum {
    167   opic_alignment = 16,
    168 };
    169 
    170 
    171 /* global configuration register */
    172 
    173 enum {
    174   gcr0_8259_bit = 0x20000000,
    175   gcr0_reset_bit = 0x80000000,
    176 };
    177 
    178 
    179 /* offsets and sizes */
    180 
    181 enum {
    182   idu_isu_base = 0x10000,
    183   sizeof_isu_register_block = 32,
    184   idu_per_processor_register_base = 0x20000,
    185   sizeof_idu_per_processor_register_block = 0x1000,
    186   idu_timer_base = 0x01100,
    187   sizeof_timer_register_block = 0x00040,
    188 };
    189 
    190 
    191 /* Interrupt sources */
    192 
    193 enum {
    194   isu_mask_bit = 0x80000000,
    195   isu_active_bit = 0x40000000,
    196   isu_multicast_bit = 0x20000000,
    197   isu_positive_polarity_bit = 0x00800000,
    198   isu_level_triggered_bit = 0x00400000,
    199   isu_priority_shift = 16,
    200   isu_vector_bits = 0x000000ff,
    201 };
    202 
    203 
    204 typedef struct _opic_interrupt_source {
    205   unsigned is_masked; /* left in place */
    206   unsigned is_multicast; /* left in place */
    207   unsigned is_positive_polarity; /* left in place */
    208   unsigned is_level_triggered; /* left in place */
    209   unsigned priority;
    210   unsigned vector;
    211   /* misc */
    212   int nr;
    213   unsigned destination;
    214   unsigned pending;
    215   unsigned in_service;
    216 } opic_interrupt_source;
    217 
    218 
    219 /* interrupt destinations (normally processors) */
    220 
    221 typedef struct _opic_interrupt_destination {
    222   int nr;
    223   unsigned base_priority;
    224   opic_interrupt_source *current_pending;
    225   opic_interrupt_source *current_in_service;
    226   unsigned bit;
    227   int init_port;
    228   int intr_port;
    229 } opic_interrupt_destination;
    230 
    231 
    232 /* address map descriptors */
    233 
    234 typedef struct _opic_isu_block { /* interrupt source unit block */
    235   int space;
    236   unsigned_word address;
    237   unsigned size;
    238   unsigned_cell int_number;
    239   unsigned_cell range;
    240   int reg;
    241 } opic_isu_block;
    242 
    243 
    244 typedef struct _opic_idu { /* interrupt delivery unit */
    245   int reg;
    246   int space;
    247   unsigned_word address;
    248   unsigned size;
    249 } opic_idu;
    250 
    251 typedef enum {
    252   /* bad */
    253   invalid_opic_register,
    254   /* interrupt source */
    255   interrupt_source_N_destination_register,
    256   interrupt_source_N_vector_priority_register,
    257   /* timers */
    258   timer_N_destination_register,
    259   timer_N_vector_priority_register,
    260   timer_N_base_count_register,
    261   timer_N_current_count_register,
    262   timer_frequency_reporting_register,
    263   /* inter-processor interrupts */
    264   ipi_N_vector_priority_register,
    265   ipi_N_dispatch_register,
    266   /* global configuration */
    267   spurious_vector_register,
    268   processor_init_register,
    269   vendor_identification_register,
    270   global_configuration_register_N,
    271   feature_reporting_register_N,
    272   /* per processor */
    273   end_of_interrupt_register_N,
    274   interrupt_acknowledge_register_N,
    275   current_task_priority_register_N,
    276 } opic_register;
    277 
    278 static const char *
    279 opic_register_name(opic_register type)
    280 {
    281   switch (type) {
    282   case invalid_opic_register: return "invalid_opic_register";
    283   case interrupt_source_N_destination_register: return "interrupt_source_N_destination_register";
    284   case interrupt_source_N_vector_priority_register: return "interrupt_source_N_vector_priority_register";
    285   case timer_N_destination_register: return "timer_N_destination_register";
    286   case timer_N_vector_priority_register: return "timer_N_vector_priority_register";
    287   case timer_N_base_count_register: return "timer_N_base_count_register";
    288   case timer_N_current_count_register: return "timer_N_current_count_register";
    289   case timer_frequency_reporting_register: return "timer_frequency_reporting_register";
    290   case ipi_N_vector_priority_register: return "ipi_N_vector_priority_register";
    291   case ipi_N_dispatch_register: return "ipi_N_dispatch_register";
    292   case spurious_vector_register: return "spurious_vector_register";
    293   case processor_init_register: return "processor_init_register";
    294   case vendor_identification_register: return "vendor_identification_register";
    295   case global_configuration_register_N: return "global_configuration_register_N";
    296   case feature_reporting_register_N: return "feature_reporting_register_N";
    297   case end_of_interrupt_register_N: return "end_of_interrupt_register_N";
    298   case interrupt_acknowledge_register_N: return "interrupt_acknowledge_register_N";
    299   case current_task_priority_register_N: return "current_task_priority_register_N";
    300   }
    301   return NULL;
    302 }
    303 
    304 
    305 
    306 /* timers */
    307 
    308 typedef struct _opic_timer {
    309   int nr;
    310   device *me; /* find my way home */
    311   hw_opic_device *opic; /* ditto */
    312   unsigned base_count;
    313   int inhibited;
    314   signed64 count; /* *ONLY* if inhibited */
    315   event_entry_tag timeout_event;
    316   opic_interrupt_source *interrupt_source;
    317 } opic_timer;
    318 
    319 
    320 /* the OPIC */
    321 
    322 struct _hw_opic_device {
    323 
    324   /* vendor id */
    325   unsigned vendor_identification;
    326 
    327   /* interrupt destinations - processors */
    328   int nr_interrupt_destinations;
    329   opic_interrupt_destination *interrupt_destination;
    330   unsigned sizeof_interrupt_destination;
    331 
    332   /* bogus interrupts */
    333   int spurious_vector;
    334 
    335   /* interrupt sources - external interrupt source units + extra internal ones */
    336   int nr_interrupt_sources;
    337   opic_interrupt_source *interrupt_source;
    338   unsigned sizeof_interrupt_source;
    339 
    340   /* external interrupts */
    341   int nr_external_interrupts;
    342   opic_interrupt_source *external_interrupt_source;
    343 
    344   /* inter-processor-interrupts */
    345   int nr_interprocessor_interrupts;
    346   opic_interrupt_source *interprocessor_interrupt_source;
    347 
    348   /* timers */
    349   int nr_timer_interrupts;
    350   opic_timer *timer;
    351   unsigned sizeof_timer;
    352   opic_interrupt_source *timer_interrupt_source;
    353   unsigned timer_frequency;
    354 
    355   /* init register */
    356   unsigned32 init;
    357 
    358   /* address maps */
    359   opic_idu idu;
    360   int nr_isu_blocks;
    361   opic_isu_block *isu_block;
    362 };
    363 
    364 
    365 static void
    366 hw_opic_init_data(device *me)
    367 {
    368   hw_opic_device *opic = (hw_opic_device*)device_data(me);
    369   int isb;
    370   int idu_reg;
    371   int nr_isu_blocks;
    372   int i;
    373 
    374   /* determine the first valid reg property entry (there could be
    375      leading reg entries with invalid (zero) size fields) and the
    376      number of isu entries found in the reg property. */
    377   idu_reg = 0;
    378   nr_isu_blocks = 0;
    379   while (1) {
    380     reg_property_spec unit;
    381     int attach_space;
    382     unsigned_word attach_address;
    383     unsigned attach_size;
    384     if (!device_find_reg_array_property(me, "reg", idu_reg + nr_isu_blocks,
    385 					&unit))
    386       break;
    387     if (nr_isu_blocks > 0
    388 	|| (device_address_to_attach_address(device_parent(me), &unit.address,
    389 					     &attach_space, &attach_address,
    390 					     me)
    391 	    && device_size_to_attach_size(device_parent(me), &unit.size,
    392 					  &attach_size,
    393 					  me))) {
    394       /* we count any thing once we've found one valid address/size pair */
    395       nr_isu_blocks += 1;
    396     }
    397     else {
    398       idu_reg += 1;
    399     }
    400   }
    401 
    402   /* determine the number and location of the multiple interrupt
    403      source units and the single interrupt delivery unit */
    404   if (opic->isu_block == NULL) {
    405     int reg_nr;
    406     opic->nr_isu_blocks = nr_isu_blocks;
    407     opic->isu_block = zalloc(sizeof(opic_isu_block) * opic->nr_isu_blocks);
    408     isb = 0;
    409     reg_nr = idu_reg;
    410     while (isb < opic->nr_isu_blocks) {
    411       reg_property_spec reg;
    412       if (!device_find_reg_array_property(me, "reg", reg_nr, &reg))
    413 	device_error(me, "reg property missing entry number %d", reg_nr);
    414       opic->isu_block[isb].reg = reg_nr;
    415       if (!device_address_to_attach_address(device_parent(me), &reg.address,
    416 					    &opic->isu_block[isb].space,
    417 					    &opic->isu_block[isb].address,
    418 					    me)
    419 	  || !device_size_to_attach_size(device_parent(me), &reg.size,
    420 					 &opic->isu_block[isb].size,
    421 					 me)) {
    422 	device_error(me, "reg property entry %d invalid", reg_nr);
    423       }
    424       if (!device_find_integer_array_property(me, "interrupt-ranges",
    425 					      reg_nr * 2,
    426 					      &opic->isu_block[isb].int_number)
    427 	  || !device_find_integer_array_property(me, "interrupt-ranges",
    428 						 reg_nr * 2 + 1,
    429 						 &opic->isu_block[isb].range))
    430 	device_error(me, "missing or invalid interrupt-ranges property entry %d", reg_nr);
    431       /* first reg entry specifies the address of both the IDU and the
    432          first set of ISU registers, adjust things accordingly */
    433       if (reg_nr == idu_reg) {
    434 	opic->idu.reg = opic->isu_block[isb].reg;
    435 	opic->idu.space = opic->isu_block[isb].space;
    436 	opic->idu.address = opic->isu_block[isb].address;
    437 	opic->idu.size = opic->isu_block[isb].size;
    438 	opic->isu_block[isb].address += idu_isu_base;
    439 	opic->isu_block[isb].size = opic->isu_block[isb].range * (16 + 16);
    440       }
    441       /* was this a valid reg entry? */
    442       if (opic->isu_block[isb].range == 0) {
    443 	opic->nr_isu_blocks -= 1;
    444       }
    445       else {
    446 	opic->nr_external_interrupts += opic->isu_block[isb].range;
    447 	isb++;
    448       }
    449       reg_nr++;
    450     }
    451   }
    452   DTRACE(opic, ("interrupt source unit block - effective number of blocks %d\n",
    453 		(int)opic->nr_isu_blocks));
    454 
    455 
    456   /* the number of other interrupts */
    457   opic->nr_interprocessor_interrupts = 4;
    458   opic->nr_timer_interrupts = 4;
    459 
    460 
    461   /* create space for the interrupt source registers */
    462   if (opic->interrupt_source != NULL) {
    463     memset(opic->interrupt_source, 0, opic->sizeof_interrupt_source);
    464   }
    465   else {
    466     opic->nr_interrupt_sources = (opic->nr_external_interrupts
    467 				  + opic->nr_interprocessor_interrupts
    468 				  + opic->nr_timer_interrupts);
    469     if (opic->nr_interrupt_sources > max_nr_interrupt_sources)
    470       device_error(me, "number of interrupt sources exceeded");
    471     opic->sizeof_interrupt_source = (sizeof(opic_interrupt_source)
    472 				     * opic->nr_interrupt_sources);
    473     opic->interrupt_source = zalloc(opic->sizeof_interrupt_source);
    474     opic->external_interrupt_source = opic->interrupt_source;
    475     opic->interprocessor_interrupt_source = (opic->external_interrupt_source
    476 					     + opic->nr_external_interrupts);
    477     opic->timer_interrupt_source = (opic->interprocessor_interrupt_source
    478 				    + opic->nr_interprocessor_interrupts);
    479   }
    480   for (i = 0; i < opic->nr_interrupt_sources; i++) {
    481     opic_interrupt_source *source = &opic->interrupt_source[i];
    482     source->nr = i;
    483     source->is_masked = isu_mask_bit;
    484   }
    485   DTRACE(opic, ("interrupt sources - external %d, timer %d, ipi %d, total %d\n",
    486 		opic->nr_external_interrupts,
    487 		opic->nr_timer_interrupts,
    488 		opic->nr_interprocessor_interrupts,
    489 		opic->nr_interrupt_sources));
    490 
    491 
    492   /* timers or interprocessor interrupts */
    493   if (opic->timer != NULL)
    494     memset(opic->timer, 0, opic->sizeof_timer);
    495   else {
    496     opic->nr_timer_interrupts = 4;
    497     opic->sizeof_timer = sizeof(opic_timer) * opic->nr_timer_interrupts;
    498     opic->timer = zalloc(opic->sizeof_timer);
    499   }
    500   for (i = 0; i < opic->nr_timer_interrupts; i++) {
    501     opic_timer *timer = &opic->timer[i];
    502     timer->nr = i;
    503     timer->me = me;
    504     timer->opic = opic;
    505     timer->inhibited = 1;
    506     timer->interrupt_source = &opic->timer_interrupt_source[i];
    507   }
    508   if (device_find_property(me, "timer-frequency"))
    509     opic->timer_frequency = device_find_integer_property(me, "timer-frequency");
    510   else
    511     opic->timer_frequency = 1;
    512 
    513 
    514   /* create space for the interrupt destination registers */
    515   if (opic->interrupt_destination != NULL) {
    516     memset(opic->interrupt_destination, 0, opic->sizeof_interrupt_destination);
    517   }
    518   else {
    519     opic->nr_interrupt_destinations = tree_find_integer_property(me, "/openprom/options/smp");
    520     opic->sizeof_interrupt_destination = (sizeof(opic_interrupt_destination)
    521 					  * opic->nr_interrupt_destinations);
    522     opic->interrupt_destination = zalloc(opic->sizeof_interrupt_destination);
    523     if (opic->nr_interrupt_destinations > max_nr_interrupt_destinations)
    524       device_error(me, "number of interrupt destinations exceeded");
    525   }
    526   for (i = 0; i < opic->nr_interrupt_destinations; i++) {
    527     opic_interrupt_destination *dest = &opic->interrupt_destination[i];
    528     dest->bit = (1 << i);
    529     dest->nr = i;
    530     dest->init_port = (device_interrupt_decode(me, "init0", output_port)
    531 		       + i);
    532     dest->intr_port = (device_interrupt_decode(me, "intr0", output_port)
    533 		       + i);
    534     dest->base_priority = max_nr_task_priorities - 1;
    535   }
    536   DTRACE(opic, ("interrupt destinations - total %d\n",
    537 		(int)opic->nr_interrupt_destinations));
    538 
    539 
    540   /* verify and print out the ISU's */
    541   for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
    542     unsigned correct_size;
    543     if ((opic->isu_block[isb].address % opic_alignment) != 0)
    544       device_error(me, "interrupt source unit %d address not aligned to %d byte boundary",
    545 		   isb, opic_alignment);
    546     correct_size = opic->isu_block[isb].range * sizeof_isu_register_block;
    547     if (opic->isu_block[isb].size != correct_size)
    548       device_error(me, "interrupt source unit %d (reg %d) has an incorrect size, should be 0x%x",
    549 		   isb, opic->isu_block[isb].reg, correct_size);
    550     DTRACE(opic, ("interrupt source unit block %ld - address %d:0x%lx, size 0x%lx, int-number %ld, range %ld\n",
    551 		  (long)isb,
    552 		  (int)opic->isu_block[isb].space,
    553 		  (unsigned long)opic->isu_block[isb].address,
    554 		  (unsigned long)opic->isu_block[isb].size,
    555 		  (long)opic->isu_block[isb].int_number,
    556 		  (long)opic->isu_block[isb].range));
    557   }
    558 
    559 
    560   /* verify and print out the IDU */
    561   {
    562     unsigned correct_size;
    563     unsigned alternate_size;
    564     if ((opic->idu.address % opic_alignment) != 0)
    565       device_error(me, "interrupt delivery unit not aligned to %d byte boundary",
    566 		   opic_alignment);
    567     correct_size = (idu_per_processor_register_base
    568 		    + (sizeof_idu_per_processor_register_block
    569 		       * opic->nr_interrupt_destinations));
    570     alternate_size = (idu_per_processor_register_base
    571 		      + (sizeof_idu_per_processor_register_block
    572 			 * max_nr_interrupt_destinations));
    573     if (opic->idu.size != correct_size
    574 	&& opic->idu.size != alternate_size)
    575       device_error(me, "interrupt delivery unit has incorrect size, should be 0x%x or 0x%x",
    576 		   correct_size, alternate_size);
    577     DTRACE(opic, ("interrupt delivery unit - address %d:0x%lx, size 0x%lx\n",
    578 		  (int)opic->idu.space,
    579 		  (unsigned long)opic->idu.address,
    580 		  (unsigned long)opic->idu.size));
    581   }
    582 
    583   /* initialize the init interrupts */
    584   opic->init = 0;
    585 
    586 
    587   /* vendor ident */
    588   if (device_find_property(me, "vendor-identification") != NULL)
    589     opic->vendor_identification = device_find_integer_property(me, "vendor-identification");
    590   else
    591     opic->vendor_identification = 0;
    592 
    593   /* misc registers */
    594   opic->spurious_vector = 0xff;
    595 
    596 }
    597 
    598 
    599 /* interrupt related actions */
    600 
    601 static void
    602 assert_interrupt(device *me,
    603 		 hw_opic_device *opic,
    604 		 opic_interrupt_destination *dest)
    605 {
    606   ASSERT(dest >= opic->interrupt_destination);
    607   ASSERT(dest < opic->interrupt_destination + opic->nr_interrupt_destinations);
    608   DTRACE(opic, ("assert interrupt - intr port %d\n", dest->intr_port));
    609   device_interrupt_event(me, dest->intr_port, 1, NULL, 0);
    610 }
    611 
    612 
    613 static void
    614 negate_interrupt(device *me,
    615 		 hw_opic_device *opic,
    616 		 opic_interrupt_destination *dest)
    617 {
    618   ASSERT(dest >= opic->interrupt_destination);
    619   ASSERT(dest < opic->interrupt_destination + opic->nr_interrupt_destinations);
    620   DTRACE(opic, ("negate interrupt - intr port %d\n", dest->intr_port));
    621   device_interrupt_event(me, dest->intr_port, 0, NULL, 0);
    622 }
    623 
    624 
    625 static int
    626 can_deliver(device *me,
    627 	    opic_interrupt_source *source,
    628 	    opic_interrupt_destination *dest)
    629 {
    630   return (source != NULL && dest != NULL
    631 	  && source->priority > dest->base_priority
    632 	  && (dest->current_in_service == NULL
    633 	      || source->priority > dest->current_in_service->priority));
    634 }
    635 
    636 
    637 static unsigned
    638 deliver_pending(device *me,
    639 		hw_opic_device *opic,
    640 		opic_interrupt_destination *dest)
    641 {
    642   ASSERT(can_deliver(me, dest->current_pending, dest));
    643   dest->current_in_service = dest->current_pending;
    644   dest->current_in_service->in_service |= dest->bit;
    645   if (!dest->current_pending->is_level_triggered) {
    646     if (dest->current_pending->is_multicast)
    647       dest->current_pending->pending &= ~dest->bit;
    648     else
    649       dest->current_pending->pending = 0;
    650   }
    651   dest->current_pending = NULL;
    652   negate_interrupt(me, opic, dest);
    653   return dest->current_in_service->vector;
    654 }
    655 
    656 
    657 typedef enum {
    658   pending_interrupt,
    659   in_service_interrupt,
    660 } interrupt_class;
    661 
    662 static opic_interrupt_source *
    663 find_interrupt_for_dest(device *me,
    664 			hw_opic_device *opic,
    665 			opic_interrupt_destination *dest,
    666 			interrupt_class class)
    667 {
    668   int i;
    669   opic_interrupt_source *pending = NULL;
    670   for (i = 0; i < opic->nr_interrupt_sources; i++) {
    671     opic_interrupt_source *src = &opic->interrupt_source[i];
    672     /* is this a potential hit? */
    673     switch (class) {
    674     case in_service_interrupt:
    675       if ((src->in_service & dest->bit) == 0)
    676 	continue;
    677       break;
    678     case pending_interrupt:
    679       if ((src->pending & dest->bit) == 0)
    680 	continue;
    681       break;
    682     }
    683     /* see if it is the highest priority */
    684     if (pending == NULL)
    685       pending = src;
    686     else if (src->priority > pending->priority)
    687       pending = src;
    688   }
    689   return pending;
    690 }
    691 
    692 
    693 static opic_interrupt_destination *
    694 find_lowest_dest(device *me,
    695 		 hw_opic_device *opic,
    696 		 opic_interrupt_source *src)
    697 {
    698   int i;
    699   opic_interrupt_destination *lowest = NULL;
    700   for (i = 0; i < opic->nr_interrupt_destinations; i++) {
    701     opic_interrupt_destination *dest = &opic->interrupt_destination[i];
    702     if (src->destination & dest->bit) {
    703       if (dest->base_priority < src->priority) {
    704 	if (lowest == NULL)
    705 	  lowest = dest;
    706 	else if (lowest->base_priority > dest->base_priority)
    707 	  lowest = dest;
    708 	else if (lowest->current_in_service != NULL
    709 		 && dest->current_in_service == NULL)
    710 	  lowest = dest; /* not doing anything */
    711 	else if (lowest->current_in_service != NULL
    712 		 && dest->current_in_service != NULL
    713 		 && (lowest->current_in_service->priority
    714 		     > dest->current_in_service->priority))
    715 	  lowest = dest; /* less urgent */
    716 	/* FIXME - need to be more fair */
    717       }
    718     }
    719   }
    720   return lowest;
    721 }
    722 
    723 
    724 static void
    725 handle_interrupt(device *me,
    726 		 hw_opic_device *opic,
    727 		 opic_interrupt_source *src,
    728 		 int asserted)
    729 {
    730   if (src->is_masked) {
    731     DTRACE(opic, ("interrupt %d - ignore masked\n", src->nr));
    732   }
    733   else if (src->is_multicast) {
    734     /* always try to deliver multicast interrupts - just easier */
    735     int i;
    736     ASSERT(!src->is_level_triggered);
    737     ASSERT(src->is_positive_polarity);
    738     ASSERT(asserted);
    739     for (i = 0; i < opic->nr_interrupt_destinations; i++) {
    740       opic_interrupt_destination *dest = &opic->interrupt_destination[i];
    741       if (src->destination & dest->bit) {
    742 	if (src->pending & dest->bit) {
    743 	  DTRACE(opic, ("interrupt %d - multicast still pending to %d\n",
    744 			src->nr, dest->nr));
    745 	}
    746 	else if (can_deliver(me, src, dest)) {
    747 	  dest->current_pending = src;
    748 	  src->pending |= dest->bit;
    749 	  assert_interrupt(me, opic, dest);
    750 	  DTRACE(opic, ("interrupt %d - multicast to %d\n",
    751 			src->nr, dest->nr));
    752 	}
    753 	else {
    754 	  src->pending |= dest->bit;
    755 	  DTRACE(opic, ("interrupt %d - multicast pending to %d\n",
    756 			src->nr, dest->nr));
    757 	}
    758       }
    759     }
    760   }
    761   else if (src->is_level_triggered
    762 	   && src->is_positive_polarity
    763 	   && !asserted) {
    764     if (src->pending)
    765       DTRACE(opic, ("interrupt %d - ignore withdrawn (active high)\n",
    766 		    src->nr));
    767     else
    768       DTRACE(opic, ("interrupt %d - ignore low level (active high)\n",
    769 		    src->nr));
    770     ASSERT(!src->is_multicast);
    771     src->pending = 0;
    772   }
    773   else if (src->is_level_triggered
    774 	   && !src->is_positive_polarity
    775 	   && asserted) {
    776     if (src->pending)
    777       DTRACE(opic, ("interrupt %d - ignore withdrawn (active low)\n",
    778 		    src->nr));
    779     else
    780       DTRACE(opic, ("interrupt %d - ignore high level (active low)\n",
    781 		    src->nr));
    782 
    783     ASSERT(!src->is_multicast);
    784     src->pending = 0;
    785   }
    786   else if (!src->is_level_triggered
    787 	   && src->is_positive_polarity
    788 	   && !asserted) {
    789     DTRACE(opic, ("interrupt %d - ignore falling edge (positive edge trigered)\n",
    790 		  src->nr));
    791   }
    792   else if (!src->is_level_triggered
    793 	   && !src->is_positive_polarity
    794 	   && asserted) {
    795     DTRACE(opic, ("interrupt %d - ignore rising edge (negative edge trigered)\n",
    796 		  src->nr));
    797   }
    798   else if (src->in_service != 0) {
    799     /* leave the interrupt where it is */
    800     ASSERT(!src->is_multicast);
    801     ASSERT(src->pending == 0 || src->pending == src->in_service);
    802     src->pending = src->in_service;
    803     DTRACE(opic, ("interrupt %ld - ignore already in service to 0x%lx\n",
    804 		  (long)src->nr, (long)src->in_service));
    805   }
    806   else if (src->pending != 0) {
    807     DTRACE(opic, ("interrupt %ld - ignore still pending to 0x%lx\n",
    808 		  (long)src->nr, (long)src->pending));
    809   }
    810   else {
    811     /* delivery is needed */
    812     opic_interrupt_destination *dest = find_lowest_dest(me, opic, src);
    813     if (can_deliver(me, src, dest)) {
    814       dest->current_pending = src;
    815       src->pending = dest->bit;
    816       DTRACE(opic, ("interrupt %d - delivered to %d\n", src->nr, dest->nr));
    817       assert_interrupt(me, opic, dest);
    818     }
    819     else {
    820       src->pending = src->destination; /* any can take this */
    821       DTRACE(opic, ("interrupt %ld - pending to 0x%lx\n",
    822 		    (long)src->nr, (long)src->pending));
    823     }
    824   }
    825 }
    826 
    827 static unsigned
    828 do_interrupt_acknowledge_register_N_read(device *me,
    829 					 hw_opic_device *opic,
    830 					 int dest_nr)
    831 {
    832   opic_interrupt_destination *dest = &opic->interrupt_destination[dest_nr];
    833   unsigned vector;
    834 
    835   ASSERT(dest_nr >= 0 && dest_nr < opic->nr_interrupt_destinations);
    836   ASSERT(dest_nr == dest->nr);
    837 
    838   /* try the current pending */
    839   if (can_deliver(me, dest->current_pending, dest)) {
    840     ASSERT(dest->current_pending->pending & dest->bit);
    841     vector = deliver_pending(me, opic, dest);
    842     DTRACE(opic, ("interrupt ack %d - entering %d (pending) - vector %d (%d), priority %d\n",
    843 		  dest->nr,
    844 		  dest->current_in_service->nr,
    845 		  dest->current_in_service->vector, vector,
    846 		  dest->current_in_service->priority));
    847   }
    848   else {
    849     /* try for something else */
    850     dest->current_pending = find_interrupt_for_dest(me, opic, dest, pending_interrupt);
    851     if (can_deliver(me, dest->current_pending, dest)) {
    852       vector = deliver_pending(me, opic, dest);
    853       DTRACE(opic, ("interrupt ack %d - entering %d (not pending) - vector %d (%d), priority %d\n",
    854 		    dest->nr,
    855 		    dest->current_in_service->nr,
    856 		    dest->current_in_service->vector, vector,
    857 		    dest->current_in_service->priority));
    858     }
    859     else {
    860       dest->current_pending = NULL;
    861       vector = opic->spurious_vector;
    862       DTRACE(opic, ("interrupt ack %d - spurious interrupt %d\n",
    863 		    dest->nr, vector));
    864     }
    865   }
    866   return vector;
    867 }
    868 
    869 
    870 static void
    871 do_end_of_interrupt_register_N_write(device *me,
    872 				     hw_opic_device *opic,
    873 				     int dest_nr,
    874 				     unsigned reg)
    875 {
    876   opic_interrupt_destination *dest = &opic->interrupt_destination[dest_nr];
    877 
    878   ASSERT(dest_nr >= 0 && dest_nr < opic->nr_interrupt_destinations);
    879   ASSERT(dest_nr == dest->nr);
    880 
    881   /* check the value written is zero */
    882   if (reg != 0) {
    883     DTRACE(opic, ("eoi %d - ignoring nonzero value\n", dest->nr));
    884   }
    885 
    886   /* user doing wierd things? */
    887   if (dest->current_in_service == NULL) {
    888     DTRACE(opic, ("eoi %d - strange, no current interrupt\n", dest->nr));
    889     return;
    890   }
    891 
    892   /* an internal stuff up? */
    893   if (!(dest->current_in_service->in_service & dest->bit)) {
    894     device_error(me, "eoi %d - current interrupt not in service", dest->nr);
    895   }
    896 
    897   /* find what was probably the previous in service interrupt */
    898   dest->current_in_service->in_service &= ~dest->bit;
    899   DTRACE(opic, ("eoi %d - ending %d - priority %d, vector %d\n",
    900 		dest->nr,
    901 		dest->current_in_service->nr,
    902 		dest->current_in_service->priority,
    903 		dest->current_in_service->vector));
    904   dest->current_in_service = find_interrupt_for_dest(me, opic, dest, in_service_interrupt);
    905   if (dest->current_in_service != NULL)
    906     DTRACE(opic, ("eoi %d - resuming %d - priority %d, vector %d\n",
    907 		  dest->nr,
    908 		  dest->current_in_service->nr,
    909 		  dest->current_in_service->priority,
    910 		  dest->current_in_service->vector));
    911   else
    912     DTRACE(opic, ("eoi %d - resuming none\n", dest->nr));
    913 
    914   /* check to see if that shouldn't be interrupted */
    915   dest->current_pending = find_interrupt_for_dest(me, opic, dest, pending_interrupt);
    916   if (can_deliver(me, dest->current_pending, dest)) {
    917     ASSERT(dest->current_pending->pending & dest->bit);
    918     assert_interrupt(me, opic, dest);
    919   }
    920   else {
    921     dest->current_pending = NULL;
    922   }
    923 }
    924 
    925 
    926 static void
    927 decode_opic_address(device *me,
    928 		    hw_opic_device *opic,
    929 		    int space,
    930 		    unsigned_word address,
    931 		    unsigned nr_bytes,
    932 		    opic_register *type,
    933 		    int *index)
    934 {
    935   int isb = 0;
    936 
    937   /* is the size valid? */
    938   if (nr_bytes != 4) {
    939     *type = invalid_opic_register;
    940     *index = -1;
    941     return;
    942   }
    943 
    944   /* try for a per-processor register within the interrupt delivery
    945      unit */
    946   if (space == opic->idu.space
    947       && address >= (opic->idu.address + idu_per_processor_register_base)
    948       && address < (opic->idu.address + idu_per_processor_register_base
    949 		    + (sizeof_idu_per_processor_register_block
    950 		       * opic->nr_interrupt_destinations))) {
    951     unsigned_word block_offset = (address
    952 				  - opic->idu.address
    953 				  - idu_per_processor_register_base);
    954     unsigned_word offset = block_offset % sizeof_idu_per_processor_register_block;
    955     *index = block_offset / sizeof_idu_per_processor_register_block;
    956     switch (offset) {
    957     case 0x040:
    958       *type = ipi_N_dispatch_register;
    959       *index = 0;
    960       break;
    961     case 0x050:
    962       *type = ipi_N_dispatch_register;
    963       *index = 1;
    964       break;
    965     case 0x060:
    966       *type = ipi_N_dispatch_register;
    967       *index = 2;
    968       break;
    969     case 0x070:
    970       *type = ipi_N_dispatch_register;
    971       *index = 3;
    972       break;
    973     case 0x080:
    974       *type = current_task_priority_register_N;
    975       break;
    976     case 0x0a0:
    977       *type = interrupt_acknowledge_register_N;
    978       break;
    979     case 0x0b0:
    980       *type = end_of_interrupt_register_N;
    981       break;
    982     default:
    983       *type = invalid_opic_register;
    984       break;
    985     }
    986     DTRACE(opic, ("per-processor register %d:0x%lx - %s[%d]\n",
    987 		  space, (unsigned long)address,
    988 		  opic_register_name(*type),
    989 		  *index));
    990     return;
    991   }
    992 
    993   /* try for an interrupt source unit */
    994   for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
    995     if (opic->isu_block[isb].space == space
    996 	&& address >= opic->isu_block[isb].address
    997 	&& address < (opic->isu_block[isb].address + opic->isu_block[isb].size)) {
    998       unsigned_word block_offset = address - opic->isu_block[isb].address;
    999       unsigned_word offset = block_offset % sizeof_isu_register_block;
   1000       *index = (opic->isu_block[isb].int_number
   1001 		+ (block_offset / sizeof_isu_register_block));
   1002       switch (offset) {
   1003       case 0x00:
   1004 	*type = interrupt_source_N_vector_priority_register;
   1005 	break;
   1006       case 0x10:
   1007 	*type = interrupt_source_N_destination_register;
   1008 	break;
   1009       default:
   1010 	*type = invalid_opic_register;
   1011 	break;
   1012       }
   1013       DTRACE(opic, ("isu register %d:0x%lx - %s[%d]\n",
   1014 		    space, (unsigned long)address,
   1015 		    opic_register_name(*type),
   1016 		    *index));
   1017       return;
   1018     }
   1019   }
   1020 
   1021   /* try for a timer */
   1022   if (space == opic->idu.space
   1023       && address >= (opic->idu.address + idu_timer_base)
   1024       && address < (opic->idu.address + idu_timer_base
   1025 		    + opic->nr_timer_interrupts * sizeof_timer_register_block)) {
   1026     unsigned_word offset = address % sizeof_timer_register_block;
   1027     *index = ((address - opic->idu.address - idu_timer_base)
   1028 	      / sizeof_timer_register_block);
   1029     switch (offset) {
   1030     case 0x00:
   1031       *type = timer_N_current_count_register;
   1032       break;
   1033     case 0x10:
   1034       *type = timer_N_base_count_register;
   1035       break;
   1036     case 0x20:
   1037       *type = timer_N_vector_priority_register;
   1038       break;
   1039     case 0x30:
   1040       *type = timer_N_destination_register;
   1041       break;
   1042     default:
   1043       *type = invalid_opic_register;
   1044       break;
   1045     }
   1046     DTRACE(opic, ("timer register %d:0x%lx - %s[%d]\n",
   1047 		  space, (unsigned long)address,
   1048 		  opic_register_name(*type),
   1049 		  *index));
   1050     return;
   1051   }
   1052 
   1053   /* finally some other misc global register */
   1054   if (space == opic->idu.space
   1055       && address >= opic->idu.address
   1056       && address < opic->idu.address + opic->idu.size) {
   1057     unsigned_word block_offset = address - opic->idu.address;
   1058     switch (block_offset) {
   1059     case 0x010f0:
   1060       *type = timer_frequency_reporting_register;
   1061       *index = -1;
   1062       break;
   1063     case 0x010e0:
   1064       *type = spurious_vector_register;
   1065       *index = -1;
   1066       break;
   1067     case 0x010d0:
   1068     case 0x010c0:
   1069     case 0x010b0:
   1070     case 0x010a0:
   1071       *type = ipi_N_vector_priority_register;
   1072       *index = (block_offset - 0x010a0) / 16;
   1073       break;
   1074     case 0x01090:
   1075       *type = processor_init_register;
   1076       *index = -1;
   1077       break;
   1078     case 0x01080:
   1079       *type = vendor_identification_register;
   1080       *index = -1;
   1081       break;
   1082     case 0x01020:
   1083       *type = global_configuration_register_N;
   1084       *index = 0;
   1085       break;
   1086     case 0x01000:
   1087       *type = feature_reporting_register_N;
   1088       *index = 0;
   1089       break;
   1090     default:
   1091       *type = invalid_opic_register;
   1092       *index = -1;
   1093       break;
   1094     }
   1095     DTRACE(opic, ("global register %d:0x%lx - %s[%d]\n",
   1096 		  space, (unsigned long)address,
   1097 		  opic_register_name(*type),
   1098 		  *index));
   1099     return;
   1100   }
   1101 
   1102   /* nothing matched */
   1103   *type = invalid_opic_register;
   1104   DTRACE(opic, ("invalid register %d:0x%lx\n",
   1105 		space, (unsigned long)address));
   1106   return;
   1107 }
   1108 
   1109 
   1110 /* Processor init register:
   1111 
   1112    The bits in this register (one per processor) are directly wired to
   1113    output "init" interrupt ports. */
   1114 
   1115 static unsigned
   1116 do_processor_init_register_read(device *me,
   1117 				hw_opic_device *opic)
   1118 {
   1119   unsigned reg = opic->init;
   1120   DTRACE(opic, ("processor init register - read 0x%lx\n",
   1121 		(long)reg));
   1122   return reg;
   1123 }
   1124 
   1125 static void
   1126 do_processor_init_register_write(device *me,
   1127 				 hw_opic_device *opic,
   1128 				 unsigned reg)
   1129 {
   1130   int i;
   1131   for (i = 0; i < opic->nr_interrupt_destinations; i++) {
   1132     opic_interrupt_destination *dest = &opic->interrupt_destination[i];
   1133     if ((reg & dest->bit) != (opic->init & dest->bit)) {
   1134       if (reg & dest->bit) {
   1135 	DTRACE(opic, ("processor init register - write 0x%lx - asserting init%d\n",
   1136 		      (long)reg, i));
   1137 	opic->init |= dest->bit;
   1138 	device_interrupt_event(me, dest->init_port, 1, NULL, 0);
   1139       }
   1140       else {
   1141 	DTRACE(opic, ("processor init register - write 0x%lx - negating init%d\n",
   1142 		      (long)reg, i));
   1143 	opic->init &= ~dest->bit;
   1144 	device_interrupt_event(me, dest->init_port, 0, NULL, 0);
   1145       }
   1146     }
   1147   }
   1148 }
   1149 
   1150 
   1151 
   1152 /* Interrupt Source Vector/Priority Register: */
   1153 
   1154 static unsigned
   1155 read_vector_priority_register(device *me,
   1156 			      hw_opic_device *opic,
   1157 			      opic_interrupt_source *interrupt,
   1158 			      const char *reg_name,
   1159 			      int reg_index)
   1160 {
   1161   unsigned reg;
   1162   reg = 0;
   1163   reg |= interrupt->is_masked;
   1164   reg |= (interrupt->in_service || interrupt->pending
   1165 	  ? isu_active_bit : 0); /* active */
   1166   reg |= interrupt->is_multicast;
   1167   reg |= interrupt->is_positive_polarity;
   1168   reg |= interrupt->is_level_triggered; /* sense? */
   1169   reg |= interrupt->priority << isu_priority_shift;
   1170   reg |= interrupt->vector;
   1171   DTRACE(opic, ("%s %d vector/priority register - read 0x%lx\n",
   1172 		reg_name, reg_index, (unsigned long)reg));
   1173   return reg;
   1174 }
   1175 
   1176 static unsigned
   1177 do_interrupt_source_N_vector_priority_register_read(device *me,
   1178 						    hw_opic_device *opic,
   1179 						    int index)
   1180 {
   1181   unsigned reg;
   1182   ASSERT(index < opic->nr_external_interrupts);
   1183   reg = read_vector_priority_register(me, opic,
   1184 				      &opic->interrupt_source[index],
   1185 				      "interrupt source", index);
   1186   return reg;
   1187 }
   1188 
   1189 static void
   1190 write_vector_priority_register(device *me,
   1191 			       hw_opic_device *opic,
   1192 			       opic_interrupt_source *interrupt,
   1193 			       unsigned reg,
   1194 			       const char *reg_name,
   1195 			       int reg_index)
   1196 {
   1197   interrupt->is_masked = (reg & isu_mask_bit);
   1198   interrupt->is_multicast = (reg & isu_multicast_bit);
   1199   interrupt->is_positive_polarity = (reg & isu_positive_polarity_bit);
   1200   interrupt->is_level_triggered = (reg & isu_level_triggered_bit);
   1201   interrupt->priority = ((reg >> isu_priority_shift)
   1202 			 % max_nr_task_priorities);
   1203   interrupt->vector = (reg & isu_vector_bits);
   1204   DTRACE(opic, ("%s %d vector/priority register - write 0x%lx - %s%s%s-polarity, %s-triggered, priority %ld vector %ld\n",
   1205 		reg_name,
   1206 		reg_index,
   1207 		(unsigned long)reg,
   1208 		interrupt->is_masked ? "masked, " : "",
   1209 		interrupt->is_multicast ? "multicast, " : "",
   1210 		interrupt->is_positive_polarity ? "positive" : "negative",
   1211 		interrupt->is_level_triggered ? "level" : "edge",
   1212 		(long)interrupt->priority,
   1213 		(long)interrupt->vector));
   1214 }
   1215 
   1216 static void
   1217 do_interrupt_source_N_vector_priority_register_write(device *me,
   1218 						     hw_opic_device *opic,
   1219 						     int index,
   1220 						     unsigned reg)
   1221 {
   1222   ASSERT(index < opic->nr_external_interrupts);
   1223   reg &= ~isu_multicast_bit; /* disable multicast */
   1224   write_vector_priority_register(me, opic,
   1225 				 &opic->interrupt_source[index],
   1226 				 reg, "interrupt source", index);
   1227 }
   1228 
   1229 
   1230 
   1231 /* Interrupt Source Destination Register: */
   1232 
   1233 static unsigned
   1234 read_destination_register(device *me,
   1235 			  hw_opic_device *opic,
   1236 			  opic_interrupt_source *interrupt,
   1237 			  const char *reg_name,
   1238 			  int reg_index)
   1239 {
   1240   unsigned long reg;
   1241   reg = interrupt->destination;
   1242   DTRACE(opic, ("%s %d destination register - read 0x%lx\n",
   1243 		reg_name, reg_index, reg));
   1244   return reg;
   1245 }
   1246 
   1247 static unsigned
   1248 do_interrupt_source_N_destination_register_read(device *me,
   1249 						hw_opic_device *opic,
   1250 						int index)
   1251 {
   1252   unsigned reg;
   1253   ASSERT(index < opic->nr_external_interrupts);
   1254   reg = read_destination_register(me, opic, &opic->external_interrupt_source[index],
   1255 				  "interrupt source", index);
   1256   return reg;
   1257 }
   1258 
   1259 static void
   1260 write_destination_register(device *me,
   1261 			   hw_opic_device *opic,
   1262 			   opic_interrupt_source *interrupt,
   1263 			   unsigned reg,
   1264 			   const char *reg_name,
   1265 			   int reg_index)
   1266 {
   1267   reg &= (1 << opic->nr_interrupt_destinations) - 1; /* mask out invalid */
   1268   DTRACE(opic, ("%s %d destination register - write 0x%x\n",
   1269 		reg_name, reg_index, reg));
   1270   interrupt->destination = reg;
   1271 }
   1272 
   1273 static void
   1274 do_interrupt_source_N_destination_register_write(device *me,
   1275 						 hw_opic_device *opic,
   1276 						 int index,
   1277 						 unsigned reg)
   1278 {
   1279   ASSERT(index < opic->nr_external_interrupts);
   1280   write_destination_register(me, opic, &opic->external_interrupt_source[index],
   1281 			     reg, "interrupt source", index);
   1282 }
   1283 
   1284 
   1285 
   1286 /* Spurious vector register: */
   1287 
   1288 static unsigned
   1289 do_spurious_vector_register_read(device *me,
   1290 				 hw_opic_device *opic)
   1291 {
   1292   unsigned long reg = opic->spurious_vector;
   1293   DTRACE(opic, ("spurious vector register - read 0x%lx\n", reg));
   1294   return reg;
   1295 }
   1296 
   1297 static void
   1298 do_spurious_vector_register_write(device *me,
   1299 				  hw_opic_device *opic,
   1300 				  unsigned reg)
   1301 {
   1302   reg &= 0xff; /* mask off invalid */
   1303   DTRACE(opic, ("spurious vector register - write 0x%x\n", reg));
   1304   opic->spurious_vector = reg;
   1305 }
   1306 
   1307 
   1308 
   1309 /* current task priority register: */
   1310 
   1311 static unsigned
   1312 do_current_task_priority_register_N_read(device *me,
   1313 					 hw_opic_device *opic,
   1314 					 int index)
   1315 {
   1316   opic_interrupt_destination *interrupt_destination = &opic->interrupt_destination[index];
   1317   unsigned reg;
   1318   ASSERT(index >= 0 && index < opic->nr_interrupt_destinations);
   1319   reg = interrupt_destination->base_priority;
   1320   DTRACE(opic, ("current task priority register %d - read 0x%x\n", index, reg));
   1321   return reg;
   1322 }
   1323 
   1324 static void
   1325 do_current_task_priority_register_N_write(device *me,
   1326 					  hw_opic_device *opic,
   1327 					  int index,
   1328 					  unsigned reg)
   1329 {
   1330   opic_interrupt_destination *interrupt_destination = &opic->interrupt_destination[index];
   1331   ASSERT(index >= 0 && index < opic->nr_interrupt_destinations);
   1332   reg %= max_nr_task_priorities;
   1333   DTRACE(opic, ("current task priority register %d - write 0x%x\n", index, reg));
   1334   interrupt_destination->base_priority = reg;
   1335 }
   1336 
   1337 
   1338 
   1339 /* Timer Frequency Reporting Register: */
   1340 
   1341 static unsigned
   1342 do_timer_frequency_reporting_register_read(device *me,
   1343 					   hw_opic_device *opic)
   1344 {
   1345   unsigned reg;
   1346   reg = opic->timer_frequency;
   1347   DTRACE(opic, ("timer frequency reporting register - read 0x%x\n", reg));
   1348   return reg;
   1349 }
   1350 
   1351 static void
   1352 do_timer_frequency_reporting_register_write(device *me,
   1353 					    hw_opic_device *opic,
   1354 					    unsigned reg)
   1355 {
   1356   DTRACE(opic, ("timer frequency reporting register - write 0x%x\n", reg));
   1357   opic->timer_frequency = reg;
   1358 }
   1359 
   1360 
   1361 /* timer registers: */
   1362 
   1363 static unsigned
   1364 do_timer_N_current_count_register_read(device *me,
   1365 				       hw_opic_device *opic,
   1366 				       int index)
   1367 {
   1368   opic_timer *timer = &opic->timer[index];
   1369   unsigned reg;
   1370   ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
   1371   if (timer->inhibited)
   1372     reg = timer->count; /* stalled value */
   1373   else
   1374     reg = timer->count - device_event_queue_time(me); /* time remaining */
   1375   DTRACE(opic, ("timer %d current count register - read 0x%x\n", index, reg));
   1376   return reg;
   1377 }
   1378 
   1379 
   1380 static unsigned
   1381 do_timer_N_base_count_register_read(device *me,
   1382 				    hw_opic_device *opic,
   1383 				    int index)
   1384 {
   1385   opic_timer *timer = &opic->timer[index];
   1386   unsigned reg;
   1387   ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
   1388   reg = timer->base_count;
   1389   DTRACE(opic, ("timer %d base count register - read 0x%x\n", index, reg));
   1390   return reg;
   1391 }
   1392 
   1393 
   1394 static void
   1395 timer_event(void *data)
   1396 {
   1397   opic_timer *timer = data;
   1398   device *me = timer->me;
   1399   if (timer->inhibited)
   1400     device_error(timer->me, "internal-error - timer event occured when timer %d inhibited",
   1401 		 timer->nr);
   1402   handle_interrupt(timer->me, timer->opic, timer->interrupt_source, 1);
   1403   timer->timeout_event = device_event_queue_schedule(me, timer->base_count,
   1404 						     timer_event, timer);
   1405   DTRACE(opic, ("timer %d - interrupt at %ld, next at %d\n",
   1406 		timer->nr, (long)device_event_queue_time(me), timer->base_count));
   1407 }
   1408 
   1409 
   1410 static void
   1411 do_timer_N_base_count_register_write(device *me,
   1412 				     hw_opic_device *opic,
   1413 				     int index,
   1414 				     unsigned reg)
   1415 {
   1416   opic_timer *timer = &opic->timer[index];
   1417   int inhibit;
   1418   ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
   1419   inhibit = reg & 0x80000000;
   1420   if (timer->inhibited && !inhibit) {
   1421     timer->inhibited = 0;
   1422     if (timer->timeout_event != NULL)
   1423       device_event_queue_deschedule(me, timer->timeout_event);
   1424     timer->count = device_event_queue_time(me) + reg;
   1425     timer->base_count = reg;
   1426     timer->timeout_event = device_event_queue_schedule(me, timer->base_count,
   1427 						       timer_event, (void*)timer);
   1428     DTRACE(opic, ("timer %d base count register - write 0x%x - timer started\n",
   1429 		  index, reg));
   1430   }
   1431   else if (!timer->inhibited && inhibit) {
   1432     if (timer->timeout_event != NULL)
   1433       device_event_queue_deschedule(me, timer->timeout_event);
   1434     timer->count = timer->count - device_event_queue_time(me);
   1435     timer->inhibited = 1;
   1436     timer->base_count = reg;
   1437     DTRACE(opic, ("timer %d base count register - write 0x%x - timer stopped\n",
   1438 		  index, reg));
   1439   }
   1440   else {
   1441     ASSERT((timer->inhibited && inhibit) || (!timer->inhibited && !inhibit));
   1442     DTRACE(opic, ("timer %d base count register - write 0x%x\n", index, reg));
   1443     timer->base_count = reg;
   1444   }
   1445 }
   1446 
   1447 
   1448 static unsigned
   1449 do_timer_N_vector_priority_register_read(device *me,
   1450 					 hw_opic_device *opic,
   1451 					 int index)
   1452 {
   1453   unsigned reg;
   1454   ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
   1455   reg = read_vector_priority_register(me, opic,
   1456 				      &opic->timer_interrupt_source[index],
   1457 				      "timer", index);
   1458   return reg;
   1459 }
   1460 
   1461 static void
   1462 do_timer_N_vector_priority_register_write(device *me,
   1463 					  hw_opic_device *opic,
   1464 					  int index,
   1465 					  unsigned reg)
   1466 {
   1467   ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
   1468   reg &= ~isu_level_triggered_bit; /* force edge trigger */
   1469   reg |= isu_positive_polarity_bit; /* force rising (positive) edge */
   1470   reg |= isu_multicast_bit; /* force multicast */
   1471   write_vector_priority_register(me, opic,
   1472 				 &opic->timer_interrupt_source[index],
   1473 				 reg, "timer", index);
   1474 }
   1475 
   1476 
   1477 static unsigned
   1478 do_timer_N_destination_register_read(device *me,
   1479 				     hw_opic_device *opic,
   1480 				     int index)
   1481 {
   1482   unsigned reg;
   1483   ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
   1484   reg = read_destination_register(me, opic, &opic->timer_interrupt_source[index],
   1485 				  "timer", index);
   1486   return reg;
   1487 }
   1488 
   1489 static void
   1490 do_timer_N_destination_register_write(device *me,
   1491 				      hw_opic_device *opic,
   1492 				      int index,
   1493 				      unsigned reg)
   1494 {
   1495   ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
   1496   write_destination_register(me, opic, &opic->timer_interrupt_source[index],
   1497 			     reg, "timer", index);
   1498 }
   1499 
   1500 
   1501 /* IPI registers */
   1502 
   1503 static unsigned
   1504 do_ipi_N_vector_priority_register_read(device *me,
   1505 				       hw_opic_device *opic,
   1506 				       int index)
   1507 {
   1508   unsigned reg;
   1509   ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
   1510   reg = read_vector_priority_register(me, opic,
   1511 				      &opic->interprocessor_interrupt_source[index],
   1512 				      "ipi", index);
   1513   return reg;
   1514 }
   1515 
   1516 static void
   1517 do_ipi_N_vector_priority_register_write(device *me,
   1518 					hw_opic_device *opic,
   1519 					int index,
   1520 					unsigned reg)
   1521 {
   1522   ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
   1523   reg &= ~isu_level_triggered_bit; /* force edge trigger */
   1524   reg |= isu_positive_polarity_bit; /* force rising (positive) edge */
   1525   reg |= isu_multicast_bit; /* force a multicast source */
   1526   write_vector_priority_register(me, opic,
   1527 				 &opic->interprocessor_interrupt_source[index],
   1528 				 reg, "ipi", index);
   1529 }
   1530 
   1531 static void
   1532 do_ipi_N_dispatch_register_write(device *me,
   1533 				 hw_opic_device *opic,
   1534 				 int index,
   1535 				 unsigned reg)
   1536 {
   1537   opic_interrupt_source *source = &opic->interprocessor_interrupt_source[index];
   1538   ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
   1539   DTRACE(opic, ("ipi %d interrupt dispatch register - write 0x%x\n", index, reg));
   1540   source->destination = reg;
   1541   handle_interrupt(me, opic, source, 1);
   1542 }
   1543 
   1544 
   1545 /* vendor and other global registers */
   1546 
   1547 static unsigned
   1548 do_vendor_identification_register_read(device *me,
   1549 				       hw_opic_device *opic)
   1550 {
   1551   unsigned reg;
   1552   reg = opic->vendor_identification;
   1553   DTRACE(opic, ("vendor identification register - read 0x%x\n", reg));
   1554   return reg;
   1555 }
   1556 
   1557 static unsigned
   1558 do_feature_reporting_register_N_read(device *me,
   1559 				     hw_opic_device *opic,
   1560 				     int index)
   1561 {
   1562   unsigned reg = 0;
   1563   ASSERT(index == 0);
   1564   switch (index) {
   1565   case 0:
   1566     reg |= (opic->nr_external_interrupts << 16);
   1567     reg |= (opic->nr_interrupt_destinations << 8);
   1568     reg |= (2/*version 1.2*/);
   1569     break;
   1570   }
   1571   DTRACE(opic, ("feature reporting register %d - read 0x%x\n", index, reg));
   1572   return reg;
   1573 }
   1574 
   1575 static unsigned
   1576 do_global_configuration_register_N_read(device *me,
   1577 					hw_opic_device *opic,
   1578 					int index)
   1579 {
   1580   unsigned reg = 0;
   1581   ASSERT(index == 0);
   1582   switch (index) {
   1583   case 0:
   1584     reg |= gcr0_8259_bit; /* hardwire 8259 disabled */
   1585     break;
   1586   }
   1587   DTRACE(opic, ("global configuration register %d - read 0x%x\n", index, reg));
   1588   return reg;
   1589 }
   1590 
   1591 static void
   1592 do_global_configuration_register_N_write(device *me,
   1593 					 hw_opic_device *opic,
   1594 					 int index,
   1595 					 unsigned reg)
   1596 {
   1597   ASSERT(index == 0);
   1598   if (reg & gcr0_reset_bit) {
   1599     DTRACE(opic, ("global configuration register %d - write 0x%x - reseting opic\n", index, reg));
   1600     hw_opic_init_data(me);
   1601   }
   1602   if (!(reg & gcr0_8259_bit)) {
   1603     DTRACE(opic, ("global configuration register %d - write 0x%x - ignoring 8259 enable\n", index, reg));
   1604   }
   1605 }
   1606 
   1607 
   1608 
   1609 /* register read-write */
   1610 
   1611 static unsigned
   1612 hw_opic_io_read_buffer(device *me,
   1613 		       void *dest,
   1614 		       int space,
   1615 		       unsigned_word addr,
   1616 		       unsigned nr_bytes,
   1617 		       cpu *processor,
   1618 		       unsigned_word cia)
   1619 {
   1620   hw_opic_device *opic = (hw_opic_device*)device_data(me);
   1621   opic_register type;
   1622   int index;
   1623   decode_opic_address(me, opic, space, addr, nr_bytes, &type, &index);
   1624   if (type == invalid_opic_register) {
   1625     device_error(me, "invalid opic read access to %d:0x%lx (%d bytes)",
   1626 		 space, (unsigned long)addr, nr_bytes);
   1627   }
   1628   else {
   1629     unsigned reg;
   1630     switch (type) {
   1631     case processor_init_register:
   1632       reg = do_processor_init_register_read(me, opic);
   1633       break;
   1634     case interrupt_source_N_vector_priority_register:
   1635       reg = do_interrupt_source_N_vector_priority_register_read(me, opic, index);
   1636       break;
   1637     case interrupt_source_N_destination_register:
   1638       reg = do_interrupt_source_N_destination_register_read(me, opic, index);
   1639       break;
   1640     case interrupt_acknowledge_register_N:
   1641       reg = do_interrupt_acknowledge_register_N_read(me, opic, index);
   1642       break;
   1643     case spurious_vector_register:
   1644       reg = do_spurious_vector_register_read(me, opic);
   1645       break;
   1646     case current_task_priority_register_N:
   1647       reg = do_current_task_priority_register_N_read(me, opic, index);
   1648       break;
   1649     case timer_frequency_reporting_register:
   1650       reg = do_timer_frequency_reporting_register_read(me, opic);
   1651       break;
   1652     case timer_N_current_count_register:
   1653       reg = do_timer_N_current_count_register_read(me, opic, index);
   1654       break;
   1655     case timer_N_base_count_register:
   1656       reg = do_timer_N_base_count_register_read(me, opic, index);
   1657       break;
   1658     case timer_N_vector_priority_register:
   1659       reg = do_timer_N_vector_priority_register_read(me, opic, index);
   1660       break;
   1661     case timer_N_destination_register:
   1662       reg = do_timer_N_destination_register_read(me, opic, index);
   1663       break;
   1664     case ipi_N_vector_priority_register:
   1665       reg = do_ipi_N_vector_priority_register_read(me, opic, index);
   1666       break;
   1667     case feature_reporting_register_N:
   1668       reg = do_feature_reporting_register_N_read(me, opic, index);
   1669       break;
   1670     case global_configuration_register_N:
   1671       reg = do_global_configuration_register_N_read(me, opic, index);
   1672       break;
   1673     case vendor_identification_register:
   1674       reg = do_vendor_identification_register_read(me, opic);
   1675       break;
   1676     default:
   1677       reg = 0;
   1678       device_error(me, "unimplemented read of register %s[%d]",
   1679 		   opic_register_name(type), index);
   1680     }
   1681     *(unsigned_4*)dest = H2LE_4(reg);
   1682   }
   1683   return nr_bytes;
   1684 }
   1685 
   1686 
   1687 static unsigned
   1688 hw_opic_io_write_buffer(device *me,
   1689 			const void *source,
   1690 			int space,
   1691 			unsigned_word addr,
   1692 			unsigned nr_bytes,
   1693 			cpu *processor,
   1694 			unsigned_word cia)
   1695 {
   1696   hw_opic_device *opic = (hw_opic_device*)device_data(me);
   1697   opic_register type;
   1698   int index;
   1699   decode_opic_address(me, opic, space, addr, nr_bytes, &type, &index);
   1700   if (type == invalid_opic_register) {
   1701     device_error(me, "invalid opic write access to %d:0x%lx (%d bytes)",
   1702 		 space, (unsigned long)addr, nr_bytes);
   1703   }
   1704   else {
   1705     unsigned reg = LE2H_4(*(unsigned_4*)source);
   1706     switch (type) {
   1707     case processor_init_register:
   1708       do_processor_init_register_write(me, opic, reg);
   1709       break;
   1710     case interrupt_source_N_vector_priority_register:
   1711       do_interrupt_source_N_vector_priority_register_write(me, opic, index, reg);
   1712       break;
   1713     case interrupt_source_N_destination_register:
   1714       do_interrupt_source_N_destination_register_write(me, opic, index, reg);
   1715       break;
   1716     case end_of_interrupt_register_N:
   1717       do_end_of_interrupt_register_N_write(me, opic, index, reg);
   1718       break;
   1719     case spurious_vector_register:
   1720       do_spurious_vector_register_write(me, opic, reg);
   1721       break;
   1722     case current_task_priority_register_N:
   1723       do_current_task_priority_register_N_write(me, opic, index, reg);
   1724       break;
   1725     case timer_frequency_reporting_register:
   1726       do_timer_frequency_reporting_register_write(me, opic, reg);
   1727       break;
   1728     case timer_N_base_count_register:
   1729       do_timer_N_base_count_register_write(me, opic, index, reg);
   1730       break;
   1731     case timer_N_vector_priority_register:
   1732       do_timer_N_vector_priority_register_write(me, opic, index, reg);
   1733       break;
   1734     case timer_N_destination_register:
   1735       do_timer_N_destination_register_write(me, opic, index, reg);
   1736       break;
   1737     case ipi_N_dispatch_register:
   1738       do_ipi_N_dispatch_register_write(me, opic, index, reg);
   1739       break;
   1740     case ipi_N_vector_priority_register:
   1741       do_ipi_N_vector_priority_register_write(me, opic, index, reg);
   1742       break;
   1743     case global_configuration_register_N:
   1744       do_global_configuration_register_N_write(me, opic, index, reg);
   1745       break;
   1746     default:
   1747       device_error(me, "unimplemented write to register %s[%d]",
   1748 		   opic_register_name(type), index);
   1749     }
   1750   }
   1751   return nr_bytes;
   1752 }
   1753 
   1754 
   1755 static void
   1756 hw_opic_interrupt_event(device *me,
   1757 			int my_port,
   1758 			device *source,
   1759 			int source_port,
   1760 			int level,
   1761 			cpu *processor,
   1762 			unsigned_word cia)
   1763 {
   1764   hw_opic_device *opic = (hw_opic_device*)device_data(me);
   1765 
   1766   int isb;
   1767   int src_nr = 0;
   1768 
   1769   /* find the corresponding internal input port */
   1770   for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
   1771     if (my_port >= opic->isu_block[isb].int_number
   1772 	&& my_port < opic->isu_block[isb].int_number + opic->isu_block[isb].range) {
   1773       src_nr += my_port - opic->isu_block[isb].int_number;
   1774       break;
   1775     }
   1776     else
   1777       src_nr += opic->isu_block[isb].range;
   1778   }
   1779   if (isb == opic->nr_isu_blocks)
   1780     device_error(me, "interrupt %d out of range", my_port);
   1781   DTRACE(opic, ("external-interrupt %d, internal %d, level %d\n",
   1782 		my_port, src_nr, level));
   1783 
   1784   /* pass it on */
   1785   ASSERT(src_nr >= 0 && src_nr < opic->nr_external_interrupts);
   1786   handle_interrupt(me, opic, &opic->external_interrupt_source[src_nr], level);
   1787 }
   1788 
   1789 
   1790 static const device_interrupt_port_descriptor hw_opic_interrupt_ports[] = {
   1791   { "irq", 0, max_nr_interrupt_sources, input_port, },
   1792   { "intr", 0, max_nr_interrupt_destinations, output_port, },
   1793   { "init", max_nr_interrupt_destinations, max_nr_interrupt_destinations, output_port, },
   1794   { NULL }
   1795 };
   1796 
   1797 
   1798 static device_callbacks const hw_opic_callbacks = {
   1799   { generic_device_init_address,
   1800     hw_opic_init_data },
   1801   { NULL, }, /* address */
   1802   { hw_opic_io_read_buffer,
   1803     hw_opic_io_write_buffer }, /* IO */
   1804   { NULL, }, /* DMA */
   1805   { hw_opic_interrupt_event, NULL, hw_opic_interrupt_ports }, /* interrupt */
   1806   { NULL, }, /* unit */
   1807   NULL, /* instance */
   1808 };
   1809 
   1810 static void *
   1811 hw_opic_create(const char *name,
   1812 	       const device_unit *unit_address,
   1813 	       const char *args)
   1814 {
   1815   hw_opic_device *opic = ZALLOC(hw_opic_device);
   1816   return opic;
   1817 }
   1818 
   1819 
   1820 
   1821 const device_descriptor hw_opic_device_descriptor[] = {
   1822   { "opic", hw_opic_create, &hw_opic_callbacks },
   1823   { NULL },
   1824 };
   1825 
   1826 #endif /* _HW_OPIC_C_ */
   1827