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 int64_t 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",
421 &opic
->isu_block
[isb
].int_number
)
422 || !device_find_integer_array_property(me
, "interrupt-ranges",
425 &opic
->isu_block
[isb
].range
))
426 device_error(me
, "missing or invalid interrupt-ranges property entry %d", reg_nr
);
427 /* first reg entry specifies the address of both the IDU and the
428 first set of ISU registers, adjust things accordingly */
429 if (reg_nr
== idu_reg
) {
430 opic
->idu
.reg
= opic
->isu_block
[isb
].reg
;
431 opic
->idu
.space
= opic
->isu_block
[isb
].space
;
432 opic
->idu
.address
= opic
->isu_block
[isb
].address
;
433 opic
->idu
.size
= opic
->isu_block
[isb
].size
;
434 opic
->isu_block
[isb
].address
+= idu_isu_base
;
435 opic
->isu_block
[isb
].size
= opic
->isu_block
[isb
].range
* (16 + 16);
437 /* was this a valid reg entry? */
438 if (opic
->isu_block
[isb
].range
== 0) {
439 opic
->nr_isu_blocks
-= 1;
442 opic
->nr_external_interrupts
+= opic
->isu_block
[isb
].range
;
448 DTRACE(opic
, ("interrupt source unit block - effective number of blocks %d\n",
449 (int)opic
->nr_isu_blocks
));
452 /* the number of other interrupts */
453 opic
->nr_interprocessor_interrupts
= 4;
454 opic
->nr_timer_interrupts
= 4;
457 /* create space for the interrupt source registers */
458 if (opic
->interrupt_source
!= NULL
) {
459 memset(opic
->interrupt_source
, 0, opic
->sizeof_interrupt_source
);
462 opic
->nr_interrupt_sources
= (opic
->nr_external_interrupts
463 + opic
->nr_interprocessor_interrupts
464 + opic
->nr_timer_interrupts
);
465 if (opic
->nr_interrupt_sources
> max_nr_interrupt_sources
)
466 device_error(me
, "number of interrupt sources exceeded");
467 opic
->sizeof_interrupt_source
= (sizeof(opic_interrupt_source
)
468 * opic
->nr_interrupt_sources
);
469 opic
->interrupt_source
= zalloc(opic
->sizeof_interrupt_source
);
470 opic
->external_interrupt_source
= opic
->interrupt_source
;
471 opic
->interprocessor_interrupt_source
= (opic
->external_interrupt_source
472 + opic
->nr_external_interrupts
);
473 opic
->timer_interrupt_source
= (opic
->interprocessor_interrupt_source
474 + opic
->nr_interprocessor_interrupts
);
476 for (i
= 0; i
< opic
->nr_interrupt_sources
; i
++) {
477 opic_interrupt_source
*source
= &opic
->interrupt_source
[i
];
479 source
->is_masked
= isu_mask_bit
;
481 DTRACE(opic
, ("interrupt sources - external %d, timer %d, ipi %d, total %d\n",
482 opic
->nr_external_interrupts
,
483 opic
->nr_timer_interrupts
,
484 opic
->nr_interprocessor_interrupts
,
485 opic
->nr_interrupt_sources
));
488 /* timers or interprocessor interrupts */
489 if (opic
->timer
!= NULL
)
490 memset(opic
->timer
, 0, opic
->sizeof_timer
);
492 opic
->nr_timer_interrupts
= 4;
493 opic
->sizeof_timer
= sizeof(opic_timer
) * opic
->nr_timer_interrupts
;
494 opic
->timer
= zalloc(opic
->sizeof_timer
);
496 for (i
= 0; i
< opic
->nr_timer_interrupts
; i
++) {
497 opic_timer
*timer
= &opic
->timer
[i
];
501 timer
->inhibited
= 1;
502 timer
->interrupt_source
= &opic
->timer_interrupt_source
[i
];
504 if (device_find_property(me
, "timer-frequency"))
505 opic
->timer_frequency
= device_find_integer_property(me
, "timer-frequency");
507 opic
->timer_frequency
= 1;
510 /* create space for the interrupt destination registers */
511 if (opic
->interrupt_destination
!= NULL
) {
512 memset(opic
->interrupt_destination
, 0, opic
->sizeof_interrupt_destination
);
515 opic
->nr_interrupt_destinations
= tree_find_integer_property(me
, "/openprom/options/smp");
516 opic
->sizeof_interrupt_destination
= (sizeof(opic_interrupt_destination
)
517 * opic
->nr_interrupt_destinations
);
518 opic
->interrupt_destination
= zalloc(opic
->sizeof_interrupt_destination
);
519 if (opic
->nr_interrupt_destinations
> max_nr_interrupt_destinations
)
520 device_error(me
, "number of interrupt destinations exceeded");
522 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
523 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
524 dest
->bit
= (1 << i
);
526 dest
->init_port
= (device_interrupt_decode(me
, "init0", output_port
)
528 dest
->intr_port
= (device_interrupt_decode(me
, "intr0", output_port
)
530 dest
->base_priority
= max_nr_task_priorities
- 1;
532 DTRACE(opic
, ("interrupt destinations - total %d\n",
533 (int)opic
->nr_interrupt_destinations
));
536 /* verify and print out the ISU's */
537 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
538 unsigned correct_size
;
539 if ((opic
->isu_block
[isb
].address
% opic_alignment
) != 0)
540 device_error(me
, "interrupt source unit %d address not aligned to %d byte boundary",
541 isb
, opic_alignment
);
542 correct_size
= opic
->isu_block
[isb
].range
* sizeof_isu_register_block
;
543 if (opic
->isu_block
[isb
].size
!= correct_size
)
544 device_error(me
, "interrupt source unit %d (reg %d) has an incorrect size, should be 0x%x",
545 isb
, opic
->isu_block
[isb
].reg
, correct_size
);
546 DTRACE(opic
, ("interrupt source unit block %ld - address %d:0x%lx, size 0x%lx, int-number %ld, range %ld\n",
548 (int)opic
->isu_block
[isb
].space
,
549 (unsigned long)opic
->isu_block
[isb
].address
,
550 (unsigned long)opic
->isu_block
[isb
].size
,
551 (long)opic
->isu_block
[isb
].int_number
,
552 (long)opic
->isu_block
[isb
].range
));
556 /* verify and print out the IDU */
558 unsigned correct_size
;
559 unsigned alternate_size
;
560 if ((opic
->idu
.address
% opic_alignment
) != 0)
561 device_error(me
, "interrupt delivery unit not aligned to %d byte boundary",
563 correct_size
= (idu_per_processor_register_base
564 + (sizeof_idu_per_processor_register_block
565 * opic
->nr_interrupt_destinations
));
566 alternate_size
= (idu_per_processor_register_base
567 + (sizeof_idu_per_processor_register_block
568 * max_nr_interrupt_destinations
));
569 if (opic
->idu
.size
!= correct_size
570 && opic
->idu
.size
!= alternate_size
)
571 device_error(me
, "interrupt delivery unit has incorrect size, should be 0x%x or 0x%x",
572 correct_size
, alternate_size
);
573 DTRACE(opic
, ("interrupt delivery unit - address %d:0x%lx, size 0x%lx\n",
574 (int)opic
->idu
.space
,
575 (unsigned long)opic
->idu
.address
,
576 (unsigned long)opic
->idu
.size
));
579 /* initialize the init interrupts */
584 if (device_find_property(me
, "vendor-identification") != NULL
)
585 opic
->vendor_identification
= device_find_integer_property(me
, "vendor-identification");
587 opic
->vendor_identification
= 0;
590 opic
->spurious_vector
= 0xff;
595 /* interrupt related actions */
598 assert_interrupt(device
*me
,
599 hw_opic_device
*opic
,
600 opic_interrupt_destination
*dest
)
602 ASSERT(dest
>= opic
->interrupt_destination
);
603 ASSERT(dest
< opic
->interrupt_destination
+ opic
->nr_interrupt_destinations
);
604 DTRACE(opic
, ("assert interrupt - intr port %d\n", dest
->intr_port
));
605 device_interrupt_event(me
, dest
->intr_port
, 1, NULL
, 0);
610 negate_interrupt(device
*me
,
611 hw_opic_device
*opic
,
612 opic_interrupt_destination
*dest
)
614 ASSERT(dest
>= opic
->interrupt_destination
);
615 ASSERT(dest
< opic
->interrupt_destination
+ opic
->nr_interrupt_destinations
);
616 DTRACE(opic
, ("negate interrupt - intr port %d\n", dest
->intr_port
));
617 device_interrupt_event(me
, dest
->intr_port
, 0, NULL
, 0);
622 can_deliver(device
*me
,
623 opic_interrupt_source
*source
,
624 opic_interrupt_destination
*dest
)
626 return (source
!= NULL
&& dest
!= NULL
627 && source
->priority
> dest
->base_priority
628 && (dest
->current_in_service
== NULL
629 || source
->priority
> dest
->current_in_service
->priority
));
634 deliver_pending(device
*me
,
635 hw_opic_device
*opic
,
636 opic_interrupt_destination
*dest
)
638 ASSERT(can_deliver(me
, dest
->current_pending
, dest
));
639 dest
->current_in_service
= dest
->current_pending
;
640 dest
->current_in_service
->in_service
|= dest
->bit
;
641 if (!dest
->current_pending
->is_level_triggered
) {
642 if (dest
->current_pending
->is_multicast
)
643 dest
->current_pending
->pending
&= ~dest
->bit
;
645 dest
->current_pending
->pending
= 0;
647 dest
->current_pending
= NULL
;
648 negate_interrupt(me
, opic
, dest
);
649 return dest
->current_in_service
->vector
;
655 in_service_interrupt
,
658 static opic_interrupt_source
*
659 find_interrupt_for_dest(device
*me
,
660 hw_opic_device
*opic
,
661 opic_interrupt_destination
*dest
,
662 interrupt_class
class)
665 opic_interrupt_source
*pending
= NULL
;
666 for (i
= 0; i
< opic
->nr_interrupt_sources
; i
++) {
667 opic_interrupt_source
*src
= &opic
->interrupt_source
[i
];
668 /* is this a potential hit? */
670 case in_service_interrupt
:
671 if ((src
->in_service
& dest
->bit
) == 0)
674 case pending_interrupt
:
675 if ((src
->pending
& dest
->bit
) == 0)
679 /* see if it is the highest priority */
682 else if (src
->priority
> pending
->priority
)
689 static opic_interrupt_destination
*
690 find_lowest_dest(device
*me
,
691 hw_opic_device
*opic
,
692 opic_interrupt_source
*src
)
695 opic_interrupt_destination
*lowest
= NULL
;
696 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
697 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
698 if (src
->destination
& dest
->bit
) {
699 if (dest
->base_priority
< src
->priority
) {
702 else if (lowest
->base_priority
> dest
->base_priority
)
704 else if (lowest
->current_in_service
!= NULL
705 && dest
->current_in_service
== NULL
)
706 lowest
= dest
; /* not doing anything */
707 else if (lowest
->current_in_service
!= NULL
708 && dest
->current_in_service
!= NULL
709 && (lowest
->current_in_service
->priority
710 > dest
->current_in_service
->priority
))
711 lowest
= dest
; /* less urgent */
712 /* FIXME - need to be more fair */
721 handle_interrupt(device
*me
,
722 hw_opic_device
*opic
,
723 opic_interrupt_source
*src
,
726 if (src
->is_masked
) {
727 DTRACE(opic
, ("interrupt %d - ignore masked\n", src
->nr
));
729 else if (src
->is_multicast
) {
730 /* always try to deliver multicast interrupts - just easier */
732 ASSERT(!src
->is_level_triggered
);
733 ASSERT(src
->is_positive_polarity
);
735 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
736 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
737 if (src
->destination
& dest
->bit
) {
738 if (src
->pending
& dest
->bit
) {
739 DTRACE(opic
, ("interrupt %d - multicast still pending to %d\n",
742 else if (can_deliver(me
, src
, dest
)) {
743 dest
->current_pending
= src
;
744 src
->pending
|= dest
->bit
;
745 assert_interrupt(me
, opic
, dest
);
746 DTRACE(opic
, ("interrupt %d - multicast to %d\n",
750 src
->pending
|= dest
->bit
;
751 DTRACE(opic
, ("interrupt %d - multicast pending to %d\n",
757 else if (src
->is_level_triggered
758 && src
->is_positive_polarity
761 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active high)\n",
764 DTRACE(opic
, ("interrupt %d - ignore low level (active high)\n",
766 ASSERT(!src
->is_multicast
);
769 else if (src
->is_level_triggered
770 && !src
->is_positive_polarity
773 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active low)\n",
776 DTRACE(opic
, ("interrupt %d - ignore high level (active low)\n",
779 ASSERT(!src
->is_multicast
);
782 else if (!src
->is_level_triggered
783 && src
->is_positive_polarity
785 DTRACE(opic
, ("interrupt %d - ignore falling edge (positive edge trigered)\n",
788 else if (!src
->is_level_triggered
789 && !src
->is_positive_polarity
791 DTRACE(opic
, ("interrupt %d - ignore rising edge (negative edge trigered)\n",
794 else if (src
->in_service
!= 0) {
795 /* leave the interrupt where it is */
796 ASSERT(!src
->is_multicast
);
797 ASSERT(src
->pending
== 0 || src
->pending
== src
->in_service
);
798 src
->pending
= src
->in_service
;
799 DTRACE(opic
, ("interrupt %ld - ignore already in service to 0x%lx\n",
800 (long)src
->nr
, (long)src
->in_service
));
802 else if (src
->pending
!= 0) {
803 DTRACE(opic
, ("interrupt %ld - ignore still pending to 0x%lx\n",
804 (long)src
->nr
, (long)src
->pending
));
807 /* delivery is needed */
808 opic_interrupt_destination
*dest
= find_lowest_dest(me
, opic
, src
);
809 if (can_deliver(me
, src
, dest
)) {
810 dest
->current_pending
= src
;
811 src
->pending
= dest
->bit
;
812 DTRACE(opic
, ("interrupt %d - delivered to %d\n", src
->nr
, dest
->nr
));
813 assert_interrupt(me
, opic
, dest
);
816 src
->pending
= src
->destination
; /* any can take this */
817 DTRACE(opic
, ("interrupt %ld - pending to 0x%lx\n",
818 (long)src
->nr
, (long)src
->pending
));
824 do_interrupt_acknowledge_register_N_read(device
*me
,
825 hw_opic_device
*opic
,
828 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
831 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
832 ASSERT(dest_nr
== dest
->nr
);
834 /* try the current pending */
835 if (can_deliver(me
, dest
->current_pending
, dest
)) {
836 ASSERT(dest
->current_pending
->pending
& dest
->bit
);
837 vector
= deliver_pending(me
, opic
, dest
);
838 DTRACE(opic
, ("interrupt ack %d - entering %d (pending) - vector %d (%d), priority %d\n",
840 dest
->current_in_service
->nr
,
841 dest
->current_in_service
->vector
, vector
,
842 dest
->current_in_service
->priority
));
845 /* try for something else */
846 dest
->current_pending
= find_interrupt_for_dest(me
, opic
, dest
, pending_interrupt
);
847 if (can_deliver(me
, dest
->current_pending
, dest
)) {
848 vector
= deliver_pending(me
, opic
, dest
);
849 DTRACE(opic
, ("interrupt ack %d - entering %d (not pending) - vector %d (%d), priority %d\n",
851 dest
->current_in_service
->nr
,
852 dest
->current_in_service
->vector
, vector
,
853 dest
->current_in_service
->priority
));
856 dest
->current_pending
= NULL
;
857 vector
= opic
->spurious_vector
;
858 DTRACE(opic
, ("interrupt ack %d - spurious interrupt %d\n",
867 do_end_of_interrupt_register_N_write(device
*me
,
868 hw_opic_device
*opic
,
872 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
874 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
875 ASSERT(dest_nr
== dest
->nr
);
877 /* check the value written is zero */
879 DTRACE(opic
, ("eoi %d - ignoring nonzero value\n", dest
->nr
));
882 /* user doing wierd things? */
883 if (dest
->current_in_service
== NULL
) {
884 DTRACE(opic
, ("eoi %d - strange, no current interrupt\n", dest
->nr
));
888 /* an internal stuff up? */
889 if (!(dest
->current_in_service
->in_service
& dest
->bit
)) {
890 device_error(me
, "eoi %d - current interrupt not in service", dest
->nr
);
893 /* find what was probably the previous in service interrupt */
894 dest
->current_in_service
->in_service
&= ~dest
->bit
;
895 DTRACE(opic
, ("eoi %d - ending %d - priority %d, vector %d\n",
897 dest
->current_in_service
->nr
,
898 dest
->current_in_service
->priority
,
899 dest
->current_in_service
->vector
));
900 dest
->current_in_service
= find_interrupt_for_dest(me
, opic
, dest
, in_service_interrupt
);
901 if (dest
->current_in_service
!= NULL
)
902 DTRACE(opic
, ("eoi %d - resuming %d - priority %d, vector %d\n",
904 dest
->current_in_service
->nr
,
905 dest
->current_in_service
->priority
,
906 dest
->current_in_service
->vector
));
908 DTRACE(opic
, ("eoi %d - resuming none\n", dest
->nr
));
910 /* check to see if that shouldn't be interrupted */
911 dest
->current_pending
= find_interrupt_for_dest(me
, opic
, dest
, pending_interrupt
);
912 if (can_deliver(me
, dest
->current_pending
, dest
)) {
913 ASSERT(dest
->current_pending
->pending
& dest
->bit
);
914 assert_interrupt(me
, opic
, dest
);
917 dest
->current_pending
= NULL
;
923 decode_opic_address(device
*me
,
924 hw_opic_device
*opic
,
926 unsigned_word address
,
933 /* is the size valid? */
935 *type
= invalid_opic_register
;
940 /* try for a per-processor register within the interrupt delivery
942 if (space
== opic
->idu
.space
943 && address
>= (opic
->idu
.address
+ idu_per_processor_register_base
)
944 && address
< (opic
->idu
.address
+ idu_per_processor_register_base
945 + (sizeof_idu_per_processor_register_block
946 * opic
->nr_interrupt_destinations
))) {
947 unsigned_word block_offset
= (address
949 - idu_per_processor_register_base
);
950 unsigned_word offset
= block_offset
% sizeof_idu_per_processor_register_block
;
951 *index
= block_offset
/ sizeof_idu_per_processor_register_block
;
954 *type
= ipi_N_dispatch_register
;
958 *type
= ipi_N_dispatch_register
;
962 *type
= ipi_N_dispatch_register
;
966 *type
= ipi_N_dispatch_register
;
970 *type
= current_task_priority_register_N
;
973 *type
= interrupt_acknowledge_register_N
;
976 *type
= end_of_interrupt_register_N
;
979 *type
= invalid_opic_register
;
982 DTRACE(opic
, ("per-processor register %d:0x%lx - %s[%d]\n",
983 space
, (unsigned long)address
,
984 opic_register_name(*type
),
989 /* try for an interrupt source unit */
990 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
991 if (opic
->isu_block
[isb
].space
== space
992 && address
>= opic
->isu_block
[isb
].address
993 && address
< (opic
->isu_block
[isb
].address
+ opic
->isu_block
[isb
].size
)) {
994 unsigned_word block_offset
= address
- opic
->isu_block
[isb
].address
;
995 unsigned_word offset
= block_offset
% sizeof_isu_register_block
;
996 *index
= (opic
->isu_block
[isb
].int_number
997 + (block_offset
/ sizeof_isu_register_block
));
1000 *type
= interrupt_source_N_vector_priority_register
;
1003 *type
= interrupt_source_N_destination_register
;
1006 *type
= invalid_opic_register
;
1009 DTRACE(opic
, ("isu register %d:0x%lx - %s[%d]\n",
1010 space
, (unsigned long)address
,
1011 opic_register_name(*type
),
1017 /* try for a timer */
1018 if (space
== opic
->idu
.space
1019 && address
>= (opic
->idu
.address
+ idu_timer_base
)
1020 && address
< (opic
->idu
.address
+ idu_timer_base
1021 + opic
->nr_timer_interrupts
* sizeof_timer_register_block
)) {
1022 unsigned_word offset
= address
% sizeof_timer_register_block
;
1023 *index
= ((address
- opic
->idu
.address
- idu_timer_base
)
1024 / sizeof_timer_register_block
);
1027 *type
= timer_N_current_count_register
;
1030 *type
= timer_N_base_count_register
;
1033 *type
= timer_N_vector_priority_register
;
1036 *type
= timer_N_destination_register
;
1039 *type
= invalid_opic_register
;
1042 DTRACE(opic
, ("timer register %d:0x%lx - %s[%d]\n",
1043 space
, (unsigned long)address
,
1044 opic_register_name(*type
),
1049 /* finally some other misc global register */
1050 if (space
== opic
->idu
.space
1051 && address
>= opic
->idu
.address
1052 && address
< opic
->idu
.address
+ opic
->idu
.size
) {
1053 unsigned_word block_offset
= address
- opic
->idu
.address
;
1054 switch (block_offset
) {
1056 *type
= timer_frequency_reporting_register
;
1060 *type
= spurious_vector_register
;
1067 *type
= ipi_N_vector_priority_register
;
1068 *index
= (block_offset
- 0x010a0) / 16;
1071 *type
= processor_init_register
;
1075 *type
= vendor_identification_register
;
1079 *type
= global_configuration_register_N
;
1083 *type
= feature_reporting_register_N
;
1087 *type
= invalid_opic_register
;
1091 DTRACE(opic
, ("global register %d:0x%lx - %s[%d]\n",
1092 space
, (unsigned long)address
,
1093 opic_register_name(*type
),
1098 /* nothing matched */
1099 *type
= invalid_opic_register
;
1100 DTRACE(opic
, ("invalid register %d:0x%lx\n",
1101 space
, (unsigned long)address
));
1106 /* Processor init register:
1108 The bits in this register (one per processor) are directly wired to
1109 output "init" interrupt ports. */
1112 do_processor_init_register_read(device
*me
,
1113 hw_opic_device
*opic
)
1115 unsigned reg
= opic
->init
;
1116 DTRACE(opic
, ("processor init register - read 0x%lx\n",
1122 do_processor_init_register_write(device
*me
,
1123 hw_opic_device
*opic
,
1127 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
1128 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
1129 if ((reg
& dest
->bit
) != (opic
->init
& dest
->bit
)) {
1130 if (reg
& dest
->bit
) {
1131 DTRACE(opic
, ("processor init register - write 0x%lx - asserting init%d\n",
1133 opic
->init
|= dest
->bit
;
1134 device_interrupt_event(me
, dest
->init_port
, 1, NULL
, 0);
1137 DTRACE(opic
, ("processor init register - write 0x%lx - negating init%d\n",
1139 opic
->init
&= ~dest
->bit
;
1140 device_interrupt_event(me
, dest
->init_port
, 0, NULL
, 0);
1148 /* Interrupt Source Vector/Priority Register: */
1151 read_vector_priority_register(device
*me
,
1152 hw_opic_device
*opic
,
1153 opic_interrupt_source
*interrupt
,
1154 const char *reg_name
,
1159 reg
|= interrupt
->is_masked
;
1160 reg
|= (interrupt
->in_service
|| interrupt
->pending
1161 ? isu_active_bit
: 0); /* active */
1162 reg
|= interrupt
->is_multicast
;
1163 reg
|= interrupt
->is_positive_polarity
;
1164 reg
|= interrupt
->is_level_triggered
; /* sense? */
1165 reg
|= interrupt
->priority
<< isu_priority_shift
;
1166 reg
|= interrupt
->vector
;
1167 DTRACE(opic
, ("%s %d vector/priority register - read 0x%lx\n",
1168 reg_name
, reg_index
, (unsigned long)reg
));
1173 do_interrupt_source_N_vector_priority_register_read(device
*me
,
1174 hw_opic_device
*opic
,
1178 ASSERT(index
< opic
->nr_external_interrupts
);
1179 reg
= read_vector_priority_register(me
, opic
,
1180 &opic
->interrupt_source
[index
],
1181 "interrupt source", index
);
1186 write_vector_priority_register(device
*me
,
1187 hw_opic_device
*opic
,
1188 opic_interrupt_source
*interrupt
,
1190 const char *reg_name
,
1193 interrupt
->is_masked
= (reg
& isu_mask_bit
);
1194 interrupt
->is_multicast
= (reg
& isu_multicast_bit
);
1195 interrupt
->is_positive_polarity
= (reg
& isu_positive_polarity_bit
);
1196 interrupt
->is_level_triggered
= (reg
& isu_level_triggered_bit
);
1197 interrupt
->priority
= ((reg
>> isu_priority_shift
)
1198 % max_nr_task_priorities
);
1199 interrupt
->vector
= (reg
& isu_vector_bits
);
1200 DTRACE(opic
, ("%s %d vector/priority register - write 0x%lx - %s%s%s-polarity, %s-triggered, priority %ld vector %ld\n",
1204 interrupt
->is_masked
? "masked, " : "",
1205 interrupt
->is_multicast
? "multicast, " : "",
1206 interrupt
->is_positive_polarity
? "positive" : "negative",
1207 interrupt
->is_level_triggered
? "level" : "edge",
1208 (long)interrupt
->priority
,
1209 (long)interrupt
->vector
));
1213 do_interrupt_source_N_vector_priority_register_write(device
*me
,
1214 hw_opic_device
*opic
,
1218 ASSERT(index
< opic
->nr_external_interrupts
);
1219 reg
&= ~isu_multicast_bit
; /* disable multicast */
1220 write_vector_priority_register(me
, opic
,
1221 &opic
->interrupt_source
[index
],
1222 reg
, "interrupt source", index
);
1227 /* Interrupt Source Destination Register: */
1230 read_destination_register(device
*me
,
1231 hw_opic_device
*opic
,
1232 opic_interrupt_source
*interrupt
,
1233 const char *reg_name
,
1237 reg
= interrupt
->destination
;
1238 DTRACE(opic
, ("%s %d destination register - read 0x%lx\n",
1239 reg_name
, reg_index
, reg
));
1244 do_interrupt_source_N_destination_register_read(device
*me
,
1245 hw_opic_device
*opic
,
1249 ASSERT(index
< opic
->nr_external_interrupts
);
1250 reg
= read_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1251 "interrupt source", index
);
1256 write_destination_register(device
*me
,
1257 hw_opic_device
*opic
,
1258 opic_interrupt_source
*interrupt
,
1260 const char *reg_name
,
1263 reg
&= (1 << opic
->nr_interrupt_destinations
) - 1; /* mask out invalid */
1264 DTRACE(opic
, ("%s %d destination register - write 0x%x\n",
1265 reg_name
, reg_index
, reg
));
1266 interrupt
->destination
= reg
;
1270 do_interrupt_source_N_destination_register_write(device
*me
,
1271 hw_opic_device
*opic
,
1275 ASSERT(index
< opic
->nr_external_interrupts
);
1276 write_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1277 reg
, "interrupt source", index
);
1282 /* Spurious vector register: */
1285 do_spurious_vector_register_read(device
*me
,
1286 hw_opic_device
*opic
)
1288 unsigned long reg
= opic
->spurious_vector
;
1289 DTRACE(opic
, ("spurious vector register - read 0x%lx\n", reg
));
1294 do_spurious_vector_register_write(device
*me
,
1295 hw_opic_device
*opic
,
1298 reg
&= 0xff; /* mask off invalid */
1299 DTRACE(opic
, ("spurious vector register - write 0x%x\n", reg
));
1300 opic
->spurious_vector
= reg
;
1305 /* current task priority register: */
1308 do_current_task_priority_register_N_read(device
*me
,
1309 hw_opic_device
*opic
,
1312 opic_interrupt_destination
*interrupt_destination
= &opic
->interrupt_destination
[index
];
1314 ASSERT(index
>= 0 && index
< opic
->nr_interrupt_destinations
);
1315 reg
= interrupt_destination
->base_priority
;
1316 DTRACE(opic
, ("current task priority register %d - read 0x%x\n", index
, reg
));
1321 do_current_task_priority_register_N_write(device
*me
,
1322 hw_opic_device
*opic
,
1326 opic_interrupt_destination
*interrupt_destination
= &opic
->interrupt_destination
[index
];
1327 ASSERT(index
>= 0 && index
< opic
->nr_interrupt_destinations
);
1328 reg
%= max_nr_task_priorities
;
1329 DTRACE(opic
, ("current task priority register %d - write 0x%x\n", index
, reg
));
1330 interrupt_destination
->base_priority
= reg
;
1335 /* Timer Frequency Reporting Register: */
1338 do_timer_frequency_reporting_register_read(device
*me
,
1339 hw_opic_device
*opic
)
1342 reg
= opic
->timer_frequency
;
1343 DTRACE(opic
, ("timer frequency reporting register - read 0x%x\n", reg
));
1348 do_timer_frequency_reporting_register_write(device
*me
,
1349 hw_opic_device
*opic
,
1352 DTRACE(opic
, ("timer frequency reporting register - write 0x%x\n", reg
));
1353 opic
->timer_frequency
= reg
;
1357 /* timer registers: */
1360 do_timer_N_current_count_register_read(device
*me
,
1361 hw_opic_device
*opic
,
1364 opic_timer
*timer
= &opic
->timer
[index
];
1366 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1367 if (timer
->inhibited
)
1368 reg
= timer
->count
; /* stalled value */
1370 reg
= timer
->count
- device_event_queue_time(me
); /* time remaining */
1371 DTRACE(opic
, ("timer %d current count register - read 0x%x\n", index
, reg
));
1377 do_timer_N_base_count_register_read(device
*me
,
1378 hw_opic_device
*opic
,
1381 opic_timer
*timer
= &opic
->timer
[index
];
1383 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1384 reg
= timer
->base_count
;
1385 DTRACE(opic
, ("timer %d base count register - read 0x%x\n", index
, reg
));
1391 timer_event(void *data
)
1393 opic_timer
*timer
= data
;
1394 device
*me
= timer
->me
;
1395 if (timer
->inhibited
)
1396 device_error(timer
->me
, "internal-error - timer event occured when timer %d inhibited",
1398 handle_interrupt(timer
->me
, timer
->opic
, timer
->interrupt_source
, 1);
1399 timer
->timeout_event
= device_event_queue_schedule(me
, timer
->base_count
,
1400 timer_event
, timer
);
1401 DTRACE(opic
, ("timer %d - interrupt at %ld, next at %d\n",
1402 timer
->nr
, (long)device_event_queue_time(me
), timer
->base_count
));
1407 do_timer_N_base_count_register_write(device
*me
,
1408 hw_opic_device
*opic
,
1412 opic_timer
*timer
= &opic
->timer
[index
];
1414 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1415 inhibit
= reg
& 0x80000000;
1416 if (timer
->inhibited
&& !inhibit
) {
1417 timer
->inhibited
= 0;
1418 if (timer
->timeout_event
!= NULL
)
1419 device_event_queue_deschedule(me
, timer
->timeout_event
);
1420 timer
->count
= device_event_queue_time(me
) + reg
;
1421 timer
->base_count
= reg
;
1422 timer
->timeout_event
= device_event_queue_schedule(me
, timer
->base_count
,
1423 timer_event
, (void*)timer
);
1424 DTRACE(opic
, ("timer %d base count register - write 0x%x - timer started\n",
1427 else if (!timer
->inhibited
&& inhibit
) {
1428 if (timer
->timeout_event
!= NULL
)
1429 device_event_queue_deschedule(me
, timer
->timeout_event
);
1430 timer
->count
= timer
->count
- device_event_queue_time(me
);
1431 timer
->inhibited
= 1;
1432 timer
->base_count
= reg
;
1433 DTRACE(opic
, ("timer %d base count register - write 0x%x - timer stopped\n",
1437 ASSERT((timer
->inhibited
&& inhibit
) || (!timer
->inhibited
&& !inhibit
));
1438 DTRACE(opic
, ("timer %d base count register - write 0x%x\n", index
, reg
));
1439 timer
->base_count
= reg
;
1445 do_timer_N_vector_priority_register_read(device
*me
,
1446 hw_opic_device
*opic
,
1450 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1451 reg
= read_vector_priority_register(me
, opic
,
1452 &opic
->timer_interrupt_source
[index
],
1458 do_timer_N_vector_priority_register_write(device
*me
,
1459 hw_opic_device
*opic
,
1463 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1464 reg
&= ~isu_level_triggered_bit
; /* force edge trigger */
1465 reg
|= isu_positive_polarity_bit
; /* force rising (positive) edge */
1466 reg
|= isu_multicast_bit
; /* force multicast */
1467 write_vector_priority_register(me
, opic
,
1468 &opic
->timer_interrupt_source
[index
],
1469 reg
, "timer", index
);
1474 do_timer_N_destination_register_read(device
*me
,
1475 hw_opic_device
*opic
,
1479 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1480 reg
= read_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1486 do_timer_N_destination_register_write(device
*me
,
1487 hw_opic_device
*opic
,
1491 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1492 write_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1493 reg
, "timer", index
);
1500 do_ipi_N_vector_priority_register_read(device
*me
,
1501 hw_opic_device
*opic
,
1505 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1506 reg
= read_vector_priority_register(me
, opic
,
1507 &opic
->interprocessor_interrupt_source
[index
],
1513 do_ipi_N_vector_priority_register_write(device
*me
,
1514 hw_opic_device
*opic
,
1518 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1519 reg
&= ~isu_level_triggered_bit
; /* force edge trigger */
1520 reg
|= isu_positive_polarity_bit
; /* force rising (positive) edge */
1521 reg
|= isu_multicast_bit
; /* force a multicast source */
1522 write_vector_priority_register(me
, opic
,
1523 &opic
->interprocessor_interrupt_source
[index
],
1528 do_ipi_N_dispatch_register_write(device
*me
,
1529 hw_opic_device
*opic
,
1533 opic_interrupt_source
*source
= &opic
->interprocessor_interrupt_source
[index
];
1534 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1535 DTRACE(opic
, ("ipi %d interrupt dispatch register - write 0x%x\n", index
, reg
));
1536 source
->destination
= reg
;
1537 handle_interrupt(me
, opic
, source
, 1);
1541 /* vendor and other global registers */
1544 do_vendor_identification_register_read(device
*me
,
1545 hw_opic_device
*opic
)
1548 reg
= opic
->vendor_identification
;
1549 DTRACE(opic
, ("vendor identification register - read 0x%x\n", reg
));
1554 do_feature_reporting_register_N_read(device
*me
,
1555 hw_opic_device
*opic
,
1562 reg
|= (opic
->nr_external_interrupts
<< 16);
1563 reg
|= (opic
->nr_interrupt_destinations
<< 8);
1564 reg
|= (2/*version 1.2*/);
1567 DTRACE(opic
, ("feature reporting register %d - read 0x%x\n", index
, reg
));
1572 do_global_configuration_register_N_read(device
*me
,
1573 hw_opic_device
*opic
,
1580 reg
|= gcr0_8259_bit
; /* hardwire 8259 disabled */
1583 DTRACE(opic
, ("global configuration register %d - read 0x%x\n", index
, reg
));
1588 do_global_configuration_register_N_write(device
*me
,
1589 hw_opic_device
*opic
,
1594 if (reg
& gcr0_reset_bit
) {
1595 DTRACE(opic
, ("global configuration register %d - write 0x%x - reseting opic\n", index
, reg
));
1596 hw_opic_init_data(me
);
1598 if (!(reg
& gcr0_8259_bit
)) {
1599 DTRACE(opic
, ("global configuration register %d - write 0x%x - ignoring 8259 enable\n", index
, reg
));
1605 /* register read-write */
1608 hw_opic_io_read_buffer(device
*me
,
1616 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1619 decode_opic_address(me
, opic
, space
, addr
, nr_bytes
, &type
, &index
);
1620 if (type
== invalid_opic_register
) {
1621 device_error(me
, "invalid opic read access to %d:0x%lx (%d bytes)",
1622 space
, (unsigned long)addr
, nr_bytes
);
1627 case processor_init_register
:
1628 reg
= do_processor_init_register_read(me
, opic
);
1630 case interrupt_source_N_vector_priority_register
:
1631 reg
= do_interrupt_source_N_vector_priority_register_read(me
, opic
, index
);
1633 case interrupt_source_N_destination_register
:
1634 reg
= do_interrupt_source_N_destination_register_read(me
, opic
, index
);
1636 case interrupt_acknowledge_register_N
:
1637 reg
= do_interrupt_acknowledge_register_N_read(me
, opic
, index
);
1639 case spurious_vector_register
:
1640 reg
= do_spurious_vector_register_read(me
, opic
);
1642 case current_task_priority_register_N
:
1643 reg
= do_current_task_priority_register_N_read(me
, opic
, index
);
1645 case timer_frequency_reporting_register
:
1646 reg
= do_timer_frequency_reporting_register_read(me
, opic
);
1648 case timer_N_current_count_register
:
1649 reg
= do_timer_N_current_count_register_read(me
, opic
, index
);
1651 case timer_N_base_count_register
:
1652 reg
= do_timer_N_base_count_register_read(me
, opic
, index
);
1654 case timer_N_vector_priority_register
:
1655 reg
= do_timer_N_vector_priority_register_read(me
, opic
, index
);
1657 case timer_N_destination_register
:
1658 reg
= do_timer_N_destination_register_read(me
, opic
, index
);
1660 case ipi_N_vector_priority_register
:
1661 reg
= do_ipi_N_vector_priority_register_read(me
, opic
, index
);
1663 case feature_reporting_register_N
:
1664 reg
= do_feature_reporting_register_N_read(me
, opic
, index
);
1666 case global_configuration_register_N
:
1667 reg
= do_global_configuration_register_N_read(me
, opic
, index
);
1669 case vendor_identification_register
:
1670 reg
= do_vendor_identification_register_read(me
, opic
);
1674 device_error(me
, "unimplemented read of register %s[%d]",
1675 opic_register_name(type
), index
);
1677 *(unsigned_4
*)dest
= H2LE_4(reg
);
1684 hw_opic_io_write_buffer(device
*me
,
1692 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1695 decode_opic_address(me
, opic
, space
, addr
, nr_bytes
, &type
, &index
);
1696 if (type
== invalid_opic_register
) {
1697 device_error(me
, "invalid opic write access to %d:0x%lx (%d bytes)",
1698 space
, (unsigned long)addr
, nr_bytes
);
1701 unsigned reg
= LE2H_4(*(unsigned_4
*)source
);
1703 case processor_init_register
:
1704 do_processor_init_register_write(me
, opic
, reg
);
1706 case interrupt_source_N_vector_priority_register
:
1707 do_interrupt_source_N_vector_priority_register_write(me
, opic
, index
, reg
);
1709 case interrupt_source_N_destination_register
:
1710 do_interrupt_source_N_destination_register_write(me
, opic
, index
, reg
);
1712 case end_of_interrupt_register_N
:
1713 do_end_of_interrupt_register_N_write(me
, opic
, index
, reg
);
1715 case spurious_vector_register
:
1716 do_spurious_vector_register_write(me
, opic
, reg
);
1718 case current_task_priority_register_N
:
1719 do_current_task_priority_register_N_write(me
, opic
, index
, reg
);
1721 case timer_frequency_reporting_register
:
1722 do_timer_frequency_reporting_register_write(me
, opic
, reg
);
1724 case timer_N_base_count_register
:
1725 do_timer_N_base_count_register_write(me
, opic
, index
, reg
);
1727 case timer_N_vector_priority_register
:
1728 do_timer_N_vector_priority_register_write(me
, opic
, index
, reg
);
1730 case timer_N_destination_register
:
1731 do_timer_N_destination_register_write(me
, opic
, index
, reg
);
1733 case ipi_N_dispatch_register
:
1734 do_ipi_N_dispatch_register_write(me
, opic
, index
, reg
);
1736 case ipi_N_vector_priority_register
:
1737 do_ipi_N_vector_priority_register_write(me
, opic
, index
, reg
);
1739 case global_configuration_register_N
:
1740 do_global_configuration_register_N_write(me
, opic
, index
, reg
);
1743 device_error(me
, "unimplemented write to register %s[%d]",
1744 opic_register_name(type
), index
);
1752 hw_opic_interrupt_event(device
*me
,
1760 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1765 /* find the corresponding internal input port */
1766 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
1767 if (my_port
>= opic
->isu_block
[isb
].int_number
1768 && my_port
< opic
->isu_block
[isb
].int_number
+ opic
->isu_block
[isb
].range
) {
1769 src_nr
+= my_port
- opic
->isu_block
[isb
].int_number
;
1773 src_nr
+= opic
->isu_block
[isb
].range
;
1775 if (isb
== opic
->nr_isu_blocks
)
1776 device_error(me
, "interrupt %d out of range", my_port
);
1777 DTRACE(opic
, ("external-interrupt %d, internal %d, level %d\n",
1778 my_port
, src_nr
, level
));
1781 ASSERT(src_nr
>= 0 && src_nr
< opic
->nr_external_interrupts
);
1782 handle_interrupt(me
, opic
, &opic
->external_interrupt_source
[src_nr
], level
);
1786 static const device_interrupt_port_descriptor hw_opic_interrupt_ports
[] = {
1787 { "irq", 0, max_nr_interrupt_sources
, input_port
, },
1788 { "intr", 0, max_nr_interrupt_destinations
, output_port
, },
1789 { "init", max_nr_interrupt_destinations
, max_nr_interrupt_destinations
, output_port
, },
1794 static device_callbacks
const hw_opic_callbacks
= {
1795 { generic_device_init_address
,
1796 hw_opic_init_data
},
1797 { NULL
, }, /* address */
1798 { hw_opic_io_read_buffer
,
1799 hw_opic_io_write_buffer
}, /* IO */
1800 { NULL
, }, /* DMA */
1801 { hw_opic_interrupt_event
, NULL
, hw_opic_interrupt_ports
}, /* interrupt */
1802 { NULL
, }, /* unit */
1803 NULL
, /* instance */
1807 hw_opic_create(const char *name
,
1808 const device_unit
*unit_address
,
1811 hw_opic_device
*opic
= ZALLOC(hw_opic_device
);
1817 const device_descriptor hw_opic_device_descriptor
[] = {
1818 { "opic", hw_opic_create
, &hw_opic_callbacks
},
1822 #endif /* _HW_OPIC_C_ */