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"
38 opic - Open Programmable Interrupt Controller (OpenPIC)
44 This device implements the core of the OpenPIC interrupt controller
45 as described in the OpenPIC specification 1.2 and other related
50 o Up to 2048 external interrupt sources
52 o The four count down timers
54 o The four interprocessor multicast interrupts
56 o multiprocessor support
58 o Full tracing to assist help debugging
60 o Support for all variations of edge/level x high/low polarity.
67 reg = <address> <size> ... (required)
69 Determine where the device lives in the parents address space. The
70 first <<address>> <<size>> pair specifies the address of the
71 interrupt destination unit (which might contain an interrupt source
72 unit) while successive reg entries specify additional interrupt
75 Note that for an <<opic>> device attached to a <<pci>> bus, the
76 first <<reg>> entry may need to be ignored it will be the address
77 of the devices configuration registers.
80 interrupt-ranges = <int-number> <range> ... (required)
82 A list of pairs. Each pair corresponds to a block of interrupt
83 source units (the address of which being specified by the
84 corresponding reg tupple). <<int-number>> is the number of the
85 first interrupt in the block while <<range>> is the number of
86 interrupts in the block.
89 timer-frequency = <integer> (optional)
91 If present, specifies the default value of the timer frequency
92 reporting register. By default a value of 1 HZ is used. The value
93 is arbitrary, the timers are always updated once per machine cycle.
96 vendor-identification = <integer> (optional)
98 If present, specifies the value to be returned when the vendor
99 identification register is read.
105 See the test suite directory:
112 For an OPIC controller attached to a PCI bus, it is not clear what
113 the value of the <<reg>> and <<interrupt-ranges>> properties should
114 be. In particular, the PCI firmware bindings require the first
115 value of the <<reg>> property to specify the devices configuration
116 address while the OpenPIC bindings require that same entry to
117 specify the address of the Interrupt Delivery Unit. This
118 implementation checks for and, if present, ignores any
119 configuration address (and its corresponding <<interrupt-ranges>>
122 The OpenPIC specification requires the controller to be fair when
123 distributing interrupts between processors. At present the
124 algorithm used isn't fair. It is biased towards processor zero.
126 The OpenPIC specification includes a 8259 pass through mode. This
133 PowerPC Multiprocessor Interrupt Controller (MPIC), January 19,
134 1996. Available from IBM.
137 The Open Programmable Interrupt Controller (PIC) Register Interface
138 Specification Revision 1.2. Issue Date: Opctober 1995. Available
139 somewhere on AMD's web page (http://www.amd.com/)
142 PowerPC Microprocessor Common Hardware Reference Platform (CHRP)
143 System bindings to: IEEE Std 1275-1994 Standard for Boot
144 (Initialization, Configuration) Firmware. Revision 1.2b (INTERIM
145 DRAFT). April 22, 1996. Available on the Open Firmware web site
146 http://playground.sun.com/p1275/.
154 typedef struct _hw_opic_device hw_opic_device
;
160 max_nr_interrupt_sources
= 2048,
161 max_nr_interrupt_destinations
= 32,
162 max_nr_task_priorities
= 16,
171 /* global configuration register */
174 gcr0_8259_bit
= 0x20000000,
175 gcr0_reset_bit
= 0x80000000,
179 /* offsets and sizes */
182 idu_isu_base
= 0x10000,
183 sizeof_isu_register_block
= 32,
184 idu_per_processor_register_base
= 0x20000,
185 sizeof_idu_per_processor_register_block
= 0x1000,
186 idu_timer_base
= 0x01100,
187 sizeof_timer_register_block
= 0x00040,
191 /* Interrupt sources */
194 isu_mask_bit
= 0x80000000,
195 isu_active_bit
= 0x40000000,
196 isu_multicast_bit
= 0x20000000,
197 isu_positive_polarity_bit
= 0x00800000,
198 isu_level_triggered_bit
= 0x00400000,
199 isu_priority_shift
= 16,
200 isu_vector_bits
= 0x000000ff,
204 typedef struct _opic_interrupt_source
{
205 unsigned is_masked
; /* left in place */
206 unsigned is_multicast
; /* left in place */
207 unsigned is_positive_polarity
; /* left in place */
208 unsigned is_level_triggered
; /* left in place */
213 unsigned destination
;
216 } opic_interrupt_source
;
219 /* interrupt destinations (normally processors) */
221 typedef struct _opic_interrupt_destination
{
223 unsigned base_priority
;
224 opic_interrupt_source
*current_pending
;
225 opic_interrupt_source
*current_in_service
;
229 } opic_interrupt_destination
;
232 /* address map descriptors */
234 typedef struct _opic_isu_block
{ /* interrupt source unit block */
236 unsigned_word address
;
238 unsigned_cell int_number
;
244 typedef struct _opic_idu
{ /* interrupt delivery unit */
247 unsigned_word address
;
253 invalid_opic_register
,
254 /* interrupt source */
255 interrupt_source_N_destination_register
,
256 interrupt_source_N_vector_priority_register
,
258 timer_N_destination_register
,
259 timer_N_vector_priority_register
,
260 timer_N_base_count_register
,
261 timer_N_current_count_register
,
262 timer_frequency_reporting_register
,
263 /* inter-processor interrupts */
264 ipi_N_vector_priority_register
,
265 ipi_N_dispatch_register
,
266 /* global configuration */
267 spurious_vector_register
,
268 processor_init_register
,
269 vendor_identification_register
,
270 global_configuration_register_N
,
271 feature_reporting_register_N
,
273 end_of_interrupt_register_N
,
274 interrupt_acknowledge_register_N
,
275 current_task_priority_register_N
,
279 opic_register_name(opic_register type
)
282 case invalid_opic_register
: return "invalid_opic_register";
283 case interrupt_source_N_destination_register
: return "interrupt_source_N_destination_register";
284 case interrupt_source_N_vector_priority_register
: return "interrupt_source_N_vector_priority_register";
285 case timer_N_destination_register
: return "timer_N_destination_register";
286 case timer_N_vector_priority_register
: return "timer_N_vector_priority_register";
287 case timer_N_base_count_register
: return "timer_N_base_count_register";
288 case timer_N_current_count_register
: return "timer_N_current_count_register";
289 case timer_frequency_reporting_register
: return "timer_frequency_reporting_register";
290 case ipi_N_vector_priority_register
: return "ipi_N_vector_priority_register";
291 case ipi_N_dispatch_register
: return "ipi_N_dispatch_register";
292 case spurious_vector_register
: return "spurious_vector_register";
293 case processor_init_register
: return "processor_init_register";
294 case vendor_identification_register
: return "vendor_identification_register";
295 case global_configuration_register_N
: return "global_configuration_register_N";
296 case feature_reporting_register_N
: return "feature_reporting_register_N";
297 case end_of_interrupt_register_N
: return "end_of_interrupt_register_N";
298 case interrupt_acknowledge_register_N
: return "interrupt_acknowledge_register_N";
299 case current_task_priority_register_N
: return "current_task_priority_register_N";
308 typedef struct _opic_timer
{
310 device
*me
; /* find my way home */
311 hw_opic_device
*opic
; /* ditto */
314 signed64 count
; /* *ONLY* if inhibited */
315 event_entry_tag timeout_event
;
316 opic_interrupt_source
*interrupt_source
;
322 struct _hw_opic_device
{
325 unsigned vendor_identification
;
327 /* interrupt destinations - processors */
328 int nr_interrupt_destinations
;
329 opic_interrupt_destination
*interrupt_destination
;
330 unsigned sizeof_interrupt_destination
;
332 /* bogus interrupts */
335 /* interrupt sources - external interrupt source units + extra internal ones */
336 int nr_interrupt_sources
;
337 opic_interrupt_source
*interrupt_source
;
338 unsigned sizeof_interrupt_source
;
340 /* external interrupts */
341 int nr_external_interrupts
;
342 opic_interrupt_source
*external_interrupt_source
;
344 /* inter-processor-interrupts */
345 int nr_interprocessor_interrupts
;
346 opic_interrupt_source
*interprocessor_interrupt_source
;
349 int nr_timer_interrupts
;
351 unsigned sizeof_timer
;
352 opic_interrupt_source
*timer_interrupt_source
;
353 unsigned timer_frequency
;
361 opic_isu_block
*isu_block
;
366 hw_opic_init_data(device
*me
)
368 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
374 /* determine the first valid reg property entry (there could be
375 leading reg entries with invalid (zero) size fields) and the
376 number of isu entries found in the reg property. */
380 reg_property_spec unit
;
382 unsigned_word attach_address
;
383 unsigned attach_size
;
384 if (!device_find_reg_array_property(me
, "reg", idu_reg
+ nr_isu_blocks
,
387 if (nr_isu_blocks
> 0
388 || (device_address_to_attach_address(device_parent(me
), &unit
.address
,
389 &attach_space
, &attach_address
,
391 && device_size_to_attach_size(device_parent(me
), &unit
.size
,
394 /* we count any thing once we've found one valid address/size pair */
402 /* determine the number and location of the multiple interrupt
403 source units and the single interrupt delivery unit */
404 if (opic
->isu_block
== NULL
) {
406 opic
->nr_isu_blocks
= nr_isu_blocks
;
407 opic
->isu_block
= zalloc(sizeof(opic_isu_block
) * opic
->nr_isu_blocks
);
410 while (isb
< opic
->nr_isu_blocks
) {
411 reg_property_spec reg
;
412 if (!device_find_reg_array_property(me
, "reg", reg_nr
, ®
))
413 device_error(me
, "reg property missing entry number %d", reg_nr
);
414 opic
->isu_block
[isb
].reg
= reg_nr
;
415 if (!device_address_to_attach_address(device_parent(me
), ®
.address
,
416 &opic
->isu_block
[isb
].space
,
417 &opic
->isu_block
[isb
].address
,
419 || !device_size_to_attach_size(device_parent(me
), ®
.size
,
420 &opic
->isu_block
[isb
].size
,
422 device_error(me
, "reg property entry %d invalid", reg_nr
);
424 if (!device_find_integer_array_property(me
, "interrupt-ranges",
426 &opic
->isu_block
[isb
].int_number
)
427 || !device_find_integer_array_property(me
, "interrupt-ranges",
429 &opic
->isu_block
[isb
].range
))
430 device_error(me
, "missing or invalid interrupt-ranges property entry %d", reg_nr
);
431 /* first reg entry specifies the address of both the IDU and the
432 first set of ISU registers, adjust things accordingly */
433 if (reg_nr
== idu_reg
) {
434 opic
->idu
.reg
= opic
->isu_block
[isb
].reg
;
435 opic
->idu
.space
= opic
->isu_block
[isb
].space
;
436 opic
->idu
.address
= opic
->isu_block
[isb
].address
;
437 opic
->idu
.size
= opic
->isu_block
[isb
].size
;
438 opic
->isu_block
[isb
].address
+= idu_isu_base
;
439 opic
->isu_block
[isb
].size
= opic
->isu_block
[isb
].range
* (16 + 16);
441 /* was this a valid reg entry? */
442 if (opic
->isu_block
[isb
].range
== 0) {
443 opic
->nr_isu_blocks
-= 1;
446 opic
->nr_external_interrupts
+= opic
->isu_block
[isb
].range
;
452 DTRACE(opic
, ("interrupt source unit block - effective number of blocks %d\n",
453 (int)opic
->nr_isu_blocks
));
456 /* the number of other interrupts */
457 opic
->nr_interprocessor_interrupts
= 4;
458 opic
->nr_timer_interrupts
= 4;
461 /* create space for the interrupt source registers */
462 if (opic
->interrupt_source
!= NULL
) {
463 memset(opic
->interrupt_source
, 0, opic
->sizeof_interrupt_source
);
466 opic
->nr_interrupt_sources
= (opic
->nr_external_interrupts
467 + opic
->nr_interprocessor_interrupts
468 + opic
->nr_timer_interrupts
);
469 if (opic
->nr_interrupt_sources
> max_nr_interrupt_sources
)
470 device_error(me
, "number of interrupt sources exceeded");
471 opic
->sizeof_interrupt_source
= (sizeof(opic_interrupt_source
)
472 * opic
->nr_interrupt_sources
);
473 opic
->interrupt_source
= zalloc(opic
->sizeof_interrupt_source
);
474 opic
->external_interrupt_source
= opic
->interrupt_source
;
475 opic
->interprocessor_interrupt_source
= (opic
->external_interrupt_source
476 + opic
->nr_external_interrupts
);
477 opic
->timer_interrupt_source
= (opic
->interprocessor_interrupt_source
478 + opic
->nr_interprocessor_interrupts
);
480 for (i
= 0; i
< opic
->nr_interrupt_sources
; i
++) {
481 opic_interrupt_source
*source
= &opic
->interrupt_source
[i
];
483 source
->is_masked
= isu_mask_bit
;
485 DTRACE(opic
, ("interrupt sources - external %d, timer %d, ipi %d, total %d\n",
486 opic
->nr_external_interrupts
,
487 opic
->nr_timer_interrupts
,
488 opic
->nr_interprocessor_interrupts
,
489 opic
->nr_interrupt_sources
));
492 /* timers or interprocessor interrupts */
493 if (opic
->timer
!= NULL
)
494 memset(opic
->timer
, 0, opic
->sizeof_timer
);
496 opic
->nr_timer_interrupts
= 4;
497 opic
->sizeof_timer
= sizeof(opic_timer
) * opic
->nr_timer_interrupts
;
498 opic
->timer
= zalloc(opic
->sizeof_timer
);
500 for (i
= 0; i
< opic
->nr_timer_interrupts
; i
++) {
501 opic_timer
*timer
= &opic
->timer
[i
];
505 timer
->inhibited
= 1;
506 timer
->interrupt_source
= &opic
->timer_interrupt_source
[i
];
508 if (device_find_property(me
, "timer-frequency"))
509 opic
->timer_frequency
= device_find_integer_property(me
, "timer-frequency");
511 opic
->timer_frequency
= 1;
514 /* create space for the interrupt destination registers */
515 if (opic
->interrupt_destination
!= NULL
) {
516 memset(opic
->interrupt_destination
, 0, opic
->sizeof_interrupt_destination
);
519 opic
->nr_interrupt_destinations
= tree_find_integer_property(me
, "/openprom/options/smp");
520 opic
->sizeof_interrupt_destination
= (sizeof(opic_interrupt_destination
)
521 * opic
->nr_interrupt_destinations
);
522 opic
->interrupt_destination
= zalloc(opic
->sizeof_interrupt_destination
);
523 if (opic
->nr_interrupt_destinations
> max_nr_interrupt_destinations
)
524 device_error(me
, "number of interrupt destinations exceeded");
526 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
527 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
528 dest
->bit
= (1 << i
);
530 dest
->init_port
= (device_interrupt_decode(me
, "init0", output_port
)
532 dest
->intr_port
= (device_interrupt_decode(me
, "intr0", output_port
)
534 dest
->base_priority
= max_nr_task_priorities
- 1;
536 DTRACE(opic
, ("interrupt destinations - total %d\n",
537 (int)opic
->nr_interrupt_destinations
));
540 /* verify and print out the ISU's */
541 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
542 unsigned correct_size
;
543 if ((opic
->isu_block
[isb
].address
% opic_alignment
) != 0)
544 device_error(me
, "interrupt source unit %d address not aligned to %d byte boundary",
545 isb
, opic_alignment
);
546 correct_size
= opic
->isu_block
[isb
].range
* sizeof_isu_register_block
;
547 if (opic
->isu_block
[isb
].size
!= correct_size
)
548 device_error(me
, "interrupt source unit %d (reg %d) has an incorrect size, should be 0x%x",
549 isb
, opic
->isu_block
[isb
].reg
, correct_size
);
550 DTRACE(opic
, ("interrupt source unit block %ld - address %d:0x%lx, size 0x%lx, int-number %ld, range %ld\n",
552 (int)opic
->isu_block
[isb
].space
,
553 (unsigned long)opic
->isu_block
[isb
].address
,
554 (unsigned long)opic
->isu_block
[isb
].size
,
555 (long)opic
->isu_block
[isb
].int_number
,
556 (long)opic
->isu_block
[isb
].range
));
560 /* verify and print out the IDU */
562 unsigned correct_size
;
563 unsigned alternate_size
;
564 if ((opic
->idu
.address
% opic_alignment
) != 0)
565 device_error(me
, "interrupt delivery unit not aligned to %d byte boundary",
567 correct_size
= (idu_per_processor_register_base
568 + (sizeof_idu_per_processor_register_block
569 * opic
->nr_interrupt_destinations
));
570 alternate_size
= (idu_per_processor_register_base
571 + (sizeof_idu_per_processor_register_block
572 * max_nr_interrupt_destinations
));
573 if (opic
->idu
.size
!= correct_size
574 && opic
->idu
.size
!= alternate_size
)
575 device_error(me
, "interrupt delivery unit has incorrect size, should be 0x%x or 0x%x",
576 correct_size
, alternate_size
);
577 DTRACE(opic
, ("interrupt delivery unit - address %d:0x%lx, size 0x%lx\n",
578 (int)opic
->idu
.space
,
579 (unsigned long)opic
->idu
.address
,
580 (unsigned long)opic
->idu
.size
));
583 /* initialize the init interrupts */
588 if (device_find_property(me
, "vendor-identification") != NULL
)
589 opic
->vendor_identification
= device_find_integer_property(me
, "vendor-identification");
591 opic
->vendor_identification
= 0;
594 opic
->spurious_vector
= 0xff;
599 /* interrupt related actions */
602 assert_interrupt(device
*me
,
603 hw_opic_device
*opic
,
604 opic_interrupt_destination
*dest
)
606 ASSERT(dest
>= opic
->interrupt_destination
);
607 ASSERT(dest
< opic
->interrupt_destination
+ opic
->nr_interrupt_destinations
);
608 DTRACE(opic
, ("assert interrupt - intr port %d\n", dest
->intr_port
));
609 device_interrupt_event(me
, dest
->intr_port
, 1, NULL
, 0);
614 negate_interrupt(device
*me
,
615 hw_opic_device
*opic
,
616 opic_interrupt_destination
*dest
)
618 ASSERT(dest
>= opic
->interrupt_destination
);
619 ASSERT(dest
< opic
->interrupt_destination
+ opic
->nr_interrupt_destinations
);
620 DTRACE(opic
, ("negate interrupt - intr port %d\n", dest
->intr_port
));
621 device_interrupt_event(me
, dest
->intr_port
, 0, NULL
, 0);
626 can_deliver(device
*me
,
627 opic_interrupt_source
*source
,
628 opic_interrupt_destination
*dest
)
630 return (source
!= NULL
&& dest
!= NULL
631 && source
->priority
> dest
->base_priority
632 && (dest
->current_in_service
== NULL
633 || source
->priority
> dest
->current_in_service
->priority
));
638 deliver_pending(device
*me
,
639 hw_opic_device
*opic
,
640 opic_interrupt_destination
*dest
)
642 ASSERT(can_deliver(me
, dest
->current_pending
, dest
));
643 dest
->current_in_service
= dest
->current_pending
;
644 dest
->current_in_service
->in_service
|= dest
->bit
;
645 if (!dest
->current_pending
->is_level_triggered
) {
646 if (dest
->current_pending
->is_multicast
)
647 dest
->current_pending
->pending
&= ~dest
->bit
;
649 dest
->current_pending
->pending
= 0;
651 dest
->current_pending
= NULL
;
652 negate_interrupt(me
, opic
, dest
);
653 return dest
->current_in_service
->vector
;
659 in_service_interrupt
,
662 static opic_interrupt_source
*
663 find_interrupt_for_dest(device
*me
,
664 hw_opic_device
*opic
,
665 opic_interrupt_destination
*dest
,
666 interrupt_class
class)
669 opic_interrupt_source
*pending
= NULL
;
670 for (i
= 0; i
< opic
->nr_interrupt_sources
; i
++) {
671 opic_interrupt_source
*src
= &opic
->interrupt_source
[i
];
672 /* is this a potential hit? */
674 case in_service_interrupt
:
675 if ((src
->in_service
& dest
->bit
) == 0)
678 case pending_interrupt
:
679 if ((src
->pending
& dest
->bit
) == 0)
683 /* see if it is the highest priority */
686 else if (src
->priority
> pending
->priority
)
693 static opic_interrupt_destination
*
694 find_lowest_dest(device
*me
,
695 hw_opic_device
*opic
,
696 opic_interrupt_source
*src
)
699 opic_interrupt_destination
*lowest
= NULL
;
700 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
701 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
702 if (src
->destination
& dest
->bit
) {
703 if (dest
->base_priority
< src
->priority
) {
706 else if (lowest
->base_priority
> dest
->base_priority
)
708 else if (lowest
->current_in_service
!= NULL
709 && dest
->current_in_service
== NULL
)
710 lowest
= dest
; /* not doing anything */
711 else if (lowest
->current_in_service
!= NULL
712 && dest
->current_in_service
!= NULL
713 && (lowest
->current_in_service
->priority
714 > dest
->current_in_service
->priority
))
715 lowest
= dest
; /* less urgent */
716 /* FIXME - need to be more fair */
725 handle_interrupt(device
*me
,
726 hw_opic_device
*opic
,
727 opic_interrupt_source
*src
,
730 if (src
->is_masked
) {
731 DTRACE(opic
, ("interrupt %d - ignore masked\n", src
->nr
));
733 else if (src
->is_multicast
) {
734 /* always try to deliver multicast interrupts - just easier */
736 ASSERT(!src
->is_level_triggered
);
737 ASSERT(src
->is_positive_polarity
);
739 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
740 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
741 if (src
->destination
& dest
->bit
) {
742 if (src
->pending
& dest
->bit
) {
743 DTRACE(opic
, ("interrupt %d - multicast still pending to %d\n",
746 else if (can_deliver(me
, src
, dest
)) {
747 dest
->current_pending
= src
;
748 src
->pending
|= dest
->bit
;
749 assert_interrupt(me
, opic
, dest
);
750 DTRACE(opic
, ("interrupt %d - multicast to %d\n",
754 src
->pending
|= dest
->bit
;
755 DTRACE(opic
, ("interrupt %d - multicast pending to %d\n",
761 else if (src
->is_level_triggered
762 && src
->is_positive_polarity
765 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active high)\n",
768 DTRACE(opic
, ("interrupt %d - ignore low level (active high)\n",
770 ASSERT(!src
->is_multicast
);
773 else if (src
->is_level_triggered
774 && !src
->is_positive_polarity
777 DTRACE(opic
, ("interrupt %d - ignore withdrawn (active low)\n",
780 DTRACE(opic
, ("interrupt %d - ignore high level (active low)\n",
783 ASSERT(!src
->is_multicast
);
786 else if (!src
->is_level_triggered
787 && src
->is_positive_polarity
789 DTRACE(opic
, ("interrupt %d - ignore falling edge (positive edge trigered)\n",
792 else if (!src
->is_level_triggered
793 && !src
->is_positive_polarity
795 DTRACE(opic
, ("interrupt %d - ignore rising edge (negative edge trigered)\n",
798 else if (src
->in_service
!= 0) {
799 /* leave the interrupt where it is */
800 ASSERT(!src
->is_multicast
);
801 ASSERT(src
->pending
== 0 || src
->pending
== src
->in_service
);
802 src
->pending
= src
->in_service
;
803 DTRACE(opic
, ("interrupt %ld - ignore already in service to 0x%lx\n",
804 (long)src
->nr
, (long)src
->in_service
));
806 else if (src
->pending
!= 0) {
807 DTRACE(opic
, ("interrupt %ld - ignore still pending to 0x%lx\n",
808 (long)src
->nr
, (long)src
->pending
));
811 /* delivery is needed */
812 opic_interrupt_destination
*dest
= find_lowest_dest(me
, opic
, src
);
813 if (can_deliver(me
, src
, dest
)) {
814 dest
->current_pending
= src
;
815 src
->pending
= dest
->bit
;
816 DTRACE(opic
, ("interrupt %d - delivered to %d\n", src
->nr
, dest
->nr
));
817 assert_interrupt(me
, opic
, dest
);
820 src
->pending
= src
->destination
; /* any can take this */
821 DTRACE(opic
, ("interrupt %ld - pending to 0x%lx\n",
822 (long)src
->nr
, (long)src
->pending
));
828 do_interrupt_acknowledge_register_N_read(device
*me
,
829 hw_opic_device
*opic
,
832 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
835 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
836 ASSERT(dest_nr
== dest
->nr
);
838 /* try the current pending */
839 if (can_deliver(me
, dest
->current_pending
, dest
)) {
840 ASSERT(dest
->current_pending
->pending
& dest
->bit
);
841 vector
= deliver_pending(me
, opic
, dest
);
842 DTRACE(opic
, ("interrupt ack %d - entering %d (pending) - vector %d (%d), priority %d\n",
844 dest
->current_in_service
->nr
,
845 dest
->current_in_service
->vector
, vector
,
846 dest
->current_in_service
->priority
));
849 /* try for something else */
850 dest
->current_pending
= find_interrupt_for_dest(me
, opic
, dest
, pending_interrupt
);
851 if (can_deliver(me
, dest
->current_pending
, dest
)) {
852 vector
= deliver_pending(me
, opic
, dest
);
853 DTRACE(opic
, ("interrupt ack %d - entering %d (not pending) - vector %d (%d), priority %d\n",
855 dest
->current_in_service
->nr
,
856 dest
->current_in_service
->vector
, vector
,
857 dest
->current_in_service
->priority
));
860 dest
->current_pending
= NULL
;
861 vector
= opic
->spurious_vector
;
862 DTRACE(opic
, ("interrupt ack %d - spurious interrupt %d\n",
871 do_end_of_interrupt_register_N_write(device
*me
,
872 hw_opic_device
*opic
,
876 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[dest_nr
];
878 ASSERT(dest_nr
>= 0 && dest_nr
< opic
->nr_interrupt_destinations
);
879 ASSERT(dest_nr
== dest
->nr
);
881 /* check the value written is zero */
883 DTRACE(opic
, ("eoi %d - ignoring nonzero value\n", dest
->nr
));
886 /* user doing wierd things? */
887 if (dest
->current_in_service
== NULL
) {
888 DTRACE(opic
, ("eoi %d - strange, no current interrupt\n", dest
->nr
));
892 /* an internal stuff up? */
893 if (!(dest
->current_in_service
->in_service
& dest
->bit
)) {
894 device_error(me
, "eoi %d - current interrupt not in service", dest
->nr
);
897 /* find what was probably the previous in service interrupt */
898 dest
->current_in_service
->in_service
&= ~dest
->bit
;
899 DTRACE(opic
, ("eoi %d - ending %d - priority %d, vector %d\n",
901 dest
->current_in_service
->nr
,
902 dest
->current_in_service
->priority
,
903 dest
->current_in_service
->vector
));
904 dest
->current_in_service
= find_interrupt_for_dest(me
, opic
, dest
, in_service_interrupt
);
905 if (dest
->current_in_service
!= NULL
)
906 DTRACE(opic
, ("eoi %d - resuming %d - priority %d, vector %d\n",
908 dest
->current_in_service
->nr
,
909 dest
->current_in_service
->priority
,
910 dest
->current_in_service
->vector
));
912 DTRACE(opic
, ("eoi %d - resuming none\n", dest
->nr
));
914 /* check to see if that shouldn't be interrupted */
915 dest
->current_pending
= find_interrupt_for_dest(me
, opic
, dest
, pending_interrupt
);
916 if (can_deliver(me
, dest
->current_pending
, dest
)) {
917 ASSERT(dest
->current_pending
->pending
& dest
->bit
);
918 assert_interrupt(me
, opic
, dest
);
921 dest
->current_pending
= NULL
;
927 decode_opic_address(device
*me
,
928 hw_opic_device
*opic
,
930 unsigned_word address
,
937 /* is the size valid? */
939 *type
= invalid_opic_register
;
944 /* try for a per-processor register within the interrupt delivery
946 if (space
== opic
->idu
.space
947 && address
>= (opic
->idu
.address
+ idu_per_processor_register_base
)
948 && address
< (opic
->idu
.address
+ idu_per_processor_register_base
949 + (sizeof_idu_per_processor_register_block
950 * opic
->nr_interrupt_destinations
))) {
951 unsigned_word block_offset
= (address
953 - idu_per_processor_register_base
);
954 unsigned_word offset
= block_offset
% sizeof_idu_per_processor_register_block
;
955 *index
= block_offset
/ sizeof_idu_per_processor_register_block
;
958 *type
= ipi_N_dispatch_register
;
962 *type
= ipi_N_dispatch_register
;
966 *type
= ipi_N_dispatch_register
;
970 *type
= ipi_N_dispatch_register
;
974 *type
= current_task_priority_register_N
;
977 *type
= interrupt_acknowledge_register_N
;
980 *type
= end_of_interrupt_register_N
;
983 *type
= invalid_opic_register
;
986 DTRACE(opic
, ("per-processor register %d:0x%lx - %s[%d]\n",
987 space
, (unsigned long)address
,
988 opic_register_name(*type
),
993 /* try for an interrupt source unit */
994 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
995 if (opic
->isu_block
[isb
].space
== space
996 && address
>= opic
->isu_block
[isb
].address
997 && address
< (opic
->isu_block
[isb
].address
+ opic
->isu_block
[isb
].size
)) {
998 unsigned_word block_offset
= address
- opic
->isu_block
[isb
].address
;
999 unsigned_word offset
= block_offset
% sizeof_isu_register_block
;
1000 *index
= (opic
->isu_block
[isb
].int_number
1001 + (block_offset
/ sizeof_isu_register_block
));
1004 *type
= interrupt_source_N_vector_priority_register
;
1007 *type
= interrupt_source_N_destination_register
;
1010 *type
= invalid_opic_register
;
1013 DTRACE(opic
, ("isu register %d:0x%lx - %s[%d]\n",
1014 space
, (unsigned long)address
,
1015 opic_register_name(*type
),
1021 /* try for a timer */
1022 if (space
== opic
->idu
.space
1023 && address
>= (opic
->idu
.address
+ idu_timer_base
)
1024 && address
< (opic
->idu
.address
+ idu_timer_base
1025 + opic
->nr_timer_interrupts
* sizeof_timer_register_block
)) {
1026 unsigned_word offset
= address
% sizeof_timer_register_block
;
1027 *index
= ((address
- opic
->idu
.address
- idu_timer_base
)
1028 / sizeof_timer_register_block
);
1031 *type
= timer_N_current_count_register
;
1034 *type
= timer_N_base_count_register
;
1037 *type
= timer_N_vector_priority_register
;
1040 *type
= timer_N_destination_register
;
1043 *type
= invalid_opic_register
;
1046 DTRACE(opic
, ("timer register %d:0x%lx - %s[%d]\n",
1047 space
, (unsigned long)address
,
1048 opic_register_name(*type
),
1053 /* finally some other misc global register */
1054 if (space
== opic
->idu
.space
1055 && address
>= opic
->idu
.address
1056 && address
< opic
->idu
.address
+ opic
->idu
.size
) {
1057 unsigned_word block_offset
= address
- opic
->idu
.address
;
1058 switch (block_offset
) {
1060 *type
= timer_frequency_reporting_register
;
1064 *type
= spurious_vector_register
;
1071 *type
= ipi_N_vector_priority_register
;
1072 *index
= (block_offset
- 0x010a0) / 16;
1075 *type
= processor_init_register
;
1079 *type
= vendor_identification_register
;
1083 *type
= global_configuration_register_N
;
1087 *type
= feature_reporting_register_N
;
1091 *type
= invalid_opic_register
;
1095 DTRACE(opic
, ("global register %d:0x%lx - %s[%d]\n",
1096 space
, (unsigned long)address
,
1097 opic_register_name(*type
),
1102 /* nothing matched */
1103 *type
= invalid_opic_register
;
1104 DTRACE(opic
, ("invalid register %d:0x%lx\n",
1105 space
, (unsigned long)address
));
1110 /* Processor init register:
1112 The bits in this register (one per processor) are directly wired to
1113 output "init" interrupt ports. */
1116 do_processor_init_register_read(device
*me
,
1117 hw_opic_device
*opic
)
1119 unsigned reg
= opic
->init
;
1120 DTRACE(opic
, ("processor init register - read 0x%lx\n",
1126 do_processor_init_register_write(device
*me
,
1127 hw_opic_device
*opic
,
1131 for (i
= 0; i
< opic
->nr_interrupt_destinations
; i
++) {
1132 opic_interrupt_destination
*dest
= &opic
->interrupt_destination
[i
];
1133 if ((reg
& dest
->bit
) != (opic
->init
& dest
->bit
)) {
1134 if (reg
& dest
->bit
) {
1135 DTRACE(opic
, ("processor init register - write 0x%lx - asserting init%d\n",
1137 opic
->init
|= dest
->bit
;
1138 device_interrupt_event(me
, dest
->init_port
, 1, NULL
, 0);
1141 DTRACE(opic
, ("processor init register - write 0x%lx - negating init%d\n",
1143 opic
->init
&= ~dest
->bit
;
1144 device_interrupt_event(me
, dest
->init_port
, 0, NULL
, 0);
1152 /* Interrupt Source Vector/Priority Register: */
1155 read_vector_priority_register(device
*me
,
1156 hw_opic_device
*opic
,
1157 opic_interrupt_source
*interrupt
,
1158 const char *reg_name
,
1163 reg
|= interrupt
->is_masked
;
1164 reg
|= (interrupt
->in_service
|| interrupt
->pending
1165 ? isu_active_bit
: 0); /* active */
1166 reg
|= interrupt
->is_multicast
;
1167 reg
|= interrupt
->is_positive_polarity
;
1168 reg
|= interrupt
->is_level_triggered
; /* sense? */
1169 reg
|= interrupt
->priority
<< isu_priority_shift
;
1170 reg
|= interrupt
->vector
;
1171 DTRACE(opic
, ("%s %d vector/priority register - read 0x%lx\n",
1172 reg_name
, reg_index
, (unsigned long)reg
));
1177 do_interrupt_source_N_vector_priority_register_read(device
*me
,
1178 hw_opic_device
*opic
,
1182 ASSERT(index
< opic
->nr_external_interrupts
);
1183 reg
= read_vector_priority_register(me
, opic
,
1184 &opic
->interrupt_source
[index
],
1185 "interrupt source", index
);
1190 write_vector_priority_register(device
*me
,
1191 hw_opic_device
*opic
,
1192 opic_interrupt_source
*interrupt
,
1194 const char *reg_name
,
1197 interrupt
->is_masked
= (reg
& isu_mask_bit
);
1198 interrupt
->is_multicast
= (reg
& isu_multicast_bit
);
1199 interrupt
->is_positive_polarity
= (reg
& isu_positive_polarity_bit
);
1200 interrupt
->is_level_triggered
= (reg
& isu_level_triggered_bit
);
1201 interrupt
->priority
= ((reg
>> isu_priority_shift
)
1202 % max_nr_task_priorities
);
1203 interrupt
->vector
= (reg
& isu_vector_bits
);
1204 DTRACE(opic
, ("%s %d vector/priority register - write 0x%lx - %s%s%s-polarity, %s-triggered, priority %ld vector %ld\n",
1208 interrupt
->is_masked
? "masked, " : "",
1209 interrupt
->is_multicast
? "multicast, " : "",
1210 interrupt
->is_positive_polarity
? "positive" : "negative",
1211 interrupt
->is_level_triggered
? "level" : "edge",
1212 (long)interrupt
->priority
,
1213 (long)interrupt
->vector
));
1217 do_interrupt_source_N_vector_priority_register_write(device
*me
,
1218 hw_opic_device
*opic
,
1222 ASSERT(index
< opic
->nr_external_interrupts
);
1223 reg
&= ~isu_multicast_bit
; /* disable multicast */
1224 write_vector_priority_register(me
, opic
,
1225 &opic
->interrupt_source
[index
],
1226 reg
, "interrupt source", index
);
1231 /* Interrupt Source Destination Register: */
1234 read_destination_register(device
*me
,
1235 hw_opic_device
*opic
,
1236 opic_interrupt_source
*interrupt
,
1237 const char *reg_name
,
1241 reg
= interrupt
->destination
;
1242 DTRACE(opic
, ("%s %d destination register - read 0x%lx\n",
1243 reg_name
, reg_index
, reg
));
1248 do_interrupt_source_N_destination_register_read(device
*me
,
1249 hw_opic_device
*opic
,
1253 ASSERT(index
< opic
->nr_external_interrupts
);
1254 reg
= read_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1255 "interrupt source", index
);
1260 write_destination_register(device
*me
,
1261 hw_opic_device
*opic
,
1262 opic_interrupt_source
*interrupt
,
1264 const char *reg_name
,
1267 reg
&= (1 << opic
->nr_interrupt_destinations
) - 1; /* mask out invalid */
1268 DTRACE(opic
, ("%s %d destination register - write 0x%x\n",
1269 reg_name
, reg_index
, reg
));
1270 interrupt
->destination
= reg
;
1274 do_interrupt_source_N_destination_register_write(device
*me
,
1275 hw_opic_device
*opic
,
1279 ASSERT(index
< opic
->nr_external_interrupts
);
1280 write_destination_register(me
, opic
, &opic
->external_interrupt_source
[index
],
1281 reg
, "interrupt source", index
);
1286 /* Spurious vector register: */
1289 do_spurious_vector_register_read(device
*me
,
1290 hw_opic_device
*opic
)
1292 unsigned long reg
= opic
->spurious_vector
;
1293 DTRACE(opic
, ("spurious vector register - read 0x%lx\n", reg
));
1298 do_spurious_vector_register_write(device
*me
,
1299 hw_opic_device
*opic
,
1302 reg
&= 0xff; /* mask off invalid */
1303 DTRACE(opic
, ("spurious vector register - write 0x%x\n", reg
));
1304 opic
->spurious_vector
= reg
;
1309 /* current task priority register: */
1312 do_current_task_priority_register_N_read(device
*me
,
1313 hw_opic_device
*opic
,
1316 opic_interrupt_destination
*interrupt_destination
= &opic
->interrupt_destination
[index
];
1318 ASSERT(index
>= 0 && index
< opic
->nr_interrupt_destinations
);
1319 reg
= interrupt_destination
->base_priority
;
1320 DTRACE(opic
, ("current task priority register %d - read 0x%x\n", index
, reg
));
1325 do_current_task_priority_register_N_write(device
*me
,
1326 hw_opic_device
*opic
,
1330 opic_interrupt_destination
*interrupt_destination
= &opic
->interrupt_destination
[index
];
1331 ASSERT(index
>= 0 && index
< opic
->nr_interrupt_destinations
);
1332 reg
%= max_nr_task_priorities
;
1333 DTRACE(opic
, ("current task priority register %d - write 0x%x\n", index
, reg
));
1334 interrupt_destination
->base_priority
= reg
;
1339 /* Timer Frequency Reporting Register: */
1342 do_timer_frequency_reporting_register_read(device
*me
,
1343 hw_opic_device
*opic
)
1346 reg
= opic
->timer_frequency
;
1347 DTRACE(opic
, ("timer frequency reporting register - read 0x%x\n", reg
));
1352 do_timer_frequency_reporting_register_write(device
*me
,
1353 hw_opic_device
*opic
,
1356 DTRACE(opic
, ("timer frequency reporting register - write 0x%x\n", reg
));
1357 opic
->timer_frequency
= reg
;
1361 /* timer registers: */
1364 do_timer_N_current_count_register_read(device
*me
,
1365 hw_opic_device
*opic
,
1368 opic_timer
*timer
= &opic
->timer
[index
];
1370 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1371 if (timer
->inhibited
)
1372 reg
= timer
->count
; /* stalled value */
1374 reg
= timer
->count
- device_event_queue_time(me
); /* time remaining */
1375 DTRACE(opic
, ("timer %d current count register - read 0x%x\n", index
, reg
));
1381 do_timer_N_base_count_register_read(device
*me
,
1382 hw_opic_device
*opic
,
1385 opic_timer
*timer
= &opic
->timer
[index
];
1387 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1388 reg
= timer
->base_count
;
1389 DTRACE(opic
, ("timer %d base count register - read 0x%x\n", index
, reg
));
1395 timer_event(void *data
)
1397 opic_timer
*timer
= data
;
1398 device
*me
= timer
->me
;
1399 if (timer
->inhibited
)
1400 device_error(timer
->me
, "internal-error - timer event occured when timer %d inhibited",
1402 handle_interrupt(timer
->me
, timer
->opic
, timer
->interrupt_source
, 1);
1403 timer
->timeout_event
= device_event_queue_schedule(me
, timer
->base_count
,
1404 timer_event
, timer
);
1405 DTRACE(opic
, ("timer %d - interrupt at %ld, next at %d\n",
1406 timer
->nr
, (long)device_event_queue_time(me
), timer
->base_count
));
1411 do_timer_N_base_count_register_write(device
*me
,
1412 hw_opic_device
*opic
,
1416 opic_timer
*timer
= &opic
->timer
[index
];
1418 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1419 inhibit
= reg
& 0x80000000;
1420 if (timer
->inhibited
&& !inhibit
) {
1421 timer
->inhibited
= 0;
1422 if (timer
->timeout_event
!= NULL
)
1423 device_event_queue_deschedule(me
, timer
->timeout_event
);
1424 timer
->count
= device_event_queue_time(me
) + reg
;
1425 timer
->base_count
= reg
;
1426 timer
->timeout_event
= device_event_queue_schedule(me
, timer
->base_count
,
1427 timer_event
, (void*)timer
);
1428 DTRACE(opic
, ("timer %d base count register - write 0x%x - timer started\n",
1431 else if (!timer
->inhibited
&& inhibit
) {
1432 if (timer
->timeout_event
!= NULL
)
1433 device_event_queue_deschedule(me
, timer
->timeout_event
);
1434 timer
->count
= timer
->count
- device_event_queue_time(me
);
1435 timer
->inhibited
= 1;
1436 timer
->base_count
= reg
;
1437 DTRACE(opic
, ("timer %d base count register - write 0x%x - timer stopped\n",
1441 ASSERT((timer
->inhibited
&& inhibit
) || (!timer
->inhibited
&& !inhibit
));
1442 DTRACE(opic
, ("timer %d base count register - write 0x%x\n", index
, reg
));
1443 timer
->base_count
= reg
;
1449 do_timer_N_vector_priority_register_read(device
*me
,
1450 hw_opic_device
*opic
,
1454 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1455 reg
= read_vector_priority_register(me
, opic
,
1456 &opic
->timer_interrupt_source
[index
],
1462 do_timer_N_vector_priority_register_write(device
*me
,
1463 hw_opic_device
*opic
,
1467 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1468 reg
&= ~isu_level_triggered_bit
; /* force edge trigger */
1469 reg
|= isu_positive_polarity_bit
; /* force rising (positive) edge */
1470 reg
|= isu_multicast_bit
; /* force multicast */
1471 write_vector_priority_register(me
, opic
,
1472 &opic
->timer_interrupt_source
[index
],
1473 reg
, "timer", index
);
1478 do_timer_N_destination_register_read(device
*me
,
1479 hw_opic_device
*opic
,
1483 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1484 reg
= read_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1490 do_timer_N_destination_register_write(device
*me
,
1491 hw_opic_device
*opic
,
1495 ASSERT(index
>= 0 && index
< opic
->nr_timer_interrupts
);
1496 write_destination_register(me
, opic
, &opic
->timer_interrupt_source
[index
],
1497 reg
, "timer", index
);
1504 do_ipi_N_vector_priority_register_read(device
*me
,
1505 hw_opic_device
*opic
,
1509 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1510 reg
= read_vector_priority_register(me
, opic
,
1511 &opic
->interprocessor_interrupt_source
[index
],
1517 do_ipi_N_vector_priority_register_write(device
*me
,
1518 hw_opic_device
*opic
,
1522 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1523 reg
&= ~isu_level_triggered_bit
; /* force edge trigger */
1524 reg
|= isu_positive_polarity_bit
; /* force rising (positive) edge */
1525 reg
|= isu_multicast_bit
; /* force a multicast source */
1526 write_vector_priority_register(me
, opic
,
1527 &opic
->interprocessor_interrupt_source
[index
],
1532 do_ipi_N_dispatch_register_write(device
*me
,
1533 hw_opic_device
*opic
,
1537 opic_interrupt_source
*source
= &opic
->interprocessor_interrupt_source
[index
];
1538 ASSERT(index
>= 0 && index
< opic
->nr_interprocessor_interrupts
);
1539 DTRACE(opic
, ("ipi %d interrupt dispatch register - write 0x%x\n", index
, reg
));
1540 source
->destination
= reg
;
1541 handle_interrupt(me
, opic
, source
, 1);
1545 /* vendor and other global registers */
1548 do_vendor_identification_register_read(device
*me
,
1549 hw_opic_device
*opic
)
1552 reg
= opic
->vendor_identification
;
1553 DTRACE(opic
, ("vendor identification register - read 0x%x\n", reg
));
1558 do_feature_reporting_register_N_read(device
*me
,
1559 hw_opic_device
*opic
,
1566 reg
|= (opic
->nr_external_interrupts
<< 16);
1567 reg
|= (opic
->nr_interrupt_destinations
<< 8);
1568 reg
|= (2/*version 1.2*/);
1571 DTRACE(opic
, ("feature reporting register %d - read 0x%x\n", index
, reg
));
1576 do_global_configuration_register_N_read(device
*me
,
1577 hw_opic_device
*opic
,
1584 reg
|= gcr0_8259_bit
; /* hardwire 8259 disabled */
1587 DTRACE(opic
, ("global configuration register %d - read 0x%x\n", index
, reg
));
1592 do_global_configuration_register_N_write(device
*me
,
1593 hw_opic_device
*opic
,
1598 if (reg
& gcr0_reset_bit
) {
1599 DTRACE(opic
, ("global configuration register %d - write 0x%x - reseting opic\n", index
, reg
));
1600 hw_opic_init_data(me
);
1602 if (!(reg
& gcr0_8259_bit
)) {
1603 DTRACE(opic
, ("global configuration register %d - write 0x%x - ignoring 8259 enable\n", index
, reg
));
1609 /* register read-write */
1612 hw_opic_io_read_buffer(device
*me
,
1620 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1623 decode_opic_address(me
, opic
, space
, addr
, nr_bytes
, &type
, &index
);
1624 if (type
== invalid_opic_register
) {
1625 device_error(me
, "invalid opic read access to %d:0x%lx (%d bytes)",
1626 space
, (unsigned long)addr
, nr_bytes
);
1631 case processor_init_register
:
1632 reg
= do_processor_init_register_read(me
, opic
);
1634 case interrupt_source_N_vector_priority_register
:
1635 reg
= do_interrupt_source_N_vector_priority_register_read(me
, opic
, index
);
1637 case interrupt_source_N_destination_register
:
1638 reg
= do_interrupt_source_N_destination_register_read(me
, opic
, index
);
1640 case interrupt_acknowledge_register_N
:
1641 reg
= do_interrupt_acknowledge_register_N_read(me
, opic
, index
);
1643 case spurious_vector_register
:
1644 reg
= do_spurious_vector_register_read(me
, opic
);
1646 case current_task_priority_register_N
:
1647 reg
= do_current_task_priority_register_N_read(me
, opic
, index
);
1649 case timer_frequency_reporting_register
:
1650 reg
= do_timer_frequency_reporting_register_read(me
, opic
);
1652 case timer_N_current_count_register
:
1653 reg
= do_timer_N_current_count_register_read(me
, opic
, index
);
1655 case timer_N_base_count_register
:
1656 reg
= do_timer_N_base_count_register_read(me
, opic
, index
);
1658 case timer_N_vector_priority_register
:
1659 reg
= do_timer_N_vector_priority_register_read(me
, opic
, index
);
1661 case timer_N_destination_register
:
1662 reg
= do_timer_N_destination_register_read(me
, opic
, index
);
1664 case ipi_N_vector_priority_register
:
1665 reg
= do_ipi_N_vector_priority_register_read(me
, opic
, index
);
1667 case feature_reporting_register_N
:
1668 reg
= do_feature_reporting_register_N_read(me
, opic
, index
);
1670 case global_configuration_register_N
:
1671 reg
= do_global_configuration_register_N_read(me
, opic
, index
);
1673 case vendor_identification_register
:
1674 reg
= do_vendor_identification_register_read(me
, opic
);
1678 device_error(me
, "unimplemented read of register %s[%d]",
1679 opic_register_name(type
), index
);
1681 *(unsigned_4
*)dest
= H2LE_4(reg
);
1688 hw_opic_io_write_buffer(device
*me
,
1696 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1699 decode_opic_address(me
, opic
, space
, addr
, nr_bytes
, &type
, &index
);
1700 if (type
== invalid_opic_register
) {
1701 device_error(me
, "invalid opic write access to %d:0x%lx (%d bytes)",
1702 space
, (unsigned long)addr
, nr_bytes
);
1705 unsigned reg
= LE2H_4(*(unsigned_4
*)source
);
1707 case processor_init_register
:
1708 do_processor_init_register_write(me
, opic
, reg
);
1710 case interrupt_source_N_vector_priority_register
:
1711 do_interrupt_source_N_vector_priority_register_write(me
, opic
, index
, reg
);
1713 case interrupt_source_N_destination_register
:
1714 do_interrupt_source_N_destination_register_write(me
, opic
, index
, reg
);
1716 case end_of_interrupt_register_N
:
1717 do_end_of_interrupt_register_N_write(me
, opic
, index
, reg
);
1719 case spurious_vector_register
:
1720 do_spurious_vector_register_write(me
, opic
, reg
);
1722 case current_task_priority_register_N
:
1723 do_current_task_priority_register_N_write(me
, opic
, index
, reg
);
1725 case timer_frequency_reporting_register
:
1726 do_timer_frequency_reporting_register_write(me
, opic
, reg
);
1728 case timer_N_base_count_register
:
1729 do_timer_N_base_count_register_write(me
, opic
, index
, reg
);
1731 case timer_N_vector_priority_register
:
1732 do_timer_N_vector_priority_register_write(me
, opic
, index
, reg
);
1734 case timer_N_destination_register
:
1735 do_timer_N_destination_register_write(me
, opic
, index
, reg
);
1737 case ipi_N_dispatch_register
:
1738 do_ipi_N_dispatch_register_write(me
, opic
, index
, reg
);
1740 case ipi_N_vector_priority_register
:
1741 do_ipi_N_vector_priority_register_write(me
, opic
, index
, reg
);
1743 case global_configuration_register_N
:
1744 do_global_configuration_register_N_write(me
, opic
, index
, reg
);
1747 device_error(me
, "unimplemented write to register %s[%d]",
1748 opic_register_name(type
), index
);
1756 hw_opic_interrupt_event(device
*me
,
1764 hw_opic_device
*opic
= (hw_opic_device
*)device_data(me
);
1769 /* find the corresponding internal input port */
1770 for (isb
= 0; isb
< opic
->nr_isu_blocks
; isb
++) {
1771 if (my_port
>= opic
->isu_block
[isb
].int_number
1772 && my_port
< opic
->isu_block
[isb
].int_number
+ opic
->isu_block
[isb
].range
) {
1773 src_nr
+= my_port
- opic
->isu_block
[isb
].int_number
;
1777 src_nr
+= opic
->isu_block
[isb
].range
;
1779 if (isb
== opic
->nr_isu_blocks
)
1780 device_error(me
, "interrupt %d out of range", my_port
);
1781 DTRACE(opic
, ("external-interrupt %d, internal %d, level %d\n",
1782 my_port
, src_nr
, level
));
1785 ASSERT(src_nr
>= 0 && src_nr
< opic
->nr_external_interrupts
);
1786 handle_interrupt(me
, opic
, &opic
->external_interrupt_source
[src_nr
], level
);
1790 static const device_interrupt_port_descriptor hw_opic_interrupt_ports
[] = {
1791 { "irq", 0, max_nr_interrupt_sources
, input_port
, },
1792 { "intr", 0, max_nr_interrupt_destinations
, output_port
, },
1793 { "init", max_nr_interrupt_destinations
, max_nr_interrupt_destinations
, output_port
, },
1798 static device_callbacks
const hw_opic_callbacks
= {
1799 { generic_device_init_address
,
1800 hw_opic_init_data
},
1801 { NULL
, }, /* address */
1802 { hw_opic_io_read_buffer
,
1803 hw_opic_io_write_buffer
}, /* IO */
1804 { NULL
, }, /* DMA */
1805 { hw_opic_interrupt_event
, NULL
, hw_opic_interrupt_ports
}, /* interrupt */
1806 { NULL
, }, /* unit */
1807 NULL
, /* instance */
1811 hw_opic_create(const char *name
,
1812 const device_unit
*unit_address
,
1815 hw_opic_device
*opic
= ZALLOC(hw_opic_device
);
1821 const device_descriptor hw_opic_device_descriptor
[] = {
1822 { "opic", hw_opic_create
, &hw_opic_callbacks
},
1826 #endif /* _HW_OPIC_C_ */