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