]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/hw_opic.c
sim: create a makefile fragment to pass common settings down
[thirdparty/binutils-gdb.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 #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 signed64 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 unsigned32 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 &opic->isu_block[isb].int_number)
421 || !device_find_integer_array_property(me, "interrupt-ranges",
422 reg_nr * 2 + 1,
423 &opic->isu_block[isb].range))
424 device_error(me, "missing or invalid interrupt-ranges property entry %d", reg_nr);
425 /* first reg entry specifies the address of both the IDU and the
426 first set of ISU registers, adjust things accordingly */
427 if (reg_nr == idu_reg) {
428 opic->idu.reg = opic->isu_block[isb].reg;
429 opic->idu.space = opic->isu_block[isb].space;
430 opic->idu.address = opic->isu_block[isb].address;
431 opic->idu.size = opic->isu_block[isb].size;
432 opic->isu_block[isb].address += idu_isu_base;
433 opic->isu_block[isb].size = opic->isu_block[isb].range * (16 + 16);
434 }
435 /* was this a valid reg entry? */
436 if (opic->isu_block[isb].range == 0) {
437 opic->nr_isu_blocks -= 1;
438 }
439 else {
440 opic->nr_external_interrupts += opic->isu_block[isb].range;
441 isb++;
442 }
443 reg_nr++;
444 }
445 }
446 DTRACE(opic, ("interrupt source unit block - effective number of blocks %d\n",
447 (int)opic->nr_isu_blocks));
448
449
450 /* the number of other interrupts */
451 opic->nr_interprocessor_interrupts = 4;
452 opic->nr_timer_interrupts = 4;
453
454
455 /* create space for the interrupt source registers */
456 if (opic->interrupt_source != NULL) {
457 memset(opic->interrupt_source, 0, opic->sizeof_interrupt_source);
458 }
459 else {
460 opic->nr_interrupt_sources = (opic->nr_external_interrupts
461 + opic->nr_interprocessor_interrupts
462 + opic->nr_timer_interrupts);
463 if (opic->nr_interrupt_sources > max_nr_interrupt_sources)
464 device_error(me, "number of interrupt sources exceeded");
465 opic->sizeof_interrupt_source = (sizeof(opic_interrupt_source)
466 * opic->nr_interrupt_sources);
467 opic->interrupt_source = zalloc(opic->sizeof_interrupt_source);
468 opic->external_interrupt_source = opic->interrupt_source;
469 opic->interprocessor_interrupt_source = (opic->external_interrupt_source
470 + opic->nr_external_interrupts);
471 opic->timer_interrupt_source = (opic->interprocessor_interrupt_source
472 + opic->nr_interprocessor_interrupts);
473 }
474 for (i = 0; i < opic->nr_interrupt_sources; i++) {
475 opic_interrupt_source *source = &opic->interrupt_source[i];
476 source->nr = i;
477 source->is_masked = isu_mask_bit;
478 }
479 DTRACE(opic, ("interrupt sources - external %d, timer %d, ipi %d, total %d\n",
480 opic->nr_external_interrupts,
481 opic->nr_timer_interrupts,
482 opic->nr_interprocessor_interrupts,
483 opic->nr_interrupt_sources));
484
485
486 /* timers or interprocessor interrupts */
487 if (opic->timer != NULL)
488 memset(opic->timer, 0, opic->sizeof_timer);
489 else {
490 opic->nr_timer_interrupts = 4;
491 opic->sizeof_timer = sizeof(opic_timer) * opic->nr_timer_interrupts;
492 opic->timer = zalloc(opic->sizeof_timer);
493 }
494 for (i = 0; i < opic->nr_timer_interrupts; i++) {
495 opic_timer *timer = &opic->timer[i];
496 timer->nr = i;
497 timer->me = me;
498 timer->opic = opic;
499 timer->inhibited = 1;
500 timer->interrupt_source = &opic->timer_interrupt_source[i];
501 }
502 if (device_find_property(me, "timer-frequency"))
503 opic->timer_frequency = device_find_integer_property(me, "timer-frequency");
504 else
505 opic->timer_frequency = 1;
506
507
508 /* create space for the interrupt destination registers */
509 if (opic->interrupt_destination != NULL) {
510 memset(opic->interrupt_destination, 0, opic->sizeof_interrupt_destination);
511 }
512 else {
513 opic->nr_interrupt_destinations = tree_find_integer_property(me, "/openprom/options/smp");
514 opic->sizeof_interrupt_destination = (sizeof(opic_interrupt_destination)
515 * opic->nr_interrupt_destinations);
516 opic->interrupt_destination = zalloc(opic->sizeof_interrupt_destination);
517 if (opic->nr_interrupt_destinations > max_nr_interrupt_destinations)
518 device_error(me, "number of interrupt destinations exceeded");
519 }
520 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
521 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
522 dest->bit = (1 << i);
523 dest->nr = i;
524 dest->init_port = (device_interrupt_decode(me, "init0", output_port)
525 + i);
526 dest->intr_port = (device_interrupt_decode(me, "intr0", output_port)
527 + i);
528 dest->base_priority = max_nr_task_priorities - 1;
529 }
530 DTRACE(opic, ("interrupt destinations - total %d\n",
531 (int)opic->nr_interrupt_destinations));
532
533
534 /* verify and print out the ISU's */
535 for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
536 unsigned correct_size;
537 if ((opic->isu_block[isb].address % opic_alignment) != 0)
538 device_error(me, "interrupt source unit %d address not aligned to %d byte boundary",
539 isb, opic_alignment);
540 correct_size = opic->isu_block[isb].range * sizeof_isu_register_block;
541 if (opic->isu_block[isb].size != correct_size)
542 device_error(me, "interrupt source unit %d (reg %d) has an incorrect size, should be 0x%x",
543 isb, opic->isu_block[isb].reg, correct_size);
544 DTRACE(opic, ("interrupt source unit block %ld - address %d:0x%lx, size 0x%lx, int-number %ld, range %ld\n",
545 (long)isb,
546 (int)opic->isu_block[isb].space,
547 (unsigned long)opic->isu_block[isb].address,
548 (unsigned long)opic->isu_block[isb].size,
549 (long)opic->isu_block[isb].int_number,
550 (long)opic->isu_block[isb].range));
551 }
552
553
554 /* verify and print out the IDU */
555 {
556 unsigned correct_size;
557 unsigned alternate_size;
558 if ((opic->idu.address % opic_alignment) != 0)
559 device_error(me, "interrupt delivery unit not aligned to %d byte boundary",
560 opic_alignment);
561 correct_size = (idu_per_processor_register_base
562 + (sizeof_idu_per_processor_register_block
563 * opic->nr_interrupt_destinations));
564 alternate_size = (idu_per_processor_register_base
565 + (sizeof_idu_per_processor_register_block
566 * max_nr_interrupt_destinations));
567 if (opic->idu.size != correct_size
568 && opic->idu.size != alternate_size)
569 device_error(me, "interrupt delivery unit has incorrect size, should be 0x%x or 0x%x",
570 correct_size, alternate_size);
571 DTRACE(opic, ("interrupt delivery unit - address %d:0x%lx, size 0x%lx\n",
572 (int)opic->idu.space,
573 (unsigned long)opic->idu.address,
574 (unsigned long)opic->idu.size));
575 }
576
577 /* initialize the init interrupts */
578 opic->init = 0;
579
580
581 /* vendor ident */
582 if (device_find_property(me, "vendor-identification") != NULL)
583 opic->vendor_identification = device_find_integer_property(me, "vendor-identification");
584 else
585 opic->vendor_identification = 0;
586
587 /* misc registers */
588 opic->spurious_vector = 0xff;
589
590 }
591
592
593 /* interrupt related actions */
594
595 static void
596 assert_interrupt(device *me,
597 hw_opic_device *opic,
598 opic_interrupt_destination *dest)
599 {
600 ASSERT(dest >= opic->interrupt_destination);
601 ASSERT(dest < opic->interrupt_destination + opic->nr_interrupt_destinations);
602 DTRACE(opic, ("assert interrupt - intr port %d\n", dest->intr_port));
603 device_interrupt_event(me, dest->intr_port, 1, NULL, 0);
604 }
605
606
607 static void
608 negate_interrupt(device *me,
609 hw_opic_device *opic,
610 opic_interrupt_destination *dest)
611 {
612 ASSERT(dest >= opic->interrupt_destination);
613 ASSERT(dest < opic->interrupt_destination + opic->nr_interrupt_destinations);
614 DTRACE(opic, ("negate interrupt - intr port %d\n", dest->intr_port));
615 device_interrupt_event(me, dest->intr_port, 0, NULL, 0);
616 }
617
618
619 static int
620 can_deliver(device *me,
621 opic_interrupt_source *source,
622 opic_interrupt_destination *dest)
623 {
624 return (source != NULL && dest != NULL
625 && source->priority > dest->base_priority
626 && (dest->current_in_service == NULL
627 || source->priority > dest->current_in_service->priority));
628 }
629
630
631 static unsigned
632 deliver_pending(device *me,
633 hw_opic_device *opic,
634 opic_interrupt_destination *dest)
635 {
636 ASSERT(can_deliver(me, dest->current_pending, dest));
637 dest->current_in_service = dest->current_pending;
638 dest->current_in_service->in_service |= dest->bit;
639 if (!dest->current_pending->is_level_triggered) {
640 if (dest->current_pending->is_multicast)
641 dest->current_pending->pending &= ~dest->bit;
642 else
643 dest->current_pending->pending = 0;
644 }
645 dest->current_pending = NULL;
646 negate_interrupt(me, opic, dest);
647 return dest->current_in_service->vector;
648 }
649
650
651 typedef enum {
652 pending_interrupt,
653 in_service_interrupt,
654 } interrupt_class;
655
656 static opic_interrupt_source *
657 find_interrupt_for_dest(device *me,
658 hw_opic_device *opic,
659 opic_interrupt_destination *dest,
660 interrupt_class class)
661 {
662 int i;
663 opic_interrupt_source *pending = NULL;
664 for (i = 0; i < opic->nr_interrupt_sources; i++) {
665 opic_interrupt_source *src = &opic->interrupt_source[i];
666 /* is this a potential hit? */
667 switch (class) {
668 case in_service_interrupt:
669 if ((src->in_service & dest->bit) == 0)
670 continue;
671 break;
672 case pending_interrupt:
673 if ((src->pending & dest->bit) == 0)
674 continue;
675 break;
676 }
677 /* see if it is the highest priority */
678 if (pending == NULL)
679 pending = src;
680 else if (src->priority > pending->priority)
681 pending = src;
682 }
683 return pending;
684 }
685
686
687 static opic_interrupt_destination *
688 find_lowest_dest(device *me,
689 hw_opic_device *opic,
690 opic_interrupt_source *src)
691 {
692 int i;
693 opic_interrupt_destination *lowest = NULL;
694 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
695 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
696 if (src->destination & dest->bit) {
697 if (dest->base_priority < src->priority) {
698 if (lowest == NULL)
699 lowest = dest;
700 else if (lowest->base_priority > dest->base_priority)
701 lowest = dest;
702 else if (lowest->current_in_service != NULL
703 && dest->current_in_service == NULL)
704 lowest = dest; /* not doing anything */
705 else if (lowest->current_in_service != NULL
706 && dest->current_in_service != NULL
707 && (lowest->current_in_service->priority
708 > dest->current_in_service->priority))
709 lowest = dest; /* less urgent */
710 /* FIXME - need to be more fair */
711 }
712 }
713 }
714 return lowest;
715 }
716
717
718 static void
719 handle_interrupt(device *me,
720 hw_opic_device *opic,
721 opic_interrupt_source *src,
722 int asserted)
723 {
724 if (src->is_masked) {
725 DTRACE(opic, ("interrupt %d - ignore masked\n", src->nr));
726 }
727 else if (src->is_multicast) {
728 /* always try to deliver multicast interrupts - just easier */
729 int i;
730 ASSERT(!src->is_level_triggered);
731 ASSERT(src->is_positive_polarity);
732 ASSERT(asserted);
733 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
734 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
735 if (src->destination & dest->bit) {
736 if (src->pending & dest->bit) {
737 DTRACE(opic, ("interrupt %d - multicast still pending to %d\n",
738 src->nr, dest->nr));
739 }
740 else if (can_deliver(me, src, dest)) {
741 dest->current_pending = src;
742 src->pending |= dest->bit;
743 assert_interrupt(me, opic, dest);
744 DTRACE(opic, ("interrupt %d - multicast to %d\n",
745 src->nr, dest->nr));
746 }
747 else {
748 src->pending |= dest->bit;
749 DTRACE(opic, ("interrupt %d - multicast pending to %d\n",
750 src->nr, dest->nr));
751 }
752 }
753 }
754 }
755 else if (src->is_level_triggered
756 && src->is_positive_polarity
757 && !asserted) {
758 if (src->pending)
759 DTRACE(opic, ("interrupt %d - ignore withdrawn (active high)\n",
760 src->nr));
761 else
762 DTRACE(opic, ("interrupt %d - ignore low level (active high)\n",
763 src->nr));
764 ASSERT(!src->is_multicast);
765 src->pending = 0;
766 }
767 else if (src->is_level_triggered
768 && !src->is_positive_polarity
769 && asserted) {
770 if (src->pending)
771 DTRACE(opic, ("interrupt %d - ignore withdrawn (active low)\n",
772 src->nr));
773 else
774 DTRACE(opic, ("interrupt %d - ignore high level (active low)\n",
775 src->nr));
776
777 ASSERT(!src->is_multicast);
778 src->pending = 0;
779 }
780 else if (!src->is_level_triggered
781 && src->is_positive_polarity
782 && !asserted) {
783 DTRACE(opic, ("interrupt %d - ignore falling edge (positive edge trigered)\n",
784 src->nr));
785 }
786 else if (!src->is_level_triggered
787 && !src->is_positive_polarity
788 && asserted) {
789 DTRACE(opic, ("interrupt %d - ignore rising edge (negative edge trigered)\n",
790 src->nr));
791 }
792 else if (src->in_service != 0) {
793 /* leave the interrupt where it is */
794 ASSERT(!src->is_multicast);
795 ASSERT(src->pending == 0 || src->pending == src->in_service);
796 src->pending = src->in_service;
797 DTRACE(opic, ("interrupt %ld - ignore already in service to 0x%lx\n",
798 (long)src->nr, (long)src->in_service));
799 }
800 else if (src->pending != 0) {
801 DTRACE(opic, ("interrupt %ld - ignore still pending to 0x%lx\n",
802 (long)src->nr, (long)src->pending));
803 }
804 else {
805 /* delivery is needed */
806 opic_interrupt_destination *dest = find_lowest_dest(me, opic, src);
807 if (can_deliver(me, src, dest)) {
808 dest->current_pending = src;
809 src->pending = dest->bit;
810 DTRACE(opic, ("interrupt %d - delivered to %d\n", src->nr, dest->nr));
811 assert_interrupt(me, opic, dest);
812 }
813 else {
814 src->pending = src->destination; /* any can take this */
815 DTRACE(opic, ("interrupt %ld - pending to 0x%lx\n",
816 (long)src->nr, (long)src->pending));
817 }
818 }
819 }
820
821 static unsigned
822 do_interrupt_acknowledge_register_N_read(device *me,
823 hw_opic_device *opic,
824 int dest_nr)
825 {
826 opic_interrupt_destination *dest = &opic->interrupt_destination[dest_nr];
827 unsigned vector;
828
829 ASSERT(dest_nr >= 0 && dest_nr < opic->nr_interrupt_destinations);
830 ASSERT(dest_nr == dest->nr);
831
832 /* try the current pending */
833 if (can_deliver(me, dest->current_pending, dest)) {
834 ASSERT(dest->current_pending->pending & dest->bit);
835 vector = deliver_pending(me, opic, dest);
836 DTRACE(opic, ("interrupt ack %d - entering %d (pending) - vector %d (%d), priority %d\n",
837 dest->nr,
838 dest->current_in_service->nr,
839 dest->current_in_service->vector, vector,
840 dest->current_in_service->priority));
841 }
842 else {
843 /* try for something else */
844 dest->current_pending = find_interrupt_for_dest(me, opic, dest, pending_interrupt);
845 if (can_deliver(me, dest->current_pending, dest)) {
846 vector = deliver_pending(me, opic, dest);
847 DTRACE(opic, ("interrupt ack %d - entering %d (not pending) - vector %d (%d), priority %d\n",
848 dest->nr,
849 dest->current_in_service->nr,
850 dest->current_in_service->vector, vector,
851 dest->current_in_service->priority));
852 }
853 else {
854 dest->current_pending = NULL;
855 vector = opic->spurious_vector;
856 DTRACE(opic, ("interrupt ack %d - spurious interrupt %d\n",
857 dest->nr, vector));
858 }
859 }
860 return vector;
861 }
862
863
864 static void
865 do_end_of_interrupt_register_N_write(device *me,
866 hw_opic_device *opic,
867 int dest_nr,
868 unsigned reg)
869 {
870 opic_interrupt_destination *dest = &opic->interrupt_destination[dest_nr];
871
872 ASSERT(dest_nr >= 0 && dest_nr < opic->nr_interrupt_destinations);
873 ASSERT(dest_nr == dest->nr);
874
875 /* check the value written is zero */
876 if (reg != 0) {
877 DTRACE(opic, ("eoi %d - ignoring nonzero value\n", dest->nr));
878 }
879
880 /* user doing wierd things? */
881 if (dest->current_in_service == NULL) {
882 DTRACE(opic, ("eoi %d - strange, no current interrupt\n", dest->nr));
883 return;
884 }
885
886 /* an internal stuff up? */
887 if (!(dest->current_in_service->in_service & dest->bit)) {
888 device_error(me, "eoi %d - current interrupt not in service", dest->nr);
889 }
890
891 /* find what was probably the previous in service interrupt */
892 dest->current_in_service->in_service &= ~dest->bit;
893 DTRACE(opic, ("eoi %d - ending %d - priority %d, vector %d\n",
894 dest->nr,
895 dest->current_in_service->nr,
896 dest->current_in_service->priority,
897 dest->current_in_service->vector));
898 dest->current_in_service = find_interrupt_for_dest(me, opic, dest, in_service_interrupt);
899 if (dest->current_in_service != NULL)
900 DTRACE(opic, ("eoi %d - resuming %d - priority %d, vector %d\n",
901 dest->nr,
902 dest->current_in_service->nr,
903 dest->current_in_service->priority,
904 dest->current_in_service->vector));
905 else
906 DTRACE(opic, ("eoi %d - resuming none\n", dest->nr));
907
908 /* check to see if that shouldn't be interrupted */
909 dest->current_pending = find_interrupt_for_dest(me, opic, dest, pending_interrupt);
910 if (can_deliver(me, dest->current_pending, dest)) {
911 ASSERT(dest->current_pending->pending & dest->bit);
912 assert_interrupt(me, opic, dest);
913 }
914 else {
915 dest->current_pending = NULL;
916 }
917 }
918
919
920 static void
921 decode_opic_address(device *me,
922 hw_opic_device *opic,
923 int space,
924 unsigned_word address,
925 unsigned nr_bytes,
926 opic_register *type,
927 int *index)
928 {
929 int isb = 0;
930
931 /* is the size valid? */
932 if (nr_bytes != 4) {
933 *type = invalid_opic_register;
934 *index = -1;
935 return;
936 }
937
938 /* try for a per-processor register within the interrupt delivery
939 unit */
940 if (space == opic->idu.space
941 && address >= (opic->idu.address + idu_per_processor_register_base)
942 && address < (opic->idu.address + idu_per_processor_register_base
943 + (sizeof_idu_per_processor_register_block
944 * opic->nr_interrupt_destinations))) {
945 unsigned_word block_offset = (address
946 - opic->idu.address
947 - idu_per_processor_register_base);
948 unsigned_word offset = block_offset % sizeof_idu_per_processor_register_block;
949 *index = block_offset / sizeof_idu_per_processor_register_block;
950 switch (offset) {
951 case 0x040:
952 *type = ipi_N_dispatch_register;
953 *index = 0;
954 break;
955 case 0x050:
956 *type = ipi_N_dispatch_register;
957 *index = 1;
958 break;
959 case 0x060:
960 *type = ipi_N_dispatch_register;
961 *index = 2;
962 break;
963 case 0x070:
964 *type = ipi_N_dispatch_register;
965 *index = 3;
966 break;
967 case 0x080:
968 *type = current_task_priority_register_N;
969 break;
970 case 0x0a0:
971 *type = interrupt_acknowledge_register_N;
972 break;
973 case 0x0b0:
974 *type = end_of_interrupt_register_N;
975 break;
976 default:
977 *type = invalid_opic_register;
978 break;
979 }
980 DTRACE(opic, ("per-processor register %d:0x%lx - %s[%d]\n",
981 space, (unsigned long)address,
982 opic_register_name(*type),
983 *index));
984 return;
985 }
986
987 /* try for an interrupt source unit */
988 for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
989 if (opic->isu_block[isb].space == space
990 && address >= opic->isu_block[isb].address
991 && address < (opic->isu_block[isb].address + opic->isu_block[isb].size)) {
992 unsigned_word block_offset = address - opic->isu_block[isb].address;
993 unsigned_word offset = block_offset % sizeof_isu_register_block;
994 *index = (opic->isu_block[isb].int_number
995 + (block_offset / sizeof_isu_register_block));
996 switch (offset) {
997 case 0x00:
998 *type = interrupt_source_N_vector_priority_register;
999 break;
1000 case 0x10:
1001 *type = interrupt_source_N_destination_register;
1002 break;
1003 default:
1004 *type = invalid_opic_register;
1005 break;
1006 }
1007 DTRACE(opic, ("isu register %d:0x%lx - %s[%d]\n",
1008 space, (unsigned long)address,
1009 opic_register_name(*type),
1010 *index));
1011 return;
1012 }
1013 }
1014
1015 /* try for a timer */
1016 if (space == opic->idu.space
1017 && address >= (opic->idu.address + idu_timer_base)
1018 && address < (opic->idu.address + idu_timer_base
1019 + opic->nr_timer_interrupts * sizeof_timer_register_block)) {
1020 unsigned_word offset = address % sizeof_timer_register_block;
1021 *index = ((address - opic->idu.address - idu_timer_base)
1022 / sizeof_timer_register_block);
1023 switch (offset) {
1024 case 0x00:
1025 *type = timer_N_current_count_register;
1026 break;
1027 case 0x10:
1028 *type = timer_N_base_count_register;
1029 break;
1030 case 0x20:
1031 *type = timer_N_vector_priority_register;
1032 break;
1033 case 0x30:
1034 *type = timer_N_destination_register;
1035 break;
1036 default:
1037 *type = invalid_opic_register;
1038 break;
1039 }
1040 DTRACE(opic, ("timer register %d:0x%lx - %s[%d]\n",
1041 space, (unsigned long)address,
1042 opic_register_name(*type),
1043 *index));
1044 return;
1045 }
1046
1047 /* finally some other misc global register */
1048 if (space == opic->idu.space
1049 && address >= opic->idu.address
1050 && address < opic->idu.address + opic->idu.size) {
1051 unsigned_word block_offset = address - opic->idu.address;
1052 switch (block_offset) {
1053 case 0x010f0:
1054 *type = timer_frequency_reporting_register;
1055 *index = -1;
1056 break;
1057 case 0x010e0:
1058 *type = spurious_vector_register;
1059 *index = -1;
1060 break;
1061 case 0x010d0:
1062 case 0x010c0:
1063 case 0x010b0:
1064 case 0x010a0:
1065 *type = ipi_N_vector_priority_register;
1066 *index = (block_offset - 0x010a0) / 16;
1067 break;
1068 case 0x01090:
1069 *type = processor_init_register;
1070 *index = -1;
1071 break;
1072 case 0x01080:
1073 *type = vendor_identification_register;
1074 *index = -1;
1075 break;
1076 case 0x01020:
1077 *type = global_configuration_register_N;
1078 *index = 0;
1079 break;
1080 case 0x01000:
1081 *type = feature_reporting_register_N;
1082 *index = 0;
1083 break;
1084 default:
1085 *type = invalid_opic_register;
1086 *index = -1;
1087 break;
1088 }
1089 DTRACE(opic, ("global register %d:0x%lx - %s[%d]\n",
1090 space, (unsigned long)address,
1091 opic_register_name(*type),
1092 *index));
1093 return;
1094 }
1095
1096 /* nothing matched */
1097 *type = invalid_opic_register;
1098 DTRACE(opic, ("invalid register %d:0x%lx\n",
1099 space, (unsigned long)address));
1100 return;
1101 }
1102
1103
1104 /* Processor init register:
1105
1106 The bits in this register (one per processor) are directly wired to
1107 output "init" interrupt ports. */
1108
1109 static unsigned
1110 do_processor_init_register_read(device *me,
1111 hw_opic_device *opic)
1112 {
1113 unsigned reg = opic->init;
1114 DTRACE(opic, ("processor init register - read 0x%lx\n",
1115 (long)reg));
1116 return reg;
1117 }
1118
1119 static void
1120 do_processor_init_register_write(device *me,
1121 hw_opic_device *opic,
1122 unsigned reg)
1123 {
1124 int i;
1125 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
1126 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
1127 if ((reg & dest->bit) != (opic->init & dest->bit)) {
1128 if (reg & dest->bit) {
1129 DTRACE(opic, ("processor init register - write 0x%lx - asserting init%d\n",
1130 (long)reg, i));
1131 opic->init |= dest->bit;
1132 device_interrupt_event(me, dest->init_port, 1, NULL, 0);
1133 }
1134 else {
1135 DTRACE(opic, ("processor init register - write 0x%lx - negating init%d\n",
1136 (long)reg, i));
1137 opic->init &= ~dest->bit;
1138 device_interrupt_event(me, dest->init_port, 0, NULL, 0);
1139 }
1140 }
1141 }
1142 }
1143
1144
1145
1146 /* Interrupt Source Vector/Priority Register: */
1147
1148 static unsigned
1149 read_vector_priority_register(device *me,
1150 hw_opic_device *opic,
1151 opic_interrupt_source *interrupt,
1152 const char *reg_name,
1153 int reg_index)
1154 {
1155 unsigned reg;
1156 reg = 0;
1157 reg |= interrupt->is_masked;
1158 reg |= (interrupt->in_service || interrupt->pending
1159 ? isu_active_bit : 0); /* active */
1160 reg |= interrupt->is_multicast;
1161 reg |= interrupt->is_positive_polarity;
1162 reg |= interrupt->is_level_triggered; /* sense? */
1163 reg |= interrupt->priority << isu_priority_shift;
1164 reg |= interrupt->vector;
1165 DTRACE(opic, ("%s %d vector/priority register - read 0x%lx\n",
1166 reg_name, reg_index, (unsigned long)reg));
1167 return reg;
1168 }
1169
1170 static unsigned
1171 do_interrupt_source_N_vector_priority_register_read(device *me,
1172 hw_opic_device *opic,
1173 int index)
1174 {
1175 unsigned reg;
1176 ASSERT(index < opic->nr_external_interrupts);
1177 reg = read_vector_priority_register(me, opic,
1178 &opic->interrupt_source[index],
1179 "interrupt source", index);
1180 return reg;
1181 }
1182
1183 static void
1184 write_vector_priority_register(device *me,
1185 hw_opic_device *opic,
1186 opic_interrupt_source *interrupt,
1187 unsigned reg,
1188 const char *reg_name,
1189 int reg_index)
1190 {
1191 interrupt->is_masked = (reg & isu_mask_bit);
1192 interrupt->is_multicast = (reg & isu_multicast_bit);
1193 interrupt->is_positive_polarity = (reg & isu_positive_polarity_bit);
1194 interrupt->is_level_triggered = (reg & isu_level_triggered_bit);
1195 interrupt->priority = ((reg >> isu_priority_shift)
1196 % max_nr_task_priorities);
1197 interrupt->vector = (reg & isu_vector_bits);
1198 DTRACE(opic, ("%s %d vector/priority register - write 0x%lx - %s%s%s-polarity, %s-triggered, priority %ld vector %ld\n",
1199 reg_name,
1200 reg_index,
1201 (unsigned long)reg,
1202 interrupt->is_masked ? "masked, " : "",
1203 interrupt->is_multicast ? "multicast, " : "",
1204 interrupt->is_positive_polarity ? "positive" : "negative",
1205 interrupt->is_level_triggered ? "level" : "edge",
1206 (long)interrupt->priority,
1207 (long)interrupt->vector));
1208 }
1209
1210 static void
1211 do_interrupt_source_N_vector_priority_register_write(device *me,
1212 hw_opic_device *opic,
1213 int index,
1214 unsigned reg)
1215 {
1216 ASSERT(index < opic->nr_external_interrupts);
1217 reg &= ~isu_multicast_bit; /* disable multicast */
1218 write_vector_priority_register(me, opic,
1219 &opic->interrupt_source[index],
1220 reg, "interrupt source", index);
1221 }
1222
1223
1224
1225 /* Interrupt Source Destination Register: */
1226
1227 static unsigned
1228 read_destination_register(device *me,
1229 hw_opic_device *opic,
1230 opic_interrupt_source *interrupt,
1231 const char *reg_name,
1232 int reg_index)
1233 {
1234 unsigned long reg;
1235 reg = interrupt->destination;
1236 DTRACE(opic, ("%s %d destination register - read 0x%lx\n",
1237 reg_name, reg_index, reg));
1238 return reg;
1239 }
1240
1241 static unsigned
1242 do_interrupt_source_N_destination_register_read(device *me,
1243 hw_opic_device *opic,
1244 int index)
1245 {
1246 unsigned reg;
1247 ASSERT(index < opic->nr_external_interrupts);
1248 reg = read_destination_register(me, opic, &opic->external_interrupt_source[index],
1249 "interrupt source", index);
1250 return reg;
1251 }
1252
1253 static void
1254 write_destination_register(device *me,
1255 hw_opic_device *opic,
1256 opic_interrupt_source *interrupt,
1257 unsigned reg,
1258 const char *reg_name,
1259 int reg_index)
1260 {
1261 reg &= (1 << opic->nr_interrupt_destinations) - 1; /* mask out invalid */
1262 DTRACE(opic, ("%s %d destination register - write 0x%x\n",
1263 reg_name, reg_index, reg));
1264 interrupt->destination = reg;
1265 }
1266
1267 static void
1268 do_interrupt_source_N_destination_register_write(device *me,
1269 hw_opic_device *opic,
1270 int index,
1271 unsigned reg)
1272 {
1273 ASSERT(index < opic->nr_external_interrupts);
1274 write_destination_register(me, opic, &opic->external_interrupt_source[index],
1275 reg, "interrupt source", index);
1276 }
1277
1278
1279
1280 /* Spurious vector register: */
1281
1282 static unsigned
1283 do_spurious_vector_register_read(device *me,
1284 hw_opic_device *opic)
1285 {
1286 unsigned long reg = opic->spurious_vector;
1287 DTRACE(opic, ("spurious vector register - read 0x%lx\n", reg));
1288 return reg;
1289 }
1290
1291 static void
1292 do_spurious_vector_register_write(device *me,
1293 hw_opic_device *opic,
1294 unsigned reg)
1295 {
1296 reg &= 0xff; /* mask off invalid */
1297 DTRACE(opic, ("spurious vector register - write 0x%x\n", reg));
1298 opic->spurious_vector = reg;
1299 }
1300
1301
1302
1303 /* current task priority register: */
1304
1305 static unsigned
1306 do_current_task_priority_register_N_read(device *me,
1307 hw_opic_device *opic,
1308 int index)
1309 {
1310 opic_interrupt_destination *interrupt_destination = &opic->interrupt_destination[index];
1311 unsigned reg;
1312 ASSERT(index >= 0 && index < opic->nr_interrupt_destinations);
1313 reg = interrupt_destination->base_priority;
1314 DTRACE(opic, ("current task priority register %d - read 0x%x\n", index, reg));
1315 return reg;
1316 }
1317
1318 static void
1319 do_current_task_priority_register_N_write(device *me,
1320 hw_opic_device *opic,
1321 int index,
1322 unsigned reg)
1323 {
1324 opic_interrupt_destination *interrupt_destination = &opic->interrupt_destination[index];
1325 ASSERT(index >= 0 && index < opic->nr_interrupt_destinations);
1326 reg %= max_nr_task_priorities;
1327 DTRACE(opic, ("current task priority register %d - write 0x%x\n", index, reg));
1328 interrupt_destination->base_priority = reg;
1329 }
1330
1331
1332
1333 /* Timer Frequency Reporting Register: */
1334
1335 static unsigned
1336 do_timer_frequency_reporting_register_read(device *me,
1337 hw_opic_device *opic)
1338 {
1339 unsigned reg;
1340 reg = opic->timer_frequency;
1341 DTRACE(opic, ("timer frequency reporting register - read 0x%x\n", reg));
1342 return reg;
1343 }
1344
1345 static void
1346 do_timer_frequency_reporting_register_write(device *me,
1347 hw_opic_device *opic,
1348 unsigned reg)
1349 {
1350 DTRACE(opic, ("timer frequency reporting register - write 0x%x\n", reg));
1351 opic->timer_frequency = reg;
1352 }
1353
1354
1355 /* timer registers: */
1356
1357 static unsigned
1358 do_timer_N_current_count_register_read(device *me,
1359 hw_opic_device *opic,
1360 int index)
1361 {
1362 opic_timer *timer = &opic->timer[index];
1363 unsigned reg;
1364 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1365 if (timer->inhibited)
1366 reg = timer->count; /* stalled value */
1367 else
1368 reg = timer->count - device_event_queue_time(me); /* time remaining */
1369 DTRACE(opic, ("timer %d current count register - read 0x%x\n", index, reg));
1370 return reg;
1371 }
1372
1373
1374 static unsigned
1375 do_timer_N_base_count_register_read(device *me,
1376 hw_opic_device *opic,
1377 int index)
1378 {
1379 opic_timer *timer = &opic->timer[index];
1380 unsigned reg;
1381 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1382 reg = timer->base_count;
1383 DTRACE(opic, ("timer %d base count register - read 0x%x\n", index, reg));
1384 return reg;
1385 }
1386
1387
1388 static void
1389 timer_event(void *data)
1390 {
1391 opic_timer *timer = data;
1392 device *me = timer->me;
1393 if (timer->inhibited)
1394 device_error(timer->me, "internal-error - timer event occured when timer %d inhibited",
1395 timer->nr);
1396 handle_interrupt(timer->me, timer->opic, timer->interrupt_source, 1);
1397 timer->timeout_event = device_event_queue_schedule(me, timer->base_count,
1398 timer_event, timer);
1399 DTRACE(opic, ("timer %d - interrupt at %ld, next at %d\n",
1400 timer->nr, (long)device_event_queue_time(me), timer->base_count));
1401 }
1402
1403
1404 static void
1405 do_timer_N_base_count_register_write(device *me,
1406 hw_opic_device *opic,
1407 int index,
1408 unsigned reg)
1409 {
1410 opic_timer *timer = &opic->timer[index];
1411 int inhibit;
1412 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1413 inhibit = reg & 0x80000000;
1414 if (timer->inhibited && !inhibit) {
1415 timer->inhibited = 0;
1416 if (timer->timeout_event != NULL)
1417 device_event_queue_deschedule(me, timer->timeout_event);
1418 timer->count = device_event_queue_time(me) + reg;
1419 timer->base_count = reg;
1420 timer->timeout_event = device_event_queue_schedule(me, timer->base_count,
1421 timer_event, (void*)timer);
1422 DTRACE(opic, ("timer %d base count register - write 0x%x - timer started\n",
1423 index, reg));
1424 }
1425 else if (!timer->inhibited && inhibit) {
1426 if (timer->timeout_event != NULL)
1427 device_event_queue_deschedule(me, timer->timeout_event);
1428 timer->count = timer->count - device_event_queue_time(me);
1429 timer->inhibited = 1;
1430 timer->base_count = reg;
1431 DTRACE(opic, ("timer %d base count register - write 0x%x - timer stopped\n",
1432 index, reg));
1433 }
1434 else {
1435 ASSERT((timer->inhibited && inhibit) || (!timer->inhibited && !inhibit));
1436 DTRACE(opic, ("timer %d base count register - write 0x%x\n", index, reg));
1437 timer->base_count = reg;
1438 }
1439 }
1440
1441
1442 static unsigned
1443 do_timer_N_vector_priority_register_read(device *me,
1444 hw_opic_device *opic,
1445 int index)
1446 {
1447 unsigned reg;
1448 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1449 reg = read_vector_priority_register(me, opic,
1450 &opic->timer_interrupt_source[index],
1451 "timer", index);
1452 return reg;
1453 }
1454
1455 static void
1456 do_timer_N_vector_priority_register_write(device *me,
1457 hw_opic_device *opic,
1458 int index,
1459 unsigned reg)
1460 {
1461 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1462 reg &= ~isu_level_triggered_bit; /* force edge trigger */
1463 reg |= isu_positive_polarity_bit; /* force rising (positive) edge */
1464 reg |= isu_multicast_bit; /* force multicast */
1465 write_vector_priority_register(me, opic,
1466 &opic->timer_interrupt_source[index],
1467 reg, "timer", index);
1468 }
1469
1470
1471 static unsigned
1472 do_timer_N_destination_register_read(device *me,
1473 hw_opic_device *opic,
1474 int index)
1475 {
1476 unsigned reg;
1477 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1478 reg = read_destination_register(me, opic, &opic->timer_interrupt_source[index],
1479 "timer", index);
1480 return reg;
1481 }
1482
1483 static void
1484 do_timer_N_destination_register_write(device *me,
1485 hw_opic_device *opic,
1486 int index,
1487 unsigned reg)
1488 {
1489 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1490 write_destination_register(me, opic, &opic->timer_interrupt_source[index],
1491 reg, "timer", index);
1492 }
1493
1494
1495 /* IPI registers */
1496
1497 static unsigned
1498 do_ipi_N_vector_priority_register_read(device *me,
1499 hw_opic_device *opic,
1500 int index)
1501 {
1502 unsigned reg;
1503 ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
1504 reg = read_vector_priority_register(me, opic,
1505 &opic->interprocessor_interrupt_source[index],
1506 "ipi", index);
1507 return reg;
1508 }
1509
1510 static void
1511 do_ipi_N_vector_priority_register_write(device *me,
1512 hw_opic_device *opic,
1513 int index,
1514 unsigned reg)
1515 {
1516 ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
1517 reg &= ~isu_level_triggered_bit; /* force edge trigger */
1518 reg |= isu_positive_polarity_bit; /* force rising (positive) edge */
1519 reg |= isu_multicast_bit; /* force a multicast source */
1520 write_vector_priority_register(me, opic,
1521 &opic->interprocessor_interrupt_source[index],
1522 reg, "ipi", index);
1523 }
1524
1525 static void
1526 do_ipi_N_dispatch_register_write(device *me,
1527 hw_opic_device *opic,
1528 int index,
1529 unsigned reg)
1530 {
1531 opic_interrupt_source *source = &opic->interprocessor_interrupt_source[index];
1532 ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
1533 DTRACE(opic, ("ipi %d interrupt dispatch register - write 0x%x\n", index, reg));
1534 source->destination = reg;
1535 handle_interrupt(me, opic, source, 1);
1536 }
1537
1538
1539 /* vendor and other global registers */
1540
1541 static unsigned
1542 do_vendor_identification_register_read(device *me,
1543 hw_opic_device *opic)
1544 {
1545 unsigned reg;
1546 reg = opic->vendor_identification;
1547 DTRACE(opic, ("vendor identification register - read 0x%x\n", reg));
1548 return reg;
1549 }
1550
1551 static unsigned
1552 do_feature_reporting_register_N_read(device *me,
1553 hw_opic_device *opic,
1554 int index)
1555 {
1556 unsigned reg = 0;
1557 ASSERT(index == 0);
1558 switch (index) {
1559 case 0:
1560 reg |= (opic->nr_external_interrupts << 16);
1561 reg |= (opic->nr_interrupt_destinations << 8);
1562 reg |= (2/*version 1.2*/);
1563 break;
1564 }
1565 DTRACE(opic, ("feature reporting register %d - read 0x%x\n", index, reg));
1566 return reg;
1567 }
1568
1569 static unsigned
1570 do_global_configuration_register_N_read(device *me,
1571 hw_opic_device *opic,
1572 int index)
1573 {
1574 unsigned reg = 0;
1575 ASSERT(index == 0);
1576 switch (index) {
1577 case 0:
1578 reg |= gcr0_8259_bit; /* hardwire 8259 disabled */
1579 break;
1580 }
1581 DTRACE(opic, ("global configuration register %d - read 0x%x\n", index, reg));
1582 return reg;
1583 }
1584
1585 static void
1586 do_global_configuration_register_N_write(device *me,
1587 hw_opic_device *opic,
1588 int index,
1589 unsigned reg)
1590 {
1591 ASSERT(index == 0);
1592 if (reg & gcr0_reset_bit) {
1593 DTRACE(opic, ("global configuration register %d - write 0x%x - reseting opic\n", index, reg));
1594 hw_opic_init_data(me);
1595 }
1596 if (!(reg & gcr0_8259_bit)) {
1597 DTRACE(opic, ("global configuration register %d - write 0x%x - ignoring 8259 enable\n", index, reg));
1598 }
1599 }
1600
1601
1602
1603 /* register read-write */
1604
1605 static unsigned
1606 hw_opic_io_read_buffer(device *me,
1607 void *dest,
1608 int space,
1609 unsigned_word addr,
1610 unsigned nr_bytes,
1611 cpu *processor,
1612 unsigned_word cia)
1613 {
1614 hw_opic_device *opic = (hw_opic_device*)device_data(me);
1615 opic_register type;
1616 int index;
1617 decode_opic_address(me, opic, space, addr, nr_bytes, &type, &index);
1618 if (type == invalid_opic_register) {
1619 device_error(me, "invalid opic read access to %d:0x%lx (%d bytes)",
1620 space, (unsigned long)addr, nr_bytes);
1621 }
1622 else {
1623 unsigned reg;
1624 switch (type) {
1625 case processor_init_register:
1626 reg = do_processor_init_register_read(me, opic);
1627 break;
1628 case interrupt_source_N_vector_priority_register:
1629 reg = do_interrupt_source_N_vector_priority_register_read(me, opic, index);
1630 break;
1631 case interrupt_source_N_destination_register:
1632 reg = do_interrupt_source_N_destination_register_read(me, opic, index);
1633 break;
1634 case interrupt_acknowledge_register_N:
1635 reg = do_interrupt_acknowledge_register_N_read(me, opic, index);
1636 break;
1637 case spurious_vector_register:
1638 reg = do_spurious_vector_register_read(me, opic);
1639 break;
1640 case current_task_priority_register_N:
1641 reg = do_current_task_priority_register_N_read(me, opic, index);
1642 break;
1643 case timer_frequency_reporting_register:
1644 reg = do_timer_frequency_reporting_register_read(me, opic);
1645 break;
1646 case timer_N_current_count_register:
1647 reg = do_timer_N_current_count_register_read(me, opic, index);
1648 break;
1649 case timer_N_base_count_register:
1650 reg = do_timer_N_base_count_register_read(me, opic, index);
1651 break;
1652 case timer_N_vector_priority_register:
1653 reg = do_timer_N_vector_priority_register_read(me, opic, index);
1654 break;
1655 case timer_N_destination_register:
1656 reg = do_timer_N_destination_register_read(me, opic, index);
1657 break;
1658 case ipi_N_vector_priority_register:
1659 reg = do_ipi_N_vector_priority_register_read(me, opic, index);
1660 break;
1661 case feature_reporting_register_N:
1662 reg = do_feature_reporting_register_N_read(me, opic, index);
1663 break;
1664 case global_configuration_register_N:
1665 reg = do_global_configuration_register_N_read(me, opic, index);
1666 break;
1667 case vendor_identification_register:
1668 reg = do_vendor_identification_register_read(me, opic);
1669 break;
1670 default:
1671 reg = 0;
1672 device_error(me, "unimplemented read of register %s[%d]",
1673 opic_register_name(type), index);
1674 }
1675 *(unsigned_4*)dest = H2LE_4(reg);
1676 }
1677 return nr_bytes;
1678 }
1679
1680
1681 static unsigned
1682 hw_opic_io_write_buffer(device *me,
1683 const void *source,
1684 int space,
1685 unsigned_word addr,
1686 unsigned nr_bytes,
1687 cpu *processor,
1688 unsigned_word cia)
1689 {
1690 hw_opic_device *opic = (hw_opic_device*)device_data(me);
1691 opic_register type;
1692 int index;
1693 decode_opic_address(me, opic, space, addr, nr_bytes, &type, &index);
1694 if (type == invalid_opic_register) {
1695 device_error(me, "invalid opic write access to %d:0x%lx (%d bytes)",
1696 space, (unsigned long)addr, nr_bytes);
1697 }
1698 else {
1699 unsigned reg = LE2H_4(*(unsigned_4*)source);
1700 switch (type) {
1701 case processor_init_register:
1702 do_processor_init_register_write(me, opic, reg);
1703 break;
1704 case interrupt_source_N_vector_priority_register:
1705 do_interrupt_source_N_vector_priority_register_write(me, opic, index, reg);
1706 break;
1707 case interrupt_source_N_destination_register:
1708 do_interrupt_source_N_destination_register_write(me, opic, index, reg);
1709 break;
1710 case end_of_interrupt_register_N:
1711 do_end_of_interrupt_register_N_write(me, opic, index, reg);
1712 break;
1713 case spurious_vector_register:
1714 do_spurious_vector_register_write(me, opic, reg);
1715 break;
1716 case current_task_priority_register_N:
1717 do_current_task_priority_register_N_write(me, opic, index, reg);
1718 break;
1719 case timer_frequency_reporting_register:
1720 do_timer_frequency_reporting_register_write(me, opic, reg);
1721 break;
1722 case timer_N_base_count_register:
1723 do_timer_N_base_count_register_write(me, opic, index, reg);
1724 break;
1725 case timer_N_vector_priority_register:
1726 do_timer_N_vector_priority_register_write(me, opic, index, reg);
1727 break;
1728 case timer_N_destination_register:
1729 do_timer_N_destination_register_write(me, opic, index, reg);
1730 break;
1731 case ipi_N_dispatch_register:
1732 do_ipi_N_dispatch_register_write(me, opic, index, reg);
1733 break;
1734 case ipi_N_vector_priority_register:
1735 do_ipi_N_vector_priority_register_write(me, opic, index, reg);
1736 break;
1737 case global_configuration_register_N:
1738 do_global_configuration_register_N_write(me, opic, index, reg);
1739 break;
1740 default:
1741 device_error(me, "unimplemented write to register %s[%d]",
1742 opic_register_name(type), index);
1743 }
1744 }
1745 return nr_bytes;
1746 }
1747
1748
1749 static void
1750 hw_opic_interrupt_event(device *me,
1751 int my_port,
1752 device *source,
1753 int source_port,
1754 int level,
1755 cpu *processor,
1756 unsigned_word cia)
1757 {
1758 hw_opic_device *opic = (hw_opic_device*)device_data(me);
1759
1760 int isb;
1761 int src_nr = 0;
1762
1763 /* find the corresponding internal input port */
1764 for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
1765 if (my_port >= opic->isu_block[isb].int_number
1766 && my_port < opic->isu_block[isb].int_number + opic->isu_block[isb].range) {
1767 src_nr += my_port - opic->isu_block[isb].int_number;
1768 break;
1769 }
1770 else
1771 src_nr += opic->isu_block[isb].range;
1772 }
1773 if (isb == opic->nr_isu_blocks)
1774 device_error(me, "interrupt %d out of range", my_port);
1775 DTRACE(opic, ("external-interrupt %d, internal %d, level %d\n",
1776 my_port, src_nr, level));
1777
1778 /* pass it on */
1779 ASSERT(src_nr >= 0 && src_nr < opic->nr_external_interrupts);
1780 handle_interrupt(me, opic, &opic->external_interrupt_source[src_nr], level);
1781 }
1782
1783
1784 static const device_interrupt_port_descriptor hw_opic_interrupt_ports[] = {
1785 { "irq", 0, max_nr_interrupt_sources, input_port, },
1786 { "intr", 0, max_nr_interrupt_destinations, output_port, },
1787 { "init", max_nr_interrupt_destinations, max_nr_interrupt_destinations, output_port, },
1788 { NULL }
1789 };
1790
1791
1792 static device_callbacks const hw_opic_callbacks = {
1793 { generic_device_init_address,
1794 hw_opic_init_data },
1795 { NULL, }, /* address */
1796 { hw_opic_io_read_buffer,
1797 hw_opic_io_write_buffer }, /* IO */
1798 { NULL, }, /* DMA */
1799 { hw_opic_interrupt_event, NULL, hw_opic_interrupt_ports }, /* interrupt */
1800 { NULL, }, /* unit */
1801 NULL, /* instance */
1802 };
1803
1804 static void *
1805 hw_opic_create(const char *name,
1806 const device_unit *unit_address,
1807 const char *args)
1808 {
1809 hw_opic_device *opic = ZALLOC(hw_opic_device);
1810 return opic;
1811 }
1812
1813
1814
1815 const device_descriptor hw_opic_device_descriptor[] = {
1816 { "opic", hw_opic_create, &hw_opic_callbacks },
1817 { NULL },
1818 };
1819
1820 #endif /* _HW_OPIC_C_ */