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