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