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