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