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 2 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, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "device_table.h"
39 opic - Open Programmable Interrupt Controller (OpenPIC)
45 This device implements the core of the OpenPIC interrupt controller
46 as described in the OpenPIC specification 1.2 and other related
51 o Up to 2048 external interrupt sources
53 o The four count down timers
55 o The four interprocessor multicast interrupts
57 o multiprocessor support
59 o Full tracing to assist help debugging
61 o Support for all variations of edge/level x high/low polarity.
68 reg = <address> <size> ... (required)
70 Determine where the device lives in the parents address space. The
71 first <<address>> <<size>> pair specifies the address of the
72 interrupt destination unit (which might contain an interrupt source
73 unit) while successive reg entries specify additional interrupt
76 Note that for an <<opic>> device attached to a <<pci>> bus, the
77 first <<reg>> entry may need to be ignored it will be the address
78 of the devices configuration registers.
81 interrupt-ranges = <int-number> <range> ... (required)
83 A list of pairs. Each pair corresponds to a block of interrupt
84 source units (the address of which being specified by the
85 corresponding reg tupple). <<int-number>> is the number of the
86 first interrupt in the block while <<range>> is the number of
87 interrupts in the block.
90 timer-frequency = <integer> (optional)
92 If present, specifies the default value of the timer frequency
93 reporting register. By default a value of 1 HZ is used. The value
94 is arbitrary, the timers are always updated once per machine cycle.
97 vendor-identification = <integer> (optional)
99 If present, specifies the value to be returned when the vendor
100 identification register is read.
106 See the test suite directory:
113 For an OPIC controller attached to a PCI bus, it is not clear what
114 the value of the <<reg>> and <<interrupt-ranges>> properties should
115 be. In particular, the PCI firmware bindings require the first
116 value of the <<reg>> property to specify the devices configuration
117 address while the OpenPIC bindings require that same entry to
118 specify the address of the Interrupt Delivery Unit. This
119 implementation checks for and, if present, ignores any
120 configuration address (and its corresponding <<interrupt-ranges>>
123 The OpenPIC specification requires the controller to be fair when
124 distributing interrupts between processors. At present the
125 algorithm used isn't fair. It is biased towards processor zero.
127 The OpenPIC specification includes a 8259 pass through mode. This
134 PowerPC Multiprocessor Interrupt Controller (MPIC), January 19,
135 1996. Available from IBM.
138 The Open Programmable Interrupt Controller (PIC) Register Interface
139 Specification Revision 1.2. Issue Date: Opctober 1995. Available
140 somewhere on AMD's web page (http://www.amd.com/)
143 PowerPC Microprocessor Common Hardware Reference Platform (CHRP)
144 System bindings to: IEEE Std 1275-1994 Standard for Boot
145 (Initialization, Configuration) Firmware. Revision 1.2b (INTERIM
146 DRAFT). April 22, 1996. Available on the Open Firmware web site
147 http://playground.sun.com/p1275/.
155 typedef struct _hw_opic_device hw_opic_device
;
161 max_nr_interrupt_sources
= 2048,
162 max_nr_interrupt_destinations
= 32,
163 max_nr_task_priorities
= 16,
172 /* global configuration register */
175 gcr0_8259_bit
= 0x20000000,
176 gcr0_reset_bit
= 0x80000000,
180 /* offsets and sizes */
183 idu_isu_base
= 0x10000,
184 sizeof_isu_register_block
= 32,
185 idu_per_processor_register_base
= 0x20000,
186 sizeof_idu_per_processor_register_block
= 0x1000,
187 idu_timer_base
= 0x01100,
188 sizeof_timer_register_block
= 0x00040,
192 /* Interrupt sources */
195 isu_mask_bit
= 0x80000000,
196 isu_active_bit
= 0x40000000,
197 isu_multicast_bit
= 0x20000000,
198 isu_positive_polarity_bit
= 0x00800000,
199 isu_level_triggered_bit
= 0x00400000,
200 isu_priority_shift
= 16,
201 isu_vector_bits
= 0x000000ff,
205 typedef struct _opic_interrupt_source
{
206 unsigned is_masked
; /* left in place */
207 unsigned is_multicast
; /* left in place */
208 unsigned is_positive_polarity
; /* left in place */
209 unsigned is_level_triggered
; /* left in place */
214 unsigned destination
;
217 } opic_interrupt_source
;
220 /* interrupt destinations (normally processors) */
222 typedef struct _opic_interrupt_destination
{
224 unsigned base_priority
;
225 opic_interrupt_source
*current_pending
;
226 opic_interrupt_source
*current_in_service
;
230 } opic_interrupt_destination
;
233 /* address map descriptors */
235 typedef struct _opic_isu_block
{ /* interrupt source unit block */
237 unsigned_word address
;
239 unsigned_cell int_number
;
245 typedef struct _opic_idu
{ /* interrupt delivery unit */
248 unsigned_word address
;
254 invalid_opic_register
,
255 /* interrupt source */
256 interrupt_source_N_destination_register
,
257 interrupt_source_N_vector_priority_register
,
259 timer_N_destination_register
,
260 timer_N_vector_priority_register
,
261 timer_N_base_count_register
,
262 timer_N_current_count_register
,
263 timer_frequency_reporting_register
,
264 /* inter-processor interrupts */
265 ipi_N_vector_priority_register
,
266 ipi_N_dispatch_register
,
267 /* global configuration */
268 spurious_vector_register
,
269 processor_init_register
,
270 vendor_identification_register
,
271 global_configuration_register_N
,
272 feature_reporting_register_N
,
274 end_of_interrupt_register_N
,
275 interrupt_acknowledge_register_N
,
276 current_task_priority_register_N
,
280 opic_register_name(opic_register type
)
283 case invalid_opic_register
: return "invalid_opic_register";
284 case interrupt_source_N_destination_register
: return "interrupt_source_N_destination_register";
285 case interrupt_source_N_vector_priority_register
: return "interrupt_source_N_vector_priority_register";
286 case timer_N_destination_register
: return "timer_N_destination_register";
287 case timer_N_vector_priority_register
: return "timer_N_vector_priority_register";
288 case timer_N_base_count_register
: return "timer_N_base_count_register";
289 case timer_N_current_count_register
: return "timer_N_current_count_register";
290 case timer_frequency_reporting_register
: return "timer_frequency_reporting_register";
291 case ipi_N_vector_priority_register
: return "ipi_N_vector_priority_register";
292 case ipi_N_dispatch_register
: return "ipi_N_dispatch_register";
293 case spurious_vector_register
: return "spurious_vector_register";
294 case processor_init_register
: return "processor_init_register";
295 case vendor_identification_register
: return "vendor_identification_register";
296 case global_configuration_register_N
: return "global_configuration_register_N";
297 case feature_reporting_register_N
: return "feature_reporting_register_N";
298 case end_of_interrupt_register_N
: return "end_of_interrupt_register_N";
299 case interrupt_acknowledge_register_N
: return "interrupt_acknowledge_register_N";
300 case current_task_priority_register_N
: return "current_task_priority_register_N";
309 typedef struct _opic_timer
{
311 device
*me
; /* find my way home */
312 hw_opic_device
*opic
; /* ditto */
315 signed64 count
; /* *ONLY* if inhibited */
316 event_entry_tag timeout_event
;
317 opic_interrupt_source
*interrupt_source
;
323 struct _hw_opic_device
{
326 unsigned vendor_identification
;
328 /* interrupt destinations - processors */
329 int nr_interrupt_destinations
;
330 opic_interrupt_destination
*interrupt_destination
;
331 unsigned sizeof_interrupt_destination
;
333 /* bogus interrupts */
336 /* interrupt sources - external interrupt source units + extra internal ones */
337 int nr_interrupt_sources
;
338 opic_interrupt_source
*interrupt_source
;
339 unsigned sizeof_interrupt_source
;
341 /* external interrupts */
342 int nr_external_interrupts
;
343 opic_interrupt_source
*external_interrupt_source
;
345 /* inter-processor-interrupts */
346 int nr_interprocessor_interrupts
;
347 opic_interrupt_source
*interprocessor_interrupt_source
;
350 int nr_timer_interrupts
;
352 unsigned sizeof_timer
;
353 opic_interrupt_source
*timer_interrupt_source
;
354 unsigned timer_frequency
;
362 opic_isu_block
*isu_block
;
367 hw_opic_init_data(device
*me
)
369 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
375 /* determine the first valid reg property entry (there could be
376 leading reg entries with invalid (zero) size fields) and the
377 number of isu entries found in the reg property. */
381 reg_property_spec unit
;
383 unsigned_word attach_address
;
384 unsigned attach_size
;
385 if (!device_find_reg_array_property(me
, "reg", idu_reg
+ nr_isu_blocks
,
388 if (nr_isu_blocks
> 0
389 || (device_address_to_attach_address(device_parent(me
), &unit
.address
,
390 &attach_space
, &attach_address
,
392 && device_size_to_attach_size(device_parent(me
), &unit
.size
,
395 /* we count any thing once we've found one valid address/size pair */
403 /* determine the number and location of the multiple interrupt
404 source units and the single interrupt delivery unit */
405 if (opic
->isu_block
== NULL
) {
407 opic
->nr_isu_blocks
= nr_isu_blocks
;
408 opic
->isu_block
= zalloc(sizeof(opic_isu_block
) * opic
->nr_isu_blocks
);
411 while (isb
< opic
->nr_isu_blocks
) {
412 reg_property_spec reg
;
413 if (!device_find_reg_array_property(me
, "reg", reg_nr
, ®
))
414 device_error(me
, "reg property missing entry number %d", reg_nr
);
415 opic
->isu_block
[isb
].reg
= reg_nr
;
416 if (!device_address_to_attach_address(device_parent(me
), ®
.address
,
417 &opic
->isu_block
[isb
].space
,
418 &opic
->isu_block
[isb
].address
,
420 || !device_size_to_attach_size(device_parent(me
), ®
.size
,
421 &opic
->isu_block
[isb
].size
,
423 device_error(me
, "reg property entry %d invalid", reg_nr
);
425 if (!device_find_integer_array_property(me
, "interrupt-ranges",
427 &opic
->isu_block
[isb
].int_number
)
428 || !device_find_integer_array_property(me
, "interrupt-ranges",
430 &opic
->isu_block
[isb
].range
))
431 device_error(me
, "missing or invalid interrupt-ranges property entry %d", reg_nr
);
432 /* first reg entry specifies the address of both the IDU and the
433 first set of ISU registers, adjust things accordingly */
434 if (reg_nr
== idu_reg
) {
435 opic
->idu
.reg
= opic
->isu_block
[isb
].reg
;
436 opic
->idu
.space
= opic
->isu_block
[isb
].space
;
437 opic
->idu
.address
= opic
->isu_block
[isb
].address
;
438 opic
->idu
.size
= opic
->isu_block
[isb
].size
;
439 opic
->isu_block
[isb
].address
+= idu_isu_base
;
440 opic
->isu_block
[isb
].size
= opic
->isu_block
[isb
].range
* (16 + 16);
442 /* was this a valid reg entry? */
443 if (opic
->isu_block
[isb
].range
== 0) {
444 opic
->nr_isu_blocks
-= 1;
447 opic
->nr_external_interrupts
+= opic
->isu_block
[isb
].range
;
453 DTRACE(opic
, ("interrupt source unit block - effective number of blocks %d\n",
454 (int)opic
->nr_isu_blocks
));
457 /* the number of other interrupts */
458 opic
->nr_interprocessor_interrupts
= 4;
459 opic
->nr_timer_interrupts
= 4;
462 /* create space for the interrupt source registers */
463 if (opic
->interrupt_source
!= NULL
) {
464 memset(opic
->interrupt_source
, 0, opic
->sizeof_interrupt_source
);
467 opic
->nr_interrupt_sources
= (opic
->nr_external_interrupts
468 + opic
->nr_interprocessor_interrupts
469 + opic
->nr_timer_interrupts
);
470 if (opic
->nr_interrupt_sources
> max_nr_interrupt_sources
)
471 device_error(me
, "number of interrupt sources exceeded");
472 opic
->sizeof_interrupt_source
= (sizeof(opic_interrupt_source
)
473 * opic
->nr_interrupt_sources
);
474 opic
->interrupt_source
= zalloc(opic
->sizeof_interrupt_source
);
475 opic
->external_interrupt_source
= opic
->interrupt_source
;
476 opic
->interprocessor_interrupt_source
= (opic
->external_interrupt_source
477 + opic
->nr_external_interrupts
);
478 opic
->timer_interrupt_source
= (opic
->interprocessor_interrupt_source
479 + opic
->nr_interprocessor_interrupts
);
481 for (i
= 0; i
< opic
->nr_interrupt_sources
; i
++) {
482 opic_interrupt_source
*source
= &opic
->interrupt_source
[i
];
484 source
->is_masked
= isu_mask_bit
;
486 DTRACE(opic
, ("interrupt sources - external %d, timer %d, ipi %d, total %d\n",
487 opic
->nr_external_interrupts
,
488 opic
->nr_timer_interrupts
,
489 opic
->nr_interprocessor_interrupts
,
490 opic
->nr_interrupt_sources
));
493 /* timers or interprocessor interrupts */
494 if (opic
->timer
!= NULL
)
495 memset(opic
->timer
, 0, opic
->sizeof_timer
);
497 opic
->nr_timer_interrupts
= 4;
498 opic
->sizeof_timer
= sizeof(opic_timer
) * opic
->nr_timer_interrupts
;
499 opic
->timer
= zalloc(opic
->sizeof_timer
);
501 for (i
= 0; i
< opic
->nr_timer_interrupts
; i
++) {
502 opic_timer
*timer
= &opic
->timer
[i
];
506 timer
->inhibited
= 1;
507 timer
->interrupt_source
= &opic
->timer_interrupt_source
[i
];
509 if (device_find_property(me
, "timer-frequency"))
510 opic
->timer_frequency
= device_find_integer_property(me
, "timer-frequency");
512 opic
->timer_frequency
= 1;
515 /* create space for the interrupt destination registers */
516 if (opic
->interrupt_destination
!= NULL
) {
517 memset(opic
->interrupt_destination
, 0, opic
->sizeof_interrupt_destination
);
520 opic
->nr_interrupt_destinations
= tree_find_integer_property(me
, "/openprom/options/smp");
521 opic
->sizeof_interrupt_destination
= (sizeof(opic_interrupt_destination
)
522 * opic
->nr_interrupt_destinations
);
523 opic
->interrupt_destination
= zalloc(opic
->sizeof_interrupt_destination
);
524 if (opic
->nr_interrupt_destinations
> max_nr_interrupt_destinations
)
525 device_error(me
, "number of interrupt destinations exceeded");
527 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
528 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
529 dest
->bit
= (1 << i
);
531 dest
->init_port
= (device_interrupt_decode(me
, "init0", output_port
)
533 dest
->intr_port
= (device_interrupt_decode(me
, "intr0", output_port
)
535 dest
->base_priority
= max_nr_task_priorities
- 1;
537 DTRACE(opic
, ("interrupt destinations - total %d\n",
538 (int)opic
->nr_interrupt_destinations
));
541 /* verify and print out the ISU's */
542 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
543 unsigned correct_size
;
544 if ((opic
->isu_block
[isb
].address
% opic_alignment
) != 0)
545 device_error(me
, "interrupt source unit %d address not aligned to %d byte boundary",
546 isb
, opic_alignment
);
547 correct_size
= opic
->isu_block
[isb
].range
* sizeof_isu_register_block
;
548 if (opic
->isu_block
[isb
].size
!= correct_size
)
549 device_error(me
, "interrupt source unit %d (reg %d) has an incorrect size, should be 0x%x",
550 isb
, opic
->isu_block
[isb
].reg
, correct_size
);
551 DTRACE(opic
, ("interrupt source unit block %ld - address %d:0x%lx, size 0x%lx, int-number %ld, range %ld\n",
553 (int)opic
->isu_block
[isb
].space
,
554 (unsigned long)opic
->isu_block
[isb
].address
,
555 (unsigned long)opic
->isu_block
[isb
].size
,
556 (long)opic
->isu_block
[isb
].int_number
,
557 (long)opic
->isu_block
[isb
].range
));
561 /* verify and print out the IDU */
563 unsigned correct_size
;
564 unsigned alternate_size
;
565 if ((opic
->idu
.address
% opic_alignment
) != 0)
566 device_error(me
, "interrupt delivery unit not aligned to %d byte boundary",
568 correct_size
= (idu_per_processor_register_base
569 + (sizeof_idu_per_processor_register_block
570 * opic
->nr_interrupt_destinations
));
571 alternate_size
= (idu_per_processor_register_base
572 + (sizeof_idu_per_processor_register_block
573 * max_nr_interrupt_destinations
));
574 if (opic
->idu
.size
!= correct_size
575 && opic
->idu
.size
!= alternate_size
)
576 device_error(me
, "interrupt delivery unit has incorrect size, should be 0x%x or 0x%x",
577 correct_size
, alternate_size
);
578 DTRACE(opic
, ("interrupt delivery unit - address %d:0x%lx, size 0x%lx\n",
579 (int)opic
->idu
.space
,
580 (unsigned long)opic
->idu
.address
,
581 (unsigned long)opic
->idu
.size
));
584 /* initialize the init interrupts */
589 if (device_find_property(me
, "vendor-identification") != NULL
)
590 opic
->vendor_identification
= device_find_integer_property(me
, "vendor-identification");
592 opic
->vendor_identification
= 0;
595 opic
->spurious_vector
= 0xff;
600 /* interrupt related actions */
603 assert_interrupt(device
*me
,
604 hw_opic_device
*opic
,
605 opic_interrupt_destination
*dest
)
607 ASSERT(dest
>= opic
->interrupt_destination
);
608 ASSERT(dest
< opic
->interrupt_destination
+ opic
->nr_interrupt_destinations
);
609 DTRACE(opic
, ("assert interrupt - intr port %d\n", dest
->intr_port
));
610 device_interrupt_event(me
, dest
->intr_port
, 1, NULL
, 0);
615 negate_interrupt(device
*me
,
616 hw_opic_device
*opic
,
617 opic_interrupt_destination
*dest
)
619 ASSERT(dest
>= opic
->interrupt_destination
);
620 ASSERT(dest
< opic
->interrupt_destination
+ opic
->nr_interrupt_destinations
);
621 DTRACE(opic
, ("negate interrupt - intr port %d\n", dest
->intr_port
));
622 device_interrupt_event(me
, dest
->intr_port
, 0, NULL
, 0);
627 can_deliver(device
*me
,
628 opic_interrupt_source
*source
,
629 opic_interrupt_destination
*dest
)
631 return (source
!= NULL
&& dest
!= NULL
632 && source
->priority
> dest
->base_priority
633 && (dest
->current_in_service
== NULL
634 || source
->priority
> dest
->current_in_service
->priority
));
639 deliver_pending(device
*me
,
640 hw_opic_device
*opic
,
641 opic_interrupt_destination
*dest
)
643 ASSERT(can_deliver(me
, dest
->current_pending
, dest
));
644 dest
->current_in_service
= dest
->current_pending
;
645 dest
->current_in_service
->in_service
|= dest
->bit
;
646 if (!dest
->current_pending
->is_level_triggered
) {
647 if (dest
->current_pending
->is_multicast
)
648 dest
->current_pending
->pending
&= ~dest
->bit
;
650 dest
->current_pending
->pending
= 0;
652 dest
->current_pending
= NULL
;
653 negate_interrupt(me
, opic
, dest
);
654 return dest
->current_in_service
->vector
;
660 in_service_interrupt
,
663 static opic_interrupt_source
*
664 find_interrupt_for_dest(device
*me
,
665 hw_opic_device
*opic
,
666 opic_interrupt_destination
*dest
,
667 interrupt_class
class)
670 opic_interrupt_source
*pending
= NULL
;
671 for (i
= 0; i
< opic
->nr_interrupt_sources
; i
++) {
672 opic_interrupt_source
*src
= &opic
->interrupt_source
[i
];
673 /* is this a potential hit? */
675 case in_service_interrupt
:
676 if ((src
->in_service
& dest
->bit
) == 0)
679 case pending_interrupt
:
680 if ((src
->pending
& dest
->bit
) == 0)
684 /* see if it is the highest priority */
687 else if (src
->priority
> pending
->priority
)
694 static opic_interrupt_destination
*
695 find_lowest_dest(device
*me
,
696 hw_opic_device
*opic
,
697 opic_interrupt_source
*src
)
700 opic_interrupt_destination
*lowest
= NULL
;
701 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
702 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
703 if (src
->destination
& dest
->bit
) {
704 if (dest
->base_priority
< src
->priority
) {
707 else if (lowest
->base_priority
> dest
->base_priority
)
709 else if (lowest
->current_in_service
!= NULL
710 && dest
->current_in_service
== NULL
)
711 lowest
= dest
; /* not doing anything */
712 else if (lowest
->current_in_service
!= NULL
713 && dest
->current_in_service
!= NULL
714 && (lowest
->current_in_service
->priority
715 > dest
->current_in_service
->priority
))
716 lowest
= dest
; /* less urgent */
717 /* FIXME - need to be more fair */
726 handle_interrupt(device
*me
,
727 hw_opic_device
*opic
,
728 opic_interrupt_source
*src
,
731 if (src
->is_masked
) {
732 DTRACE(opic
, ("interrupt %d - ignore masked\n", src
->nr
));
734 else if (src
->is_multicast
) {
735 /* always try to deliver multicast interrupts - just easier */
737 ASSERT(!src
->is_level_triggered
);
738 ASSERT(src
->is_positive_polarity
);
740 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
741 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
742 if (src
->destination
& dest
->bit
) {
743 if (src
->pending
& dest
->bit
) {
744 DTRACE(opic
, ("interrupt %d - multicast still pending to %d\n",
747 else if (can_deliver(me
, src
, dest
)) {
748 dest
->current_pending
= src
;
749 src
->pending
|= dest
->bit
;
750 assert_interrupt(me
, opic
, dest
);
751 DTRACE(opic
, ("interrupt %d - multicast to %d\n",
755 src
->pending
|= dest
->bit
;
756 DTRACE(opic
, ("interrupt %d - multicast pending to %d\n",
762 else if (src
->is_level_triggered
763 && src
->is_positive_polarity
766 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active high)\n",
769 DTRACE(opic
, ("interrupt %d - ignore low level (active high)\n",
771 ASSERT(!src
->is_multicast
);
774 else if (src
->is_level_triggered
775 && !src
->is_positive_polarity
778 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active low)\n",
781 DTRACE(opic
, ("interrupt %d - ignore high level (active low)\n",
784 ASSERT(!src
->is_multicast
);
787 else if (!src
->is_level_triggered
788 && src
->is_positive_polarity
790 DTRACE(opic
, ("interrupt %d - ignore falling edge (positive edge trigered)\n",
793 else if (!src
->is_level_triggered
794 && !src
->is_positive_polarity
796 DTRACE(opic
, ("interrupt %d - ignore rising edge (negative edge trigered)\n",
799 else if (src
->in_service
!= 0) {
800 /* leave the interrupt where it is */
801 ASSERT(!src
->is_multicast
);
802 ASSERT(src
->pending
== 0 || src
->pending
== src
->in_service
);
803 src
->pending
= src
->in_service
;
804 DTRACE(opic
, ("interrupt %ld - ignore already in service to 0x%lx\n",
805 (long)src
->nr
, (long)src
->in_service
));
807 else if (src
->pending
!= 0) {
808 DTRACE(opic
, ("interrupt %ld - ignore still pending to 0x%lx\n",
809 (long)src
->nr
, (long)src
->pending
));
812 /* delivery is needed */
813 opic_interrupt_destination
*dest
= find_lowest_dest(me
, opic
, src
);
814 if (can_deliver(me
, src
, dest
)) {
815 dest
->current_pending
= src
;
816 src
->pending
= dest
->bit
;
817 DTRACE(opic
, ("interrupt %d - delivered to %d\n", src
->nr
, dest
->nr
));
818 assert_interrupt(me
, opic
, dest
);
821 src
->pending
= src
->destination
; /* any can take this */
822 DTRACE(opic
, ("interrupt %ld - pending to 0x%lx\n",
823 (long)src
->nr
, (long)src
->pending
));
829 do_interrupt_acknowledge_register_N_read(device
*me
,
830 hw_opic_device
*opic
,
833 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
836 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
837 ASSERT(dest_nr
== dest
->nr
);
839 /* try the current pending */
840 if (can_deliver(me
, dest
->current_pending
, dest
)) {
841 ASSERT(dest
->current_pending
->pending
& dest
->bit
);
842 vector
= deliver_pending(me
, opic
, dest
);
843 DTRACE(opic
, ("interrupt ack %d - entering %d (pending) - vector %d (%d), priority %d\n",
845 dest
->current_in_service
->nr
,
846 dest
->current_in_service
->vector
, vector
,
847 dest
->current_in_service
->priority
));
850 /* try for something else */
851 dest
->current_pending
= find_interrupt_for_dest(me
, opic
, dest
, pending_interrupt
);
852 if (can_deliver(me
, dest
->current_pending
, dest
)) {
853 vector
= deliver_pending(me
, opic
, dest
);
854 DTRACE(opic
, ("interrupt ack %d - entering %d (not pending) - vector %d (%d), priority %d\n",
856 dest
->current_in_service
->nr
,
857 dest
->current_in_service
->vector
, vector
,
858 dest
->current_in_service
->priority
));
861 dest
->current_pending
= NULL
;
862 vector
= opic
->spurious_vector
;
863 DTRACE(opic
, ("interrupt ack %d - spurious interrupt %d\n",
872 do_end_of_interrupt_register_N_write(device
*me
,
873 hw_opic_device
*opic
,
877 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
879 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
880 ASSERT(dest_nr
== dest
->nr
);
882 /* check the value written is zero */
884 DTRACE(opic
, ("eoi %d - ignoring nonzero value\n", dest
->nr
));
887 /* user doing wierd things? */
888 if (dest
->current_in_service
== NULL
) {
889 DTRACE(opic
, ("eoi %d - strange, no current interrupt\n", dest
->nr
));
893 /* an internal stuff up? */
894 if (!(dest
->current_in_service
->in_service
& dest
->bit
)) {
895 device_error(me
, "eoi %d - current interrupt not in service", dest
->nr
);
898 /* find what was probably the previous in service interrupt */
899 dest
->current_in_service
->in_service
&= ~dest
->bit
;
900 DTRACE(opic
, ("eoi %d - ending %d - priority %d, vector %d\n",
902 dest
->current_in_service
->nr
,
903 dest
->current_in_service
->priority
,
904 dest
->current_in_service
->vector
));
905 dest
->current_in_service
= find_interrupt_for_dest(me
, opic
, dest
, in_service_interrupt
);
906 if (dest
->current_in_service
!= NULL
)
907 DTRACE(opic
, ("eoi %d - resuming %d - priority %d, vector %d\n",
909 dest
->current_in_service
->nr
,
910 dest
->current_in_service
->priority
,
911 dest
->current_in_service
->vector
));
913 DTRACE(opic
, ("eoi %d - resuming none\n", dest
->nr
));
915 /* check to see if that shouldn't be interrupted */
916 dest
->current_pending
= find_interrupt_for_dest(me
, opic
, dest
, pending_interrupt
);
917 if (can_deliver(me
, dest
->current_pending
, dest
)) {
918 ASSERT(dest
->current_pending
->pending
& dest
->bit
);
919 assert_interrupt(me
, opic
, dest
);
922 dest
->current_pending
= NULL
;
928 decode_opic_address(device
*me
,
929 hw_opic_device
*opic
,
931 unsigned_word address
,
938 /* is the size valid? */
940 *type
= invalid_opic_register
;
945 /* try for a per-processor register within the interrupt delivery
947 if (space
== opic
->idu
.space
948 && address
>= (opic
->idu
.address
+ idu_per_processor_register_base
)
949 && address
< (opic
->idu
.address
+ idu_per_processor_register_base
950 + (sizeof_idu_per_processor_register_block
951 * opic
->nr_interrupt_destinations
))) {
952 unsigned_word block_offset
= (address
954 - idu_per_processor_register_base
);
955 unsigned_word offset
= block_offset
% sizeof_idu_per_processor_register_block
;
956 *index
= block_offset
/ sizeof_idu_per_processor_register_block
;
959 *type
= ipi_N_dispatch_register
;
963 *type
= ipi_N_dispatch_register
;
967 *type
= ipi_N_dispatch_register
;
971 *type
= ipi_N_dispatch_register
;
975 *type
= current_task_priority_register_N
;
978 *type
= interrupt_acknowledge_register_N
;
981 *type
= end_of_interrupt_register_N
;
984 *type
= invalid_opic_register
;
987 DTRACE(opic
, ("per-processor register %d:0x%lx - %s[%d]\n",
988 space
, (unsigned long)address
,
989 opic_register_name(*type
),
994 /* try for an interrupt source unit */
995 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
996 if (opic
->isu_block
[isb
].space
== space
997 && address
>= opic
->isu_block
[isb
].address
998 && address
< (opic
->isu_block
[isb
].address
+ opic
->isu_block
[isb
].size
)) {
999 unsigned_word block_offset
= address
- opic
->isu_block
[isb
].address
;
1000 unsigned_word offset
= block_offset
% sizeof_isu_register_block
;
1001 *index
= (opic
->isu_block
[isb
].int_number
1002 + (block_offset
/ sizeof_isu_register_block
));
1005 *type
= interrupt_source_N_vector_priority_register
;
1008 *type
= interrupt_source_N_destination_register
;
1011 *type
= invalid_opic_register
;
1014 DTRACE(opic
, ("isu register %d:0x%lx - %s[%d]\n",
1015 space
, (unsigned long)address
,
1016 opic_register_name(*type
),
1022 /* try for a timer */
1023 if (space
== opic
->idu
.space
1024 && address
>= (opic
->idu
.address
+ idu_timer_base
)
1025 && address
< (opic
->idu
.address
+ idu_timer_base
1026 + opic
->nr_timer_interrupts
* sizeof_timer_register_block
)) {
1027 unsigned_word offset
= address
% sizeof_timer_register_block
;
1028 *index
= ((address
- opic
->idu
.address
- idu_timer_base
)
1029 / sizeof_timer_register_block
);
1032 *type
= timer_N_current_count_register
;
1035 *type
= timer_N_base_count_register
;
1038 *type
= timer_N_vector_priority_register
;
1041 *type
= timer_N_destination_register
;
1044 *type
= invalid_opic_register
;
1047 DTRACE(opic
, ("timer register %d:0x%lx - %s[%d]\n",
1048 space
, (unsigned long)address
,
1049 opic_register_name(*type
),
1054 /* finally some other misc global register */
1055 if (space
== opic
->idu
.space
1056 && address
>= opic
->idu
.address
1057 && address
< opic
->idu
.address
+ opic
->idu
.size
) {
1058 unsigned_word block_offset
= address
- opic
->idu
.address
;
1059 switch (block_offset
) {
1061 *type
= timer_frequency_reporting_register
;
1065 *type
= spurious_vector_register
;
1072 *type
= ipi_N_vector_priority_register
;
1073 *index
= (block_offset
- 0x010a0) / 16;
1076 *type
= processor_init_register
;
1080 *type
= vendor_identification_register
;
1084 *type
= global_configuration_register_N
;
1088 *type
= feature_reporting_register_N
;
1092 *type
= invalid_opic_register
;
1096 DTRACE(opic
, ("global register %d:0x%lx - %s[%d]\n",
1097 space
, (unsigned long)address
,
1098 opic_register_name(*type
),
1103 /* nothing matched */
1104 *type
= invalid_opic_register
;
1105 DTRACE(opic
, ("invalid register %d:0x%lx\n",
1106 space
, (unsigned long)address
));
1111 /* Processor init register:
1113 The bits in this register (one per processor) are directly wired to
1114 output "init" interrupt ports. */
1117 do_processor_init_register_read(device
*me
,
1118 hw_opic_device
*opic
)
1120 unsigned reg
= opic
->init
;
1121 DTRACE(opic
, ("processor init register - read 0x%lx\n",
1127 do_processor_init_register_write(device
*me
,
1128 hw_opic_device
*opic
,
1132 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
1133 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
1134 if ((reg
& dest
->bit
) != (opic
->init
& dest
->bit
)) {
1135 if (reg
& dest
->bit
) {
1136 DTRACE(opic
, ("processor init register - write 0x%lx - asserting init%d\n",
1138 opic
->init
|= dest
->bit
;
1139 device_interrupt_event(me
, dest
->init_port
, 1, NULL
, 0);
1142 DTRACE(opic
, ("processor init register - write 0x%lx - negating init%d\n",
1144 opic
->init
&= ~dest
->bit
;
1145 device_interrupt_event(me
, dest
->init_port
, 0, NULL
, 0);
1153 /* Interrupt Source Vector/Priority Register: */
1156 read_vector_priority_register(device
*me
,
1157 hw_opic_device
*opic
,
1158 opic_interrupt_source
*interrupt
,
1159 const char *reg_name
,
1164 reg
|= interrupt
->is_masked
;
1165 reg
|= (interrupt
->in_service
|| interrupt
->pending
1166 ? isu_active_bit
: 0); /* active */
1167 reg
|= interrupt
->is_multicast
;
1168 reg
|= interrupt
->is_positive_polarity
;
1169 reg
|= interrupt
->is_level_triggered
; /* sense? */
1170 reg
|= interrupt
->priority
<< isu_priority_shift
;
1171 reg
|= interrupt
->vector
;
1172 DTRACE(opic
, ("%s %d vector/priority register - read 0x%lx\n",
1173 reg_name
, reg_index
, (unsigned long)reg
));
1178 do_interrupt_source_N_vector_priority_register_read(device
*me
,
1179 hw_opic_device
*opic
,
1183 ASSERT(index
< opic
->nr_external_interrupts
);
1184 reg
= read_vector_priority_register(me
, opic
,
1185 &opic
->interrupt_source
[index
],
1186 "interrupt source", index
);
1191 write_vector_priority_register(device
*me
,
1192 hw_opic_device
*opic
,
1193 opic_interrupt_source
*interrupt
,
1195 const char *reg_name
,
1198 interrupt
->is_masked
= (reg
& isu_mask_bit
);
1199 interrupt
->is_multicast
= (reg
& isu_multicast_bit
);
1200 interrupt
->is_positive_polarity
= (reg
& isu_positive_polarity_bit
);
1201 interrupt
->is_level_triggered
= (reg
& isu_level_triggered_bit
);
1202 interrupt
->priority
= ((reg
>> isu_priority_shift
)
1203 % max_nr_task_priorities
);
1204 interrupt
->vector
= (reg
& isu_vector_bits
);
1205 DTRACE(opic
, ("%s %d vector/priority register - write 0x%lx - %s%s%s-polarity, %s-triggered, priority %ld vector %ld\n",
1209 interrupt
->is_masked
? "masked, " : "",
1210 interrupt
->is_multicast
? "multicast, " : "",
1211 interrupt
->is_positive_polarity
? "positive" : "negative",
1212 interrupt
->is_level_triggered
? "level" : "edge",
1213 (long)interrupt
->priority
,
1214 (long)interrupt
->vector
));
1218 do_interrupt_source_N_vector_priority_register_write(device
*me
,
1219 hw_opic_device
*opic
,
1223 ASSERT(index
< opic
->nr_external_interrupts
);
1224 reg
&= ~isu_multicast_bit
; /* disable multicast */
1225 write_vector_priority_register(me
, opic
,
1226 &opic
->interrupt_source
[index
],
1227 reg
, "interrupt source", index
);
1232 /* Interrupt Source Destination Register: */
1235 read_destination_register(device
*me
,
1236 hw_opic_device
*opic
,
1237 opic_interrupt_source
*interrupt
,
1238 const char *reg_name
,
1242 reg
= interrupt
->destination
;
1243 DTRACE(opic
, ("%s %d destination register - read 0x%lx\n",
1244 reg_name
, reg_index
, reg
));
1249 do_interrupt_source_N_destination_register_read(device
*me
,
1250 hw_opic_device
*opic
,
1254 ASSERT(index
< opic
->nr_external_interrupts
);
1255 reg
= read_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1256 "interrupt source", index
);
1261 write_destination_register(device
*me
,
1262 hw_opic_device
*opic
,
1263 opic_interrupt_source
*interrupt
,
1265 const char *reg_name
,
1268 reg
&= (1 << opic
->nr_interrupt_destinations
) - 1; /* mask out invalid */
1269 DTRACE(opic
, ("%s %d destination register - write 0x%x\n",
1270 reg_name
, reg_index
, reg
));
1271 interrupt
->destination
= reg
;
1275 do_interrupt_source_N_destination_register_write(device
*me
,
1276 hw_opic_device
*opic
,
1280 ASSERT(index
< opic
->nr_external_interrupts
);
1281 write_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1282 reg
, "interrupt source", index
);
1287 /* Spurious vector register: */
1290 do_spurious_vector_register_read(device
*me
,
1291 hw_opic_device
*opic
)
1293 unsigned long reg
= opic
->spurious_vector
;
1294 DTRACE(opic
, ("spurious vector register - read 0x%lx\n", reg
));
1299 do_spurious_vector_register_write(device
*me
,
1300 hw_opic_device
*opic
,
1303 reg
&= 0xff; /* mask off invalid */
1304 DTRACE(opic
, ("spurious vector register - write 0x%x\n", reg
));
1305 opic
->spurious_vector
= reg
;
1310 /* current task priority register: */
1313 do_current_task_priority_register_N_read(device
*me
,
1314 hw_opic_device
*opic
,
1317 opic_interrupt_destination
*interrupt_destination
= &opic
->interrupt_destination
[index
];
1319 ASSERT(index
>= 0 && index
< opic
->nr_interrupt_destinations
);
1320 reg
= interrupt_destination
->base_priority
;
1321 DTRACE(opic
, ("current task priority register %d - read 0x%x\n", index
, reg
));
1326 do_current_task_priority_register_N_write(device
*me
,
1327 hw_opic_device
*opic
,
1331 opic_interrupt_destination
*interrupt_destination
= &opic
->interrupt_destination
[index
];
1332 ASSERT(index
>= 0 && index
< opic
->nr_interrupt_destinations
);
1333 reg
%= max_nr_task_priorities
;
1334 DTRACE(opic
, ("current task priority register %d - write 0x%x\n", index
, reg
));
1335 interrupt_destination
->base_priority
= reg
;
1340 /* Timer Frequency Reporting Register: */
1343 do_timer_frequency_reporting_register_read(device
*me
,
1344 hw_opic_device
*opic
)
1347 reg
= opic
->timer_frequency
;
1348 DTRACE(opic
, ("timer frequency reporting register - read 0x%x\n", reg
));
1353 do_timer_frequency_reporting_register_write(device
*me
,
1354 hw_opic_device
*opic
,
1357 DTRACE(opic
, ("timer frequency reporting register - write 0x%x\n", reg
));
1358 opic
->timer_frequency
= reg
;
1362 /* timer registers: */
1365 do_timer_N_current_count_register_read(device
*me
,
1366 hw_opic_device
*opic
,
1369 opic_timer
*timer
= &opic
->timer
[index
];
1371 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1372 if (timer
->inhibited
)
1373 reg
= timer
->count
; /* stalled value */
1375 reg
= timer
->count
- device_event_queue_time(me
); /* time remaining */
1376 DTRACE(opic
, ("timer %d current count register - read 0x%x\n", index
, reg
));
1382 do_timer_N_base_count_register_read(device
*me
,
1383 hw_opic_device
*opic
,
1386 opic_timer
*timer
= &opic
->timer
[index
];
1388 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1389 reg
= timer
->base_count
;
1390 DTRACE(opic
, ("timer %d base count register - read 0x%x\n", index
, reg
));
1396 timer_event(void *data
)
1398 opic_timer
*timer
= data
;
1399 device
*me
= timer
->me
;
1400 if (timer
->inhibited
)
1401 device_error(timer
->me
, "internal-error - timer event occured when timer %d inhibited",
1403 handle_interrupt(timer
->me
, timer
->opic
, timer
->interrupt_source
, 1);
1404 timer
->timeout_event
= device_event_queue_schedule(me
, timer
->base_count
,
1405 timer_event
, timer
);
1406 DTRACE(opic
, ("timer %d - interrupt at %ld, next at %d\n",
1407 timer
->nr
, (long)device_event_queue_time(me
), timer
->base_count
));
1412 do_timer_N_base_count_register_write(device
*me
,
1413 hw_opic_device
*opic
,
1417 opic_timer
*timer
= &opic
->timer
[index
];
1419 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1420 inhibit
= reg
& 0x80000000;
1421 if (timer
->inhibited
&& !inhibit
) {
1422 timer
->inhibited
= 0;
1423 if (timer
->timeout_event
!= NULL
)
1424 device_event_queue_deschedule(me
, timer
->timeout_event
);
1425 timer
->count
= device_event_queue_time(me
) + reg
;
1426 timer
->base_count
= reg
;
1427 timer
->timeout_event
= device_event_queue_schedule(me
, timer
->base_count
,
1428 timer_event
, (void*)timer
);
1429 DTRACE(opic
, ("timer %d base count register - write 0x%x - timer started\n",
1432 else if (!timer
->inhibited
&& inhibit
) {
1433 if (timer
->timeout_event
!= NULL
)
1434 device_event_queue_deschedule(me
, timer
->timeout_event
);
1435 timer
->count
= timer
->count
- device_event_queue_time(me
);
1436 timer
->inhibited
= 1;
1437 timer
->base_count
= reg
;
1438 DTRACE(opic
, ("timer %d base count register - write 0x%x - timer stopped\n",
1442 ASSERT((timer
->inhibited
&& inhibit
) || (!timer
->inhibited
&& !inhibit
));
1443 DTRACE(opic
, ("timer %d base count register - write 0x%x\n", index
, reg
));
1444 timer
->base_count
= reg
;
1450 do_timer_N_vector_priority_register_read(device
*me
,
1451 hw_opic_device
*opic
,
1455 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1456 reg
= read_vector_priority_register(me
, opic
,
1457 &opic
->timer_interrupt_source
[index
],
1463 do_timer_N_vector_priority_register_write(device
*me
,
1464 hw_opic_device
*opic
,
1468 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1469 reg
&= ~isu_level_triggered_bit
; /* force edge trigger */
1470 reg
|= isu_positive_polarity_bit
; /* force rising (positive) edge */
1471 reg
|= isu_multicast_bit
; /* force multicast */
1472 write_vector_priority_register(me
, opic
,
1473 &opic
->timer_interrupt_source
[index
],
1474 reg
, "timer", index
);
1479 do_timer_N_destination_register_read(device
*me
,
1480 hw_opic_device
*opic
,
1484 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1485 reg
= read_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1491 do_timer_N_destination_register_write(device
*me
,
1492 hw_opic_device
*opic
,
1496 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1497 write_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1498 reg
, "timer", index
);
1505 do_ipi_N_vector_priority_register_read(device
*me
,
1506 hw_opic_device
*opic
,
1510 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1511 reg
= read_vector_priority_register(me
, opic
,
1512 &opic
->interprocessor_interrupt_source
[index
],
1518 do_ipi_N_vector_priority_register_write(device
*me
,
1519 hw_opic_device
*opic
,
1523 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1524 reg
&= ~isu_level_triggered_bit
; /* force edge trigger */
1525 reg
|= isu_positive_polarity_bit
; /* force rising (positive) edge */
1526 reg
|= isu_multicast_bit
; /* force a multicast source */
1527 write_vector_priority_register(me
, opic
,
1528 &opic
->interprocessor_interrupt_source
[index
],
1533 do_ipi_N_dispatch_register_write(device
*me
,
1534 hw_opic_device
*opic
,
1538 opic_interrupt_source
*source
= &opic
->interprocessor_interrupt_source
[index
];
1539 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1540 DTRACE(opic
, ("ipi %d interrupt dispatch register - write 0x%x\n", index
, reg
));
1541 source
->destination
= reg
;
1542 handle_interrupt(me
, opic
, source
, 1);
1546 /* vendor and other global registers */
1549 do_vendor_identification_register_read(device
*me
,
1550 hw_opic_device
*opic
)
1553 reg
= opic
->vendor_identification
;
1554 DTRACE(opic
, ("vendor identification register - read 0x%x\n", reg
));
1559 do_feature_reporting_register_N_read(device
*me
,
1560 hw_opic_device
*opic
,
1567 reg
|= (opic
->nr_external_interrupts
<< 16);
1568 reg
|= (opic
->nr_interrupt_destinations
<< 8);
1569 reg
|= (2/*version 1.2*/);
1572 DTRACE(opic
, ("feature reporting register %d - read 0x%x\n", index
, reg
));
1577 do_global_configuration_register_N_read(device
*me
,
1578 hw_opic_device
*opic
,
1585 reg
|= gcr0_8259_bit
; /* hardwire 8259 disabled */
1588 DTRACE(opic
, ("global configuration register %d - read 0x%x\n", index
, reg
));
1593 do_global_configuration_register_N_write(device
*me
,
1594 hw_opic_device
*opic
,
1599 if (reg
& gcr0_reset_bit
) {
1600 DTRACE(opic
, ("global configuration register %d - write 0x%x - reseting opic\n", index
, reg
));
1601 hw_opic_init_data(me
);
1603 if (!(reg
& gcr0_8259_bit
)) {
1604 DTRACE(opic
, ("global configuration register %d - write 0x%x - ignoring 8259 enable\n", index
, reg
));
1610 /* register read-write */
1613 hw_opic_io_read_buffer(device
*me
,
1621 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1624 decode_opic_address(me
, opic
, space
, addr
, nr_bytes
, &type
, &index
);
1625 if (type
== invalid_opic_register
) {
1626 device_error(me
, "invalid opic read access to %d:0x%lx (%d bytes)",
1627 space
, (unsigned long)addr
, nr_bytes
);
1632 case processor_init_register
:
1633 reg
= do_processor_init_register_read(me
, opic
);
1635 case interrupt_source_N_vector_priority_register
:
1636 reg
= do_interrupt_source_N_vector_priority_register_read(me
, opic
, index
);
1638 case interrupt_source_N_destination_register
:
1639 reg
= do_interrupt_source_N_destination_register_read(me
, opic
, index
);
1641 case interrupt_acknowledge_register_N
:
1642 reg
= do_interrupt_acknowledge_register_N_read(me
, opic
, index
);
1644 case spurious_vector_register
:
1645 reg
= do_spurious_vector_register_read(me
, opic
);
1647 case current_task_priority_register_N
:
1648 reg
= do_current_task_priority_register_N_read(me
, opic
, index
);
1650 case timer_frequency_reporting_register
:
1651 reg
= do_timer_frequency_reporting_register_read(me
, opic
);
1653 case timer_N_current_count_register
:
1654 reg
= do_timer_N_current_count_register_read(me
, opic
, index
);
1656 case timer_N_base_count_register
:
1657 reg
= do_timer_N_base_count_register_read(me
, opic
, index
);
1659 case timer_N_vector_priority_register
:
1660 reg
= do_timer_N_vector_priority_register_read(me
, opic
, index
);
1662 case timer_N_destination_register
:
1663 reg
= do_timer_N_destination_register_read(me
, opic
, index
);
1665 case ipi_N_vector_priority_register
:
1666 reg
= do_ipi_N_vector_priority_register_read(me
, opic
, index
);
1668 case feature_reporting_register_N
:
1669 reg
= do_feature_reporting_register_N_read(me
, opic
, index
);
1671 case global_configuration_register_N
:
1672 reg
= do_global_configuration_register_N_read(me
, opic
, index
);
1674 case vendor_identification_register
:
1675 reg
= do_vendor_identification_register_read(me
, opic
);
1679 device_error(me
, "unimplemented read of register %s[%d]",
1680 opic_register_name(type
), index
);
1682 *(unsigned_4
*)dest
= H2LE_4(reg
);
1689 hw_opic_io_write_buffer(device
*me
,
1697 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1700 decode_opic_address(me
, opic
, space
, addr
, nr_bytes
, &type
, &index
);
1701 if (type
== invalid_opic_register
) {
1702 device_error(me
, "invalid opic write access to %d:0x%lx (%d bytes)",
1703 space
, (unsigned long)addr
, nr_bytes
);
1706 unsigned reg
= LE2H_4(*(unsigned_4
*)source
);
1708 case processor_init_register
:
1709 do_processor_init_register_write(me
, opic
, reg
);
1711 case interrupt_source_N_vector_priority_register
:
1712 do_interrupt_source_N_vector_priority_register_write(me
, opic
, index
, reg
);
1714 case interrupt_source_N_destination_register
:
1715 do_interrupt_source_N_destination_register_write(me
, opic
, index
, reg
);
1717 case end_of_interrupt_register_N
:
1718 do_end_of_interrupt_register_N_write(me
, opic
, index
, reg
);
1720 case spurious_vector_register
:
1721 do_spurious_vector_register_write(me
, opic
, reg
);
1723 case current_task_priority_register_N
:
1724 do_current_task_priority_register_N_write(me
, opic
, index
, reg
);
1726 case timer_frequency_reporting_register
:
1727 do_timer_frequency_reporting_register_write(me
, opic
, reg
);
1729 case timer_N_base_count_register
:
1730 do_timer_N_base_count_register_write(me
, opic
, index
, reg
);
1732 case timer_N_vector_priority_register
:
1733 do_timer_N_vector_priority_register_write(me
, opic
, index
, reg
);
1735 case timer_N_destination_register
:
1736 do_timer_N_destination_register_write(me
, opic
, index
, reg
);
1738 case ipi_N_dispatch_register
:
1739 do_ipi_N_dispatch_register_write(me
, opic
, index
, reg
);
1741 case ipi_N_vector_priority_register
:
1742 do_ipi_N_vector_priority_register_write(me
, opic
, index
, reg
);
1744 case global_configuration_register_N
:
1745 do_global_configuration_register_N_write(me
, opic
, index
, reg
);
1748 device_error(me
, "unimplemented write to register %s[%d]",
1749 opic_register_name(type
), index
);
1757 hw_opic_interrupt_event(device
*me
,
1765 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1770 /* find the corresponding internal input port */
1771 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
1772 if (my_port
>= opic
->isu_block
[isb
].int_number
1773 && my_port
< opic
->isu_block
[isb
].int_number
+ opic
->isu_block
[isb
].range
) {
1774 src_nr
+= my_port
- opic
->isu_block
[isb
].int_number
;
1778 src_nr
+= opic
->isu_block
[isb
].range
;
1780 if (isb
== opic
->nr_isu_blocks
)
1781 device_error(me
, "interrupt %d out of range", my_port
);
1782 DTRACE(opic
, ("external-interrupt %d, internal %d, level %d\n",
1783 my_port
, src_nr
, level
));
1786 ASSERT(src_nr
>= 0 && src_nr
< opic
->nr_external_interrupts
);
1787 handle_interrupt(me
, opic
, &opic
->external_interrupt_source
[src_nr
], level
);
1791 static const device_interrupt_port_descriptor hw_opic_interrupt_ports
[] = {
1792 { "irq", 0, max_nr_interrupt_sources
, input_port
, },
1793 { "intr", 0, max_nr_interrupt_destinations
, output_port
, },
1794 { "init", max_nr_interrupt_destinations
, max_nr_interrupt_destinations
, output_port
, },
1799 static device_callbacks
const hw_opic_callbacks
= {
1800 { generic_device_init_address
,
1801 hw_opic_init_data
},
1802 { NULL
, }, /* address */
1803 { hw_opic_io_read_buffer
,
1804 hw_opic_io_write_buffer
}, /* IO */
1805 { NULL
, }, /* DMA */
1806 { hw_opic_interrupt_event
, NULL
, hw_opic_interrupt_ports
}, /* interrupt */
1807 { NULL
, }, /* unit */
1808 NULL
, /* instance */
1812 hw_opic_create(const char *name
,
1813 const device_unit
*unit_address
,
1816 hw_opic_device
*opic
= ZALLOC(hw_opic_device
);
1822 const device_descriptor hw_opic_device_descriptor
[] = {
1823 { "opic", hw_opic_create
, &hw_opic_callbacks
},
1827 #endif /* _HW_OPIC_C_ */