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