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