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