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