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