1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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.
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.
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/>.
24 #include "device_table.h"
32 opic - Open Programmable Interrupt Controller (OpenPIC)
38 This device implements the core of the OpenPIC interrupt controller
39 as described in the OpenPIC specification 1.2 and other related
44 o Up to 2048 external interrupt sources
46 o The four count down timers
48 o The four interprocessor multicast interrupts
50 o multiprocessor support
52 o Full tracing to assist help debugging
54 o Support for all variations of edge/level x high/low polarity.
61 reg = <address> <size> ... (required)
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
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.
74 interrupt-ranges = <int-number> <range> ... (required)
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.
83 timer-frequency = <integer> (optional)
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.
90 vendor-identification = <integer> (optional)
92 If present, specifies the value to be returned when the vendor
93 identification register is read.
99 See the test suite directory:
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>>
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.
120 The OpenPIC specification includes a 8259 pass through mode. This
127 PowerPC Multiprocessor Interrupt Controller (MPIC), January 19,
128 1996. Available from IBM.
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/)
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/.
148 typedef struct _hw_opic_device hw_opic_device
;
154 max_nr_interrupt_sources
= 2048,
155 max_nr_interrupt_destinations
= 32,
156 max_nr_task_priorities
= 16,
165 /* global configuration register */
168 gcr0_8259_bit
= 0x20000000,
169 gcr0_reset_bit
= 0x80000000,
173 /* offsets and sizes */
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,
185 /* Interrupt sources */
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,
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 */
207 unsigned destination
;
210 } opic_interrupt_source
;
213 /* interrupt destinations (normally processors) */
215 typedef struct _opic_interrupt_destination
{
217 unsigned base_priority
;
218 opic_interrupt_source
*current_pending
;
219 opic_interrupt_source
*current_in_service
;
223 } opic_interrupt_destination
;
226 /* address map descriptors */
228 typedef struct _opic_isu_block
{ /* interrupt source unit block */
230 unsigned_word address
;
232 unsigned_cell int_number
;
238 typedef struct _opic_idu
{ /* interrupt delivery unit */
241 unsigned_word address
;
247 invalid_opic_register
,
248 /* interrupt source */
249 interrupt_source_N_destination_register
,
250 interrupt_source_N_vector_priority_register
,
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
,
267 end_of_interrupt_register_N
,
268 interrupt_acknowledge_register_N
,
269 current_task_priority_register_N
,
273 opic_register_name(opic_register 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";
302 typedef struct _opic_timer
{
304 device
*me
; /* find my way home */
305 hw_opic_device
*opic
; /* ditto */
308 signed64 count
; /* *ONLY* if inhibited */
309 event_entry_tag timeout_event
;
310 opic_interrupt_source
*interrupt_source
;
316 struct _hw_opic_device
{
319 unsigned vendor_identification
;
321 /* interrupt destinations - processors */
322 int nr_interrupt_destinations
;
323 opic_interrupt_destination
*interrupt_destination
;
324 unsigned sizeof_interrupt_destination
;
326 /* bogus interrupts */
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
;
334 /* external interrupts */
335 int nr_external_interrupts
;
336 opic_interrupt_source
*external_interrupt_source
;
338 /* inter-processor-interrupts */
339 int nr_interprocessor_interrupts
;
340 opic_interrupt_source
*interprocessor_interrupt_source
;
343 int nr_timer_interrupts
;
345 unsigned sizeof_timer
;
346 opic_interrupt_source
*timer_interrupt_source
;
347 unsigned timer_frequency
;
355 opic_isu_block
*isu_block
;
360 hw_opic_init_data(device
*me
)
362 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
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. */
374 reg_property_spec unit
;
376 unsigned_word attach_address
;
377 unsigned attach_size
;
378 if (!device_find_reg_array_property(me
, "reg", idu_reg
+ nr_isu_blocks
,
381 if (nr_isu_blocks
> 0
382 || (device_address_to_attach_address(device_parent(me
), &unit
.address
,
383 &attach_space
, &attach_address
,
385 && device_size_to_attach_size(device_parent(me
), &unit
.size
,
388 /* we count any thing once we've found one valid address/size pair */
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
) {
400 opic
->nr_isu_blocks
= nr_isu_blocks
;
401 opic
->isu_block
= zalloc(sizeof(opic_isu_block
) * opic
->nr_isu_blocks
);
404 while (isb
< opic
->nr_isu_blocks
) {
405 reg_property_spec reg
;
406 if (!device_find_reg_array_property(me
, "reg", reg_nr
, ®
))
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
), ®
.address
,
410 &opic
->isu_block
[isb
].space
,
411 &opic
->isu_block
[isb
].address
,
413 || !device_size_to_attach_size(device_parent(me
), ®
.size
,
414 &opic
->isu_block
[isb
].size
,
416 device_error(me
, "reg property entry %d invalid", reg_nr
);
418 if (!device_find_integer_array_property(me
, "interrupt-ranges",
420 &opic
->isu_block
[isb
].int_number
)
421 || !device_find_integer_array_property(me
, "interrupt-ranges",
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);
435 /* was this a valid reg entry? */
436 if (opic
->isu_block
[isb
].range
== 0) {
437 opic
->nr_isu_blocks
-= 1;
440 opic
->nr_external_interrupts
+= opic
->isu_block
[isb
].range
;
446 DTRACE(opic
, ("interrupt source unit block - effective number of blocks %d\n",
447 (int)opic
->nr_isu_blocks
));
450 /* the number of other interrupts */
451 opic
->nr_interprocessor_interrupts
= 4;
452 opic
->nr_timer_interrupts
= 4;
455 /* create space for the interrupt source registers */
456 if (opic
->interrupt_source
!= NULL
) {
457 memset(opic
->interrupt_source
, 0, opic
->sizeof_interrupt_source
);
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
);
474 for (i
= 0; i
< opic
->nr_interrupt_sources
; i
++) {
475 opic_interrupt_source
*source
= &opic
->interrupt_source
[i
];
477 source
->is_masked
= isu_mask_bit
;
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
));
486 /* timers or interprocessor interrupts */
487 if (opic
->timer
!= NULL
)
488 memset(opic
->timer
, 0, opic
->sizeof_timer
);
490 opic
->nr_timer_interrupts
= 4;
491 opic
->sizeof_timer
= sizeof(opic_timer
) * opic
->nr_timer_interrupts
;
492 opic
->timer
= zalloc(opic
->sizeof_timer
);
494 for (i
= 0; i
< opic
->nr_timer_interrupts
; i
++) {
495 opic_timer
*timer
= &opic
->timer
[i
];
499 timer
->inhibited
= 1;
500 timer
->interrupt_source
= &opic
->timer_interrupt_source
[i
];
502 if (device_find_property(me
, "timer-frequency"))
503 opic
->timer_frequency
= device_find_integer_property(me
, "timer-frequency");
505 opic
->timer_frequency
= 1;
508 /* create space for the interrupt destination registers */
509 if (opic
->interrupt_destination
!= NULL
) {
510 memset(opic
->interrupt_destination
, 0, opic
->sizeof_interrupt_destination
);
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");
520 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
521 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
522 dest
->bit
= (1 << i
);
524 dest
->init_port
= (device_interrupt_decode(me
, "init0", output_port
)
526 dest
->intr_port
= (device_interrupt_decode(me
, "intr0", output_port
)
528 dest
->base_priority
= max_nr_task_priorities
- 1;
530 DTRACE(opic
, ("interrupt destinations - total %d\n",
531 (int)opic
->nr_interrupt_destinations
));
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",
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
));
554 /* verify and print out the IDU */
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",
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
));
577 /* initialize the init interrupts */
582 if (device_find_property(me
, "vendor-identification") != NULL
)
583 opic
->vendor_identification
= device_find_integer_property(me
, "vendor-identification");
585 opic
->vendor_identification
= 0;
588 opic
->spurious_vector
= 0xff;
593 /* interrupt related actions */
596 assert_interrupt(device
*me
,
597 hw_opic_device
*opic
,
598 opic_interrupt_destination
*dest
)
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);
608 negate_interrupt(device
*me
,
609 hw_opic_device
*opic
,
610 opic_interrupt_destination
*dest
)
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);
620 can_deliver(device
*me
,
621 opic_interrupt_source
*source
,
622 opic_interrupt_destination
*dest
)
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
));
632 deliver_pending(device
*me
,
633 hw_opic_device
*opic
,
634 opic_interrupt_destination
*dest
)
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
;
643 dest
->current_pending
->pending
= 0;
645 dest
->current_pending
= NULL
;
646 negate_interrupt(me
, opic
, dest
);
647 return dest
->current_in_service
->vector
;
653 in_service_interrupt
,
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)
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? */
668 case in_service_interrupt
:
669 if ((src
->in_service
& dest
->bit
) == 0)
672 case pending_interrupt
:
673 if ((src
->pending
& dest
->bit
) == 0)
677 /* see if it is the highest priority */
680 else if (src
->priority
> pending
->priority
)
687 static opic_interrupt_destination
*
688 find_lowest_dest(device
*me
,
689 hw_opic_device
*opic
,
690 opic_interrupt_source
*src
)
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
) {
700 else if (lowest
->base_priority
> dest
->base_priority
)
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 */
719 handle_interrupt(device
*me
,
720 hw_opic_device
*opic
,
721 opic_interrupt_source
*src
,
724 if (src
->is_masked
) {
725 DTRACE(opic
, ("interrupt %d - ignore masked\n", src
->nr
));
727 else if (src
->is_multicast
) {
728 /* always try to deliver multicast interrupts - just easier */
730 ASSERT(!src
->is_level_triggered
);
731 ASSERT(src
->is_positive_polarity
);
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",
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",
748 src
->pending
|= dest
->bit
;
749 DTRACE(opic
, ("interrupt %d - multicast pending to %d\n",
755 else if (src
->is_level_triggered
756 && src
->is_positive_polarity
759 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active high)\n",
762 DTRACE(opic
, ("interrupt %d - ignore low level (active high)\n",
764 ASSERT(!src
->is_multicast
);
767 else if (src
->is_level_triggered
768 && !src
->is_positive_polarity
771 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active low)\n",
774 DTRACE(opic
, ("interrupt %d - ignore high level (active low)\n",
777 ASSERT(!src
->is_multicast
);
780 else if (!src
->is_level_triggered
781 && src
->is_positive_polarity
783 DTRACE(opic
, ("interrupt %d - ignore falling edge (positive edge trigered)\n",
786 else if (!src
->is_level_triggered
787 && !src
->is_positive_polarity
789 DTRACE(opic
, ("interrupt %d - ignore rising edge (negative edge trigered)\n",
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
));
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
));
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
);
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
));
822 do_interrupt_acknowledge_register_N_read(device
*me
,
823 hw_opic_device
*opic
,
826 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
829 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
830 ASSERT(dest_nr
== dest
->nr
);
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",
838 dest
->current_in_service
->nr
,
839 dest
->current_in_service
->vector
, vector
,
840 dest
->current_in_service
->priority
));
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",
849 dest
->current_in_service
->nr
,
850 dest
->current_in_service
->vector
, vector
,
851 dest
->current_in_service
->priority
));
854 dest
->current_pending
= NULL
;
855 vector
= opic
->spurious_vector
;
856 DTRACE(opic
, ("interrupt ack %d - spurious interrupt %d\n",
865 do_end_of_interrupt_register_N_write(device
*me
,
866 hw_opic_device
*opic
,
870 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
872 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
873 ASSERT(dest_nr
== dest
->nr
);
875 /* check the value written is zero */
877 DTRACE(opic
, ("eoi %d - ignoring nonzero value\n", dest
->nr
));
880 /* user doing wierd things? */
881 if (dest
->current_in_service
== NULL
) {
882 DTRACE(opic
, ("eoi %d - strange, no current interrupt\n", dest
->nr
));
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
);
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",
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",
902 dest
->current_in_service
->nr
,
903 dest
->current_in_service
->priority
,
904 dest
->current_in_service
->vector
));
906 DTRACE(opic
, ("eoi %d - resuming none\n", dest
->nr
));
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
);
915 dest
->current_pending
= NULL
;
921 decode_opic_address(device
*me
,
922 hw_opic_device
*opic
,
924 unsigned_word address
,
931 /* is the size valid? */
933 *type
= invalid_opic_register
;
938 /* try for a per-processor register within the interrupt delivery
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
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
;
952 *type
= ipi_N_dispatch_register
;
956 *type
= ipi_N_dispatch_register
;
960 *type
= ipi_N_dispatch_register
;
964 *type
= ipi_N_dispatch_register
;
968 *type
= current_task_priority_register_N
;
971 *type
= interrupt_acknowledge_register_N
;
974 *type
= end_of_interrupt_register_N
;
977 *type
= invalid_opic_register
;
980 DTRACE(opic
, ("per-processor register %d:0x%lx - %s[%d]\n",
981 space
, (unsigned long)address
,
982 opic_register_name(*type
),
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
));
998 *type
= interrupt_source_N_vector_priority_register
;
1001 *type
= interrupt_source_N_destination_register
;
1004 *type
= invalid_opic_register
;
1007 DTRACE(opic
, ("isu register %d:0x%lx - %s[%d]\n",
1008 space
, (unsigned long)address
,
1009 opic_register_name(*type
),
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
);
1025 *type
= timer_N_current_count_register
;
1028 *type
= timer_N_base_count_register
;
1031 *type
= timer_N_vector_priority_register
;
1034 *type
= timer_N_destination_register
;
1037 *type
= invalid_opic_register
;
1040 DTRACE(opic
, ("timer register %d:0x%lx - %s[%d]\n",
1041 space
, (unsigned long)address
,
1042 opic_register_name(*type
),
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
) {
1054 *type
= timer_frequency_reporting_register
;
1058 *type
= spurious_vector_register
;
1065 *type
= ipi_N_vector_priority_register
;
1066 *index
= (block_offset
- 0x010a0) / 16;
1069 *type
= processor_init_register
;
1073 *type
= vendor_identification_register
;
1077 *type
= global_configuration_register_N
;
1081 *type
= feature_reporting_register_N
;
1085 *type
= invalid_opic_register
;
1089 DTRACE(opic
, ("global register %d:0x%lx - %s[%d]\n",
1090 space
, (unsigned long)address
,
1091 opic_register_name(*type
),
1096 /* nothing matched */
1097 *type
= invalid_opic_register
;
1098 DTRACE(opic
, ("invalid register %d:0x%lx\n",
1099 space
, (unsigned long)address
));
1104 /* Processor init register:
1106 The bits in this register (one per processor) are directly wired to
1107 output "init" interrupt ports. */
1110 do_processor_init_register_read(device
*me
,
1111 hw_opic_device
*opic
)
1113 unsigned reg
= opic
->init
;
1114 DTRACE(opic
, ("processor init register - read 0x%lx\n",
1120 do_processor_init_register_write(device
*me
,
1121 hw_opic_device
*opic
,
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",
1131 opic
->init
|= dest
->bit
;
1132 device_interrupt_event(me
, dest
->init_port
, 1, NULL
, 0);
1135 DTRACE(opic
, ("processor init register - write 0x%lx - negating init%d\n",
1137 opic
->init
&= ~dest
->bit
;
1138 device_interrupt_event(me
, dest
->init_port
, 0, NULL
, 0);
1146 /* Interrupt Source Vector/Priority Register: */
1149 read_vector_priority_register(device
*me
,
1150 hw_opic_device
*opic
,
1151 opic_interrupt_source
*interrupt
,
1152 const char *reg_name
,
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
));
1171 do_interrupt_source_N_vector_priority_register_read(device
*me
,
1172 hw_opic_device
*opic
,
1176 ASSERT(index
< opic
->nr_external_interrupts
);
1177 reg
= read_vector_priority_register(me
, opic
,
1178 &opic
->interrupt_source
[index
],
1179 "interrupt source", index
);
1184 write_vector_priority_register(device
*me
,
1185 hw_opic_device
*opic
,
1186 opic_interrupt_source
*interrupt
,
1188 const char *reg_name
,
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",
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
));
1211 do_interrupt_source_N_vector_priority_register_write(device
*me
,
1212 hw_opic_device
*opic
,
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
);
1225 /* Interrupt Source Destination Register: */
1228 read_destination_register(device
*me
,
1229 hw_opic_device
*opic
,
1230 opic_interrupt_source
*interrupt
,
1231 const char *reg_name
,
1235 reg
= interrupt
->destination
;
1236 DTRACE(opic
, ("%s %d destination register - read 0x%lx\n",
1237 reg_name
, reg_index
, reg
));
1242 do_interrupt_source_N_destination_register_read(device
*me
,
1243 hw_opic_device
*opic
,
1247 ASSERT(index
< opic
->nr_external_interrupts
);
1248 reg
= read_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1249 "interrupt source", index
);
1254 write_destination_register(device
*me
,
1255 hw_opic_device
*opic
,
1256 opic_interrupt_source
*interrupt
,
1258 const char *reg_name
,
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
;
1268 do_interrupt_source_N_destination_register_write(device
*me
,
1269 hw_opic_device
*opic
,
1273 ASSERT(index
< opic
->nr_external_interrupts
);
1274 write_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1275 reg
, "interrupt source", index
);
1280 /* Spurious vector register: */
1283 do_spurious_vector_register_read(device
*me
,
1284 hw_opic_device
*opic
)
1286 unsigned long reg
= opic
->spurious_vector
;
1287 DTRACE(opic
, ("spurious vector register - read 0x%lx\n", reg
));
1292 do_spurious_vector_register_write(device
*me
,
1293 hw_opic_device
*opic
,
1296 reg
&= 0xff; /* mask off invalid */
1297 DTRACE(opic
, ("spurious vector register - write 0x%x\n", reg
));
1298 opic
->spurious_vector
= reg
;
1303 /* current task priority register: */
1306 do_current_task_priority_register_N_read(device
*me
,
1307 hw_opic_device
*opic
,
1310 opic_interrupt_destination
*interrupt_destination
= &opic
->interrupt_destination
[index
];
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
));
1319 do_current_task_priority_register_N_write(device
*me
,
1320 hw_opic_device
*opic
,
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
;
1333 /* Timer Frequency Reporting Register: */
1336 do_timer_frequency_reporting_register_read(device
*me
,
1337 hw_opic_device
*opic
)
1340 reg
= opic
->timer_frequency
;
1341 DTRACE(opic
, ("timer frequency reporting register - read 0x%x\n", reg
));
1346 do_timer_frequency_reporting_register_write(device
*me
,
1347 hw_opic_device
*opic
,
1350 DTRACE(opic
, ("timer frequency reporting register - write 0x%x\n", reg
));
1351 opic
->timer_frequency
= reg
;
1355 /* timer registers: */
1358 do_timer_N_current_count_register_read(device
*me
,
1359 hw_opic_device
*opic
,
1362 opic_timer
*timer
= &opic
->timer
[index
];
1364 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1365 if (timer
->inhibited
)
1366 reg
= timer
->count
; /* stalled value */
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
));
1375 do_timer_N_base_count_register_read(device
*me
,
1376 hw_opic_device
*opic
,
1379 opic_timer
*timer
= &opic
->timer
[index
];
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
));
1389 timer_event(void *data
)
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",
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
));
1405 do_timer_N_base_count_register_write(device
*me
,
1406 hw_opic_device
*opic
,
1410 opic_timer
*timer
= &opic
->timer
[index
];
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",
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",
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
;
1443 do_timer_N_vector_priority_register_read(device
*me
,
1444 hw_opic_device
*opic
,
1448 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1449 reg
= read_vector_priority_register(me
, opic
,
1450 &opic
->timer_interrupt_source
[index
],
1456 do_timer_N_vector_priority_register_write(device
*me
,
1457 hw_opic_device
*opic
,
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
);
1472 do_timer_N_destination_register_read(device
*me
,
1473 hw_opic_device
*opic
,
1477 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1478 reg
= read_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1484 do_timer_N_destination_register_write(device
*me
,
1485 hw_opic_device
*opic
,
1489 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1490 write_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1491 reg
, "timer", index
);
1498 do_ipi_N_vector_priority_register_read(device
*me
,
1499 hw_opic_device
*opic
,
1503 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1504 reg
= read_vector_priority_register(me
, opic
,
1505 &opic
->interprocessor_interrupt_source
[index
],
1511 do_ipi_N_vector_priority_register_write(device
*me
,
1512 hw_opic_device
*opic
,
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
],
1526 do_ipi_N_dispatch_register_write(device
*me
,
1527 hw_opic_device
*opic
,
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);
1539 /* vendor and other global registers */
1542 do_vendor_identification_register_read(device
*me
,
1543 hw_opic_device
*opic
)
1546 reg
= opic
->vendor_identification
;
1547 DTRACE(opic
, ("vendor identification register - read 0x%x\n", reg
));
1552 do_feature_reporting_register_N_read(device
*me
,
1553 hw_opic_device
*opic
,
1560 reg
|= (opic
->nr_external_interrupts
<< 16);
1561 reg
|= (opic
->nr_interrupt_destinations
<< 8);
1562 reg
|= (2/*version 1.2*/);
1565 DTRACE(opic
, ("feature reporting register %d - read 0x%x\n", index
, reg
));
1570 do_global_configuration_register_N_read(device
*me
,
1571 hw_opic_device
*opic
,
1578 reg
|= gcr0_8259_bit
; /* hardwire 8259 disabled */
1581 DTRACE(opic
, ("global configuration register %d - read 0x%x\n", index
, reg
));
1586 do_global_configuration_register_N_write(device
*me
,
1587 hw_opic_device
*opic
,
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
);
1596 if (!(reg
& gcr0_8259_bit
)) {
1597 DTRACE(opic
, ("global configuration register %d - write 0x%x - ignoring 8259 enable\n", index
, reg
));
1603 /* register read-write */
1606 hw_opic_io_read_buffer(device
*me
,
1614 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
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
);
1625 case processor_init_register
:
1626 reg
= do_processor_init_register_read(me
, opic
);
1628 case interrupt_source_N_vector_priority_register
:
1629 reg
= do_interrupt_source_N_vector_priority_register_read(me
, opic
, index
);
1631 case interrupt_source_N_destination_register
:
1632 reg
= do_interrupt_source_N_destination_register_read(me
, opic
, index
);
1634 case interrupt_acknowledge_register_N
:
1635 reg
= do_interrupt_acknowledge_register_N_read(me
, opic
, index
);
1637 case spurious_vector_register
:
1638 reg
= do_spurious_vector_register_read(me
, opic
);
1640 case current_task_priority_register_N
:
1641 reg
= do_current_task_priority_register_N_read(me
, opic
, index
);
1643 case timer_frequency_reporting_register
:
1644 reg
= do_timer_frequency_reporting_register_read(me
, opic
);
1646 case timer_N_current_count_register
:
1647 reg
= do_timer_N_current_count_register_read(me
, opic
, index
);
1649 case timer_N_base_count_register
:
1650 reg
= do_timer_N_base_count_register_read(me
, opic
, index
);
1652 case timer_N_vector_priority_register
:
1653 reg
= do_timer_N_vector_priority_register_read(me
, opic
, index
);
1655 case timer_N_destination_register
:
1656 reg
= do_timer_N_destination_register_read(me
, opic
, index
);
1658 case ipi_N_vector_priority_register
:
1659 reg
= do_ipi_N_vector_priority_register_read(me
, opic
, index
);
1661 case feature_reporting_register_N
:
1662 reg
= do_feature_reporting_register_N_read(me
, opic
, index
);
1664 case global_configuration_register_N
:
1665 reg
= do_global_configuration_register_N_read(me
, opic
, index
);
1667 case vendor_identification_register
:
1668 reg
= do_vendor_identification_register_read(me
, opic
);
1672 device_error(me
, "unimplemented read of register %s[%d]",
1673 opic_register_name(type
), index
);
1675 *(unsigned_4
*)dest
= H2LE_4(reg
);
1682 hw_opic_io_write_buffer(device
*me
,
1690 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
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
);
1699 unsigned reg
= LE2H_4(*(unsigned_4
*)source
);
1701 case processor_init_register
:
1702 do_processor_init_register_write(me
, opic
, reg
);
1704 case interrupt_source_N_vector_priority_register
:
1705 do_interrupt_source_N_vector_priority_register_write(me
, opic
, index
, reg
);
1707 case interrupt_source_N_destination_register
:
1708 do_interrupt_source_N_destination_register_write(me
, opic
, index
, reg
);
1710 case end_of_interrupt_register_N
:
1711 do_end_of_interrupt_register_N_write(me
, opic
, index
, reg
);
1713 case spurious_vector_register
:
1714 do_spurious_vector_register_write(me
, opic
, reg
);
1716 case current_task_priority_register_N
:
1717 do_current_task_priority_register_N_write(me
, opic
, index
, reg
);
1719 case timer_frequency_reporting_register
:
1720 do_timer_frequency_reporting_register_write(me
, opic
, reg
);
1722 case timer_N_base_count_register
:
1723 do_timer_N_base_count_register_write(me
, opic
, index
, reg
);
1725 case timer_N_vector_priority_register
:
1726 do_timer_N_vector_priority_register_write(me
, opic
, index
, reg
);
1728 case timer_N_destination_register
:
1729 do_timer_N_destination_register_write(me
, opic
, index
, reg
);
1731 case ipi_N_dispatch_register
:
1732 do_ipi_N_dispatch_register_write(me
, opic
, index
, reg
);
1734 case ipi_N_vector_priority_register
:
1735 do_ipi_N_vector_priority_register_write(me
, opic
, index
, reg
);
1737 case global_configuration_register_N
:
1738 do_global_configuration_register_N_write(me
, opic
, index
, reg
);
1741 device_error(me
, "unimplemented write to register %s[%d]",
1742 opic_register_name(type
), index
);
1750 hw_opic_interrupt_event(device
*me
,
1758 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
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
;
1771 src_nr
+= opic
->isu_block
[isb
].range
;
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
));
1779 ASSERT(src_nr
>= 0 && src_nr
< opic
->nr_external_interrupts
);
1780 handle_interrupt(me
, opic
, &opic
->external_interrupt_source
[src_nr
], level
);
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
, },
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 */
1805 hw_opic_create(const char *name
,
1806 const device_unit
*unit_address
,
1809 hw_opic_device
*opic
= ZALLOC(hw_opic_device
);
1815 const device_descriptor hw_opic_device_descriptor
[] = {
1816 { "opic", hw_opic_create
, &hw_opic_callbacks
},
1820 #endif /* _HW_OPIC_C_ */