New Romanian translation for ld
[binutils-gdb.git] / sim / ppc / hw_opic.c
blob42474115a717add336d3543395d42487c2a2f15d
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/>.
21 #ifndef _HW_OPIC_C_
22 #define _HW_OPIC_C_
24 #include "device_table.h"
26 #include <string.h>
29 /* DEVICE
32 opic - Open Programmable Interrupt Controller (OpenPIC)
35 DESCRIPTION
38 This device implements the core of the OpenPIC interrupt controller
39 as described in the OpenPIC specification 1.2 and other related
40 documents.
42 The model includes:
44 o Up to 2048 external interrupt sources
46 o The four count down timers
48 o The four interprocessor multicast interrupts
50 o multiprocessor support
52 o Full tracing to assist help debugging
54 o Support for all variations of edge/level x high/low polarity.
58 PROPERTIES
61 reg = <address> <size> ... (required)
63 Determine where the device lives in the parents address space. The
64 first <<address>> <<size>> pair specifies the address of the
65 interrupt destination unit (which might contain an interrupt source
66 unit) while successive reg entries specify additional interrupt
67 source units.
69 Note that for an <<opic>> device attached to a <<pci>> bus, the
70 first <<reg>> entry may need to be ignored it will be the address
71 of the devices configuration registers.
74 interrupt-ranges = <int-number> <range> ... (required)
76 A list of pairs. Each pair corresponds to a block of interrupt
77 source units (the address of which being specified by the
78 corresponding reg tupple). <<int-number>> is the number of the
79 first interrupt in the block while <<range>> is the number of
80 interrupts in the block.
83 timer-frequency = <integer> (optional)
85 If present, specifies the default value of the timer frequency
86 reporting register. By default a value of 1 HZ is used. The value
87 is arbitrary, the timers are always updated once per machine cycle.
90 vendor-identification = <integer> (optional)
92 If present, specifies the value to be returned when the vendor
93 identification register is read.
96 EXAMPLES
99 See the test suite directory:
101 | psim-test/hw-opic
104 BUGS
106 For an OPIC controller attached to a PCI bus, it is not clear what
107 the value of the <<reg>> and <<interrupt-ranges>> properties should
108 be. In particular, the PCI firmware bindings require the first
109 value of the <<reg>> property to specify the devices configuration
110 address while the OpenPIC bindings require that same entry to
111 specify the address of the Interrupt Delivery Unit. This
112 implementation checks for and, if present, ignores any
113 configuration address (and its corresponding <<interrupt-ranges>>
114 entry).
116 The OpenPIC specification requires the controller to be fair when
117 distributing interrupts between processors. At present the
118 algorithm used isn't fair. It is biased towards processor zero.
120 The OpenPIC specification includes a 8259 pass through mode. This
121 is not supported.
124 REFERENCES
127 PowerPC Multiprocessor Interrupt Controller (MPIC), January 19,
128 1996. Available from IBM.
131 The Open Programmable Interrupt Controller (PIC) Register Interface
132 Specification Revision 1.2. Issue Date: Opctober 1995. Available
133 somewhere on AMD's web page (http://www.amd.com/)
136 PowerPC Microprocessor Common Hardware Reference Platform (CHRP)
137 System bindings to: IEEE Std 1275-1994 Standard for Boot
138 (Initialization, Configuration) Firmware. Revision 1.2b (INTERIM
139 DRAFT). April 22, 1996. Available on the Open Firmware web site
140 http://playground.sun.com/p1275/.
146 /* forward types */
148 typedef struct _hw_opic_device hw_opic_device;
151 /* bounds */
153 enum {
154 max_nr_interrupt_sources = 2048,
155 max_nr_interrupt_destinations = 32,
156 max_nr_task_priorities = 16,
160 enum {
161 opic_alignment = 16,
165 /* global configuration register */
167 enum {
168 gcr0_8259_bit = 0x20000000,
169 gcr0_reset_bit = 0x80000000,
173 /* offsets and sizes */
175 enum {
176 idu_isu_base = 0x10000,
177 sizeof_isu_register_block = 32,
178 idu_per_processor_register_base = 0x20000,
179 sizeof_idu_per_processor_register_block = 0x1000,
180 idu_timer_base = 0x01100,
181 sizeof_timer_register_block = 0x00040,
185 /* Interrupt sources */
187 enum {
188 isu_mask_bit = 0x80000000,
189 isu_active_bit = 0x40000000,
190 isu_multicast_bit = 0x20000000,
191 isu_positive_polarity_bit = 0x00800000,
192 isu_level_triggered_bit = 0x00400000,
193 isu_priority_shift = 16,
194 isu_vector_bits = 0x000000ff,
198 typedef struct _opic_interrupt_source {
199 unsigned is_masked; /* left in place */
200 unsigned is_multicast; /* left in place */
201 unsigned is_positive_polarity; /* left in place */
202 unsigned is_level_triggered; /* left in place */
203 unsigned priority;
204 unsigned vector;
205 /* misc */
206 int nr;
207 unsigned destination;
208 unsigned pending;
209 unsigned in_service;
210 } opic_interrupt_source;
213 /* interrupt destinations (normally processors) */
215 typedef struct _opic_interrupt_destination {
216 int nr;
217 unsigned base_priority;
218 opic_interrupt_source *current_pending;
219 opic_interrupt_source *current_in_service;
220 unsigned bit;
221 int init_port;
222 int intr_port;
223 } opic_interrupt_destination;
226 /* address map descriptors */
228 typedef struct _opic_isu_block { /* interrupt source unit block */
229 int space;
230 unsigned_word address;
231 unsigned size;
232 unsigned_cell int_number;
233 unsigned_cell range;
234 int reg;
235 } opic_isu_block;
238 typedef struct _opic_idu { /* interrupt delivery unit */
239 int reg;
240 int space;
241 unsigned_word address;
242 unsigned size;
243 } opic_idu;
245 typedef enum {
246 /* bad */
247 invalid_opic_register,
248 /* interrupt source */
249 interrupt_source_N_destination_register,
250 interrupt_source_N_vector_priority_register,
251 /* timers */
252 timer_N_destination_register,
253 timer_N_vector_priority_register,
254 timer_N_base_count_register,
255 timer_N_current_count_register,
256 timer_frequency_reporting_register,
257 /* inter-processor interrupts */
258 ipi_N_vector_priority_register,
259 ipi_N_dispatch_register,
260 /* global configuration */
261 spurious_vector_register,
262 processor_init_register,
263 vendor_identification_register,
264 global_configuration_register_N,
265 feature_reporting_register_N,
266 /* per processor */
267 end_of_interrupt_register_N,
268 interrupt_acknowledge_register_N,
269 current_task_priority_register_N,
270 } opic_register;
272 static const char *
273 opic_register_name(opic_register type)
275 switch (type) {
276 case invalid_opic_register: return "invalid_opic_register";
277 case interrupt_source_N_destination_register: return "interrupt_source_N_destination_register";
278 case interrupt_source_N_vector_priority_register: return "interrupt_source_N_vector_priority_register";
279 case timer_N_destination_register: return "timer_N_destination_register";
280 case timer_N_vector_priority_register: return "timer_N_vector_priority_register";
281 case timer_N_base_count_register: return "timer_N_base_count_register";
282 case timer_N_current_count_register: return "timer_N_current_count_register";
283 case timer_frequency_reporting_register: return "timer_frequency_reporting_register";
284 case ipi_N_vector_priority_register: return "ipi_N_vector_priority_register";
285 case ipi_N_dispatch_register: return "ipi_N_dispatch_register";
286 case spurious_vector_register: return "spurious_vector_register";
287 case processor_init_register: return "processor_init_register";
288 case vendor_identification_register: return "vendor_identification_register";
289 case global_configuration_register_N: return "global_configuration_register_N";
290 case feature_reporting_register_N: return "feature_reporting_register_N";
291 case end_of_interrupt_register_N: return "end_of_interrupt_register_N";
292 case interrupt_acknowledge_register_N: return "interrupt_acknowledge_register_N";
293 case current_task_priority_register_N: return "current_task_priority_register_N";
295 return NULL;
300 /* timers */
302 typedef struct _opic_timer {
303 int nr;
304 device *me; /* find my way home */
305 hw_opic_device *opic; /* ditto */
306 unsigned base_count;
307 int inhibited;
308 int64_t count; /* *ONLY* if inhibited */
309 event_entry_tag timeout_event;
310 opic_interrupt_source *interrupt_source;
311 } opic_timer;
314 /* the OPIC */
316 struct _hw_opic_device {
318 /* vendor id */
319 unsigned vendor_identification;
321 /* interrupt destinations - processors */
322 int nr_interrupt_destinations;
323 opic_interrupt_destination *interrupt_destination;
324 unsigned sizeof_interrupt_destination;
326 /* bogus interrupts */
327 int spurious_vector;
329 /* interrupt sources - external interrupt source units + extra internal ones */
330 int nr_interrupt_sources;
331 opic_interrupt_source *interrupt_source;
332 unsigned sizeof_interrupt_source;
334 /* external interrupts */
335 int nr_external_interrupts;
336 opic_interrupt_source *external_interrupt_source;
338 /* inter-processor-interrupts */
339 int nr_interprocessor_interrupts;
340 opic_interrupt_source *interprocessor_interrupt_source;
342 /* timers */
343 int nr_timer_interrupts;
344 opic_timer *timer;
345 unsigned sizeof_timer;
346 opic_interrupt_source *timer_interrupt_source;
347 unsigned timer_frequency;
349 /* init register */
350 uint32_t init;
352 /* address maps */
353 opic_idu idu;
354 int nr_isu_blocks;
355 opic_isu_block *isu_block;
359 static void
360 hw_opic_init_data(device *me)
362 hw_opic_device *opic = (hw_opic_device*)device_data(me);
363 int isb;
364 int idu_reg;
365 int nr_isu_blocks;
366 int i;
368 /* determine the first valid reg property entry (there could be
369 leading reg entries with invalid (zero) size fields) and the
370 number of isu entries found in the reg property. */
371 idu_reg = 0;
372 nr_isu_blocks = 0;
373 while (1) {
374 reg_property_spec unit;
375 int attach_space;
376 unsigned_word attach_address;
377 unsigned attach_size;
378 if (!device_find_reg_array_property(me, "reg", idu_reg + nr_isu_blocks,
379 &unit))
380 break;
381 if (nr_isu_blocks > 0
382 || (device_address_to_attach_address(device_parent(me), &unit.address,
383 &attach_space, &attach_address,
385 && device_size_to_attach_size(device_parent(me), &unit.size,
386 &attach_size,
387 me))) {
388 /* we count any thing once we've found one valid address/size pair */
389 nr_isu_blocks += 1;
391 else {
392 idu_reg += 1;
396 /* determine the number and location of the multiple interrupt
397 source units and the single interrupt delivery unit */
398 if (opic->isu_block == NULL) {
399 int reg_nr;
400 opic->nr_isu_blocks = nr_isu_blocks;
401 opic->isu_block = zalloc(sizeof(opic_isu_block) * opic->nr_isu_blocks);
402 isb = 0;
403 reg_nr = idu_reg;
404 while (isb < opic->nr_isu_blocks) {
405 reg_property_spec reg;
406 if (!device_find_reg_array_property(me, "reg", reg_nr, &reg))
407 device_error(me, "reg property missing entry number %d", reg_nr);
408 opic->isu_block[isb].reg = reg_nr;
409 if (!device_address_to_attach_address(device_parent(me), &reg.address,
410 &opic->isu_block[isb].space,
411 &opic->isu_block[isb].address,
413 || !device_size_to_attach_size(device_parent(me), &reg.size,
414 &opic->isu_block[isb].size,
415 me)) {
416 device_error(me, "reg property entry %d invalid", reg_nr);
418 if (!device_find_integer_array_property(me, "interrupt-ranges",
419 reg_nr * 2,
420 (signed_cell *)
421 &opic->isu_block[isb].int_number)
422 || !device_find_integer_array_property(me, "interrupt-ranges",
423 reg_nr * 2 + 1,
424 (signed_cell *)
425 &opic->isu_block[isb].range))
426 device_error(me, "missing or invalid interrupt-ranges property entry %d", reg_nr);
427 /* first reg entry specifies the address of both the IDU and the
428 first set of ISU registers, adjust things accordingly */
429 if (reg_nr == idu_reg) {
430 opic->idu.reg = opic->isu_block[isb].reg;
431 opic->idu.space = opic->isu_block[isb].space;
432 opic->idu.address = opic->isu_block[isb].address;
433 opic->idu.size = opic->isu_block[isb].size;
434 opic->isu_block[isb].address += idu_isu_base;
435 opic->isu_block[isb].size = opic->isu_block[isb].range * (16 + 16);
437 /* was this a valid reg entry? */
438 if (opic->isu_block[isb].range == 0) {
439 opic->nr_isu_blocks -= 1;
441 else {
442 opic->nr_external_interrupts += opic->isu_block[isb].range;
443 isb++;
445 reg_nr++;
448 DTRACE(opic, ("interrupt source unit block - effective number of blocks %d\n",
449 (int)opic->nr_isu_blocks));
452 /* the number of other interrupts */
453 opic->nr_interprocessor_interrupts = 4;
454 opic->nr_timer_interrupts = 4;
457 /* create space for the interrupt source registers */
458 if (opic->interrupt_source != NULL) {
459 memset(opic->interrupt_source, 0, opic->sizeof_interrupt_source);
461 else {
462 opic->nr_interrupt_sources = (opic->nr_external_interrupts
463 + opic->nr_interprocessor_interrupts
464 + opic->nr_timer_interrupts);
465 if (opic->nr_interrupt_sources > max_nr_interrupt_sources)
466 device_error(me, "number of interrupt sources exceeded");
467 opic->sizeof_interrupt_source = (sizeof(opic_interrupt_source)
468 * opic->nr_interrupt_sources);
469 opic->interrupt_source = zalloc(opic->sizeof_interrupt_source);
470 opic->external_interrupt_source = opic->interrupt_source;
471 opic->interprocessor_interrupt_source = (opic->external_interrupt_source
472 + opic->nr_external_interrupts);
473 opic->timer_interrupt_source = (opic->interprocessor_interrupt_source
474 + opic->nr_interprocessor_interrupts);
476 for (i = 0; i < opic->nr_interrupt_sources; i++) {
477 opic_interrupt_source *source = &opic->interrupt_source[i];
478 source->nr = i;
479 source->is_masked = isu_mask_bit;
481 DTRACE(opic, ("interrupt sources - external %d, timer %d, ipi %d, total %d\n",
482 opic->nr_external_interrupts,
483 opic->nr_timer_interrupts,
484 opic->nr_interprocessor_interrupts,
485 opic->nr_interrupt_sources));
488 /* timers or interprocessor interrupts */
489 if (opic->timer != NULL)
490 memset(opic->timer, 0, opic->sizeof_timer);
491 else {
492 opic->nr_timer_interrupts = 4;
493 opic->sizeof_timer = sizeof(opic_timer) * opic->nr_timer_interrupts;
494 opic->timer = zalloc(opic->sizeof_timer);
496 for (i = 0; i < opic->nr_timer_interrupts; i++) {
497 opic_timer *timer = &opic->timer[i];
498 timer->nr = i;
499 timer->me = me;
500 timer->opic = opic;
501 timer->inhibited = 1;
502 timer->interrupt_source = &opic->timer_interrupt_source[i];
504 if (device_find_property(me, "timer-frequency"))
505 opic->timer_frequency = device_find_integer_property(me, "timer-frequency");
506 else
507 opic->timer_frequency = 1;
510 /* create space for the interrupt destination registers */
511 if (opic->interrupt_destination != NULL) {
512 memset(opic->interrupt_destination, 0, opic->sizeof_interrupt_destination);
514 else {
515 opic->nr_interrupt_destinations = tree_find_integer_property(me, "/openprom/options/smp");
516 opic->sizeof_interrupt_destination = (sizeof(opic_interrupt_destination)
517 * opic->nr_interrupt_destinations);
518 opic->interrupt_destination = zalloc(opic->sizeof_interrupt_destination);
519 if (opic->nr_interrupt_destinations > max_nr_interrupt_destinations)
520 device_error(me, "number of interrupt destinations exceeded");
522 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
523 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
524 dest->bit = (1 << i);
525 dest->nr = i;
526 dest->init_port = (device_interrupt_decode(me, "init0", output_port)
527 + i);
528 dest->intr_port = (device_interrupt_decode(me, "intr0", output_port)
529 + i);
530 dest->base_priority = max_nr_task_priorities - 1;
532 DTRACE(opic, ("interrupt destinations - total %d\n",
533 (int)opic->nr_interrupt_destinations));
536 /* verify and print out the ISU's */
537 for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
538 unsigned correct_size;
539 if ((opic->isu_block[isb].address % opic_alignment) != 0)
540 device_error(me, "interrupt source unit %d address not aligned to %d byte boundary",
541 isb, opic_alignment);
542 correct_size = opic->isu_block[isb].range * sizeof_isu_register_block;
543 if (opic->isu_block[isb].size != correct_size)
544 device_error(me, "interrupt source unit %d (reg %d) has an incorrect size, should be 0x%x",
545 isb, opic->isu_block[isb].reg, correct_size);
546 DTRACE(opic, ("interrupt source unit block %ld - address %d:0x%lx, size 0x%lx, int-number %ld, range %ld\n",
547 (long)isb,
548 (int)opic->isu_block[isb].space,
549 (unsigned long)opic->isu_block[isb].address,
550 (unsigned long)opic->isu_block[isb].size,
551 (long)opic->isu_block[isb].int_number,
552 (long)opic->isu_block[isb].range));
556 /* verify and print out the IDU */
558 unsigned correct_size;
559 unsigned alternate_size;
560 if ((opic->idu.address % opic_alignment) != 0)
561 device_error(me, "interrupt delivery unit not aligned to %d byte boundary",
562 opic_alignment);
563 correct_size = (idu_per_processor_register_base
564 + (sizeof_idu_per_processor_register_block
565 * opic->nr_interrupt_destinations));
566 alternate_size = (idu_per_processor_register_base
567 + (sizeof_idu_per_processor_register_block
568 * max_nr_interrupt_destinations));
569 if (opic->idu.size != correct_size
570 && opic->idu.size != alternate_size)
571 device_error(me, "interrupt delivery unit has incorrect size, should be 0x%x or 0x%x",
572 correct_size, alternate_size);
573 DTRACE(opic, ("interrupt delivery unit - address %d:0x%lx, size 0x%lx\n",
574 (int)opic->idu.space,
575 (unsigned long)opic->idu.address,
576 (unsigned long)opic->idu.size));
579 /* initialize the init interrupts */
580 opic->init = 0;
583 /* vendor ident */
584 if (device_find_property(me, "vendor-identification") != NULL)
585 opic->vendor_identification = device_find_integer_property(me, "vendor-identification");
586 else
587 opic->vendor_identification = 0;
589 /* misc registers */
590 opic->spurious_vector = 0xff;
595 /* interrupt related actions */
597 static void
598 assert_interrupt(device *me,
599 hw_opic_device *opic,
600 opic_interrupt_destination *dest)
602 ASSERT(dest >= opic->interrupt_destination);
603 ASSERT(dest < opic->interrupt_destination + opic->nr_interrupt_destinations);
604 DTRACE(opic, ("assert interrupt - intr port %d\n", dest->intr_port));
605 device_interrupt_event(me, dest->intr_port, 1, NULL, 0);
609 static void
610 negate_interrupt(device *me,
611 hw_opic_device *opic,
612 opic_interrupt_destination *dest)
614 ASSERT(dest >= opic->interrupt_destination);
615 ASSERT(dest < opic->interrupt_destination + opic->nr_interrupt_destinations);
616 DTRACE(opic, ("negate interrupt - intr port %d\n", dest->intr_port));
617 device_interrupt_event(me, dest->intr_port, 0, NULL, 0);
621 static int
622 can_deliver(device *me,
623 opic_interrupt_source *source,
624 opic_interrupt_destination *dest)
626 return (source != NULL && dest != NULL
627 && source->priority > dest->base_priority
628 && (dest->current_in_service == NULL
629 || source->priority > dest->current_in_service->priority));
633 static unsigned
634 deliver_pending(device *me,
635 hw_opic_device *opic,
636 opic_interrupt_destination *dest)
638 ASSERT(can_deliver(me, dest->current_pending, dest));
639 dest->current_in_service = dest->current_pending;
640 dest->current_in_service->in_service |= dest->bit;
641 if (!dest->current_pending->is_level_triggered) {
642 if (dest->current_pending->is_multicast)
643 dest->current_pending->pending &= ~dest->bit;
644 else
645 dest->current_pending->pending = 0;
647 dest->current_pending = NULL;
648 negate_interrupt(me, opic, dest);
649 return dest->current_in_service->vector;
653 typedef enum {
654 pending_interrupt,
655 in_service_interrupt,
656 } interrupt_class;
658 static opic_interrupt_source *
659 find_interrupt_for_dest(device *me,
660 hw_opic_device *opic,
661 opic_interrupt_destination *dest,
662 interrupt_class class)
664 int i;
665 opic_interrupt_source *pending = NULL;
666 for (i = 0; i < opic->nr_interrupt_sources; i++) {
667 opic_interrupt_source *src = &opic->interrupt_source[i];
668 /* is this a potential hit? */
669 switch (class) {
670 case in_service_interrupt:
671 if ((src->in_service & dest->bit) == 0)
672 continue;
673 break;
674 case pending_interrupt:
675 if ((src->pending & dest->bit) == 0)
676 continue;
677 break;
679 /* see if it is the highest priority */
680 if (pending == NULL)
681 pending = src;
682 else if (src->priority > pending->priority)
683 pending = src;
685 return pending;
689 static opic_interrupt_destination *
690 find_lowest_dest(device *me,
691 hw_opic_device *opic,
692 opic_interrupt_source *src)
694 int i;
695 opic_interrupt_destination *lowest = NULL;
696 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
697 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
698 if (src->destination & dest->bit) {
699 if (dest->base_priority < src->priority) {
700 if (lowest == NULL)
701 lowest = dest;
702 else if (lowest->base_priority > dest->base_priority)
703 lowest = dest;
704 else if (lowest->current_in_service != NULL
705 && dest->current_in_service == NULL)
706 lowest = dest; /* not doing anything */
707 else if (lowest->current_in_service != NULL
708 && dest->current_in_service != NULL
709 && (lowest->current_in_service->priority
710 > dest->current_in_service->priority))
711 lowest = dest; /* less urgent */
712 /* FIXME - need to be more fair */
716 return lowest;
720 static void
721 handle_interrupt(device *me,
722 hw_opic_device *opic,
723 opic_interrupt_source *src,
724 int asserted)
726 if (src->is_masked) {
727 DTRACE(opic, ("interrupt %d - ignore masked\n", src->nr));
729 else if (src->is_multicast) {
730 /* always try to deliver multicast interrupts - just easier */
731 int i;
732 ASSERT(!src->is_level_triggered);
733 ASSERT(src->is_positive_polarity);
734 ASSERT(asserted);
735 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
736 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
737 if (src->destination & dest->bit) {
738 if (src->pending & dest->bit) {
739 DTRACE(opic, ("interrupt %d - multicast still pending to %d\n",
740 src->nr, dest->nr));
742 else if (can_deliver(me, src, dest)) {
743 dest->current_pending = src;
744 src->pending |= dest->bit;
745 assert_interrupt(me, opic, dest);
746 DTRACE(opic, ("interrupt %d - multicast to %d\n",
747 src->nr, dest->nr));
749 else {
750 src->pending |= dest->bit;
751 DTRACE(opic, ("interrupt %d - multicast pending to %d\n",
752 src->nr, dest->nr));
757 else if (src->is_level_triggered
758 && src->is_positive_polarity
759 && !asserted) {
760 if (src->pending)
761 DTRACE(opic, ("interrupt %d - ignore withdrawn (active high)\n",
762 src->nr));
763 else
764 DTRACE(opic, ("interrupt %d - ignore low level (active high)\n",
765 src->nr));
766 ASSERT(!src->is_multicast);
767 src->pending = 0;
769 else if (src->is_level_triggered
770 && !src->is_positive_polarity
771 && asserted) {
772 if (src->pending)
773 DTRACE(opic, ("interrupt %d - ignore withdrawn (active low)\n",
774 src->nr));
775 else
776 DTRACE(opic, ("interrupt %d - ignore high level (active low)\n",
777 src->nr));
779 ASSERT(!src->is_multicast);
780 src->pending = 0;
782 else if (!src->is_level_triggered
783 && src->is_positive_polarity
784 && !asserted) {
785 DTRACE(opic, ("interrupt %d - ignore falling edge (positive edge trigered)\n",
786 src->nr));
788 else if (!src->is_level_triggered
789 && !src->is_positive_polarity
790 && asserted) {
791 DTRACE(opic, ("interrupt %d - ignore rising edge (negative edge trigered)\n",
792 src->nr));
794 else if (src->in_service != 0) {
795 /* leave the interrupt where it is */
796 ASSERT(!src->is_multicast);
797 ASSERT(src->pending == 0 || src->pending == src->in_service);
798 src->pending = src->in_service;
799 DTRACE(opic, ("interrupt %ld - ignore already in service to 0x%lx\n",
800 (long)src->nr, (long)src->in_service));
802 else if (src->pending != 0) {
803 DTRACE(opic, ("interrupt %ld - ignore still pending to 0x%lx\n",
804 (long)src->nr, (long)src->pending));
806 else {
807 /* delivery is needed */
808 opic_interrupt_destination *dest = find_lowest_dest(me, opic, src);
809 if (can_deliver(me, src, dest)) {
810 dest->current_pending = src;
811 src->pending = dest->bit;
812 DTRACE(opic, ("interrupt %d - delivered to %d\n", src->nr, dest->nr));
813 assert_interrupt(me, opic, dest);
815 else {
816 src->pending = src->destination; /* any can take this */
817 DTRACE(opic, ("interrupt %ld - pending to 0x%lx\n",
818 (long)src->nr, (long)src->pending));
823 static unsigned
824 do_interrupt_acknowledge_register_N_read(device *me,
825 hw_opic_device *opic,
826 int dest_nr)
828 opic_interrupt_destination *dest = &opic->interrupt_destination[dest_nr];
829 unsigned vector;
831 ASSERT(dest_nr >= 0 && dest_nr < opic->nr_interrupt_destinations);
832 ASSERT(dest_nr == dest->nr);
834 /* try the current pending */
835 if (can_deliver(me, dest->current_pending, dest)) {
836 ASSERT(dest->current_pending->pending & dest->bit);
837 vector = deliver_pending(me, opic, dest);
838 DTRACE(opic, ("interrupt ack %d - entering %d (pending) - vector %d (%d), priority %d\n",
839 dest->nr,
840 dest->current_in_service->nr,
841 dest->current_in_service->vector, vector,
842 dest->current_in_service->priority));
844 else {
845 /* try for something else */
846 dest->current_pending = find_interrupt_for_dest(me, opic, dest, pending_interrupt);
847 if (can_deliver(me, dest->current_pending, dest)) {
848 vector = deliver_pending(me, opic, dest);
849 DTRACE(opic, ("interrupt ack %d - entering %d (not pending) - vector %d (%d), priority %d\n",
850 dest->nr,
851 dest->current_in_service->nr,
852 dest->current_in_service->vector, vector,
853 dest->current_in_service->priority));
855 else {
856 dest->current_pending = NULL;
857 vector = opic->spurious_vector;
858 DTRACE(opic, ("interrupt ack %d - spurious interrupt %d\n",
859 dest->nr, vector));
862 return vector;
866 static void
867 do_end_of_interrupt_register_N_write(device *me,
868 hw_opic_device *opic,
869 int dest_nr,
870 unsigned reg)
872 opic_interrupt_destination *dest = &opic->interrupt_destination[dest_nr];
874 ASSERT(dest_nr >= 0 && dest_nr < opic->nr_interrupt_destinations);
875 ASSERT(dest_nr == dest->nr);
877 /* check the value written is zero */
878 if (reg != 0) {
879 DTRACE(opic, ("eoi %d - ignoring nonzero value\n", dest->nr));
882 /* user doing wierd things? */
883 if (dest->current_in_service == NULL) {
884 DTRACE(opic, ("eoi %d - strange, no current interrupt\n", dest->nr));
885 return;
888 /* an internal stuff up? */
889 if (!(dest->current_in_service->in_service & dest->bit)) {
890 device_error(me, "eoi %d - current interrupt not in service", dest->nr);
893 /* find what was probably the previous in service interrupt */
894 dest->current_in_service->in_service &= ~dest->bit;
895 DTRACE(opic, ("eoi %d - ending %d - priority %d, vector %d\n",
896 dest->nr,
897 dest->current_in_service->nr,
898 dest->current_in_service->priority,
899 dest->current_in_service->vector));
900 dest->current_in_service = find_interrupt_for_dest(me, opic, dest, in_service_interrupt);
901 if (dest->current_in_service != NULL)
902 DTRACE(opic, ("eoi %d - resuming %d - priority %d, vector %d\n",
903 dest->nr,
904 dest->current_in_service->nr,
905 dest->current_in_service->priority,
906 dest->current_in_service->vector));
907 else
908 DTRACE(opic, ("eoi %d - resuming none\n", dest->nr));
910 /* check to see if that shouldn't be interrupted */
911 dest->current_pending = find_interrupt_for_dest(me, opic, dest, pending_interrupt);
912 if (can_deliver(me, dest->current_pending, dest)) {
913 ASSERT(dest->current_pending->pending & dest->bit);
914 assert_interrupt(me, opic, dest);
916 else {
917 dest->current_pending = NULL;
922 static void
923 decode_opic_address(device *me,
924 hw_opic_device *opic,
925 int space,
926 unsigned_word address,
927 unsigned nr_bytes,
928 opic_register *type,
929 int *index)
931 int isb = 0;
933 /* is the size valid? */
934 if (nr_bytes != 4) {
935 *type = invalid_opic_register;
936 *index = -1;
937 return;
940 /* try for a per-processor register within the interrupt delivery
941 unit */
942 if (space == opic->idu.space
943 && address >= (opic->idu.address + idu_per_processor_register_base)
944 && address < (opic->idu.address + idu_per_processor_register_base
945 + (sizeof_idu_per_processor_register_block
946 * opic->nr_interrupt_destinations))) {
947 unsigned_word block_offset = (address
948 - opic->idu.address
949 - idu_per_processor_register_base);
950 unsigned_word offset = block_offset % sizeof_idu_per_processor_register_block;
951 *index = block_offset / sizeof_idu_per_processor_register_block;
952 switch (offset) {
953 case 0x040:
954 *type = ipi_N_dispatch_register;
955 *index = 0;
956 break;
957 case 0x050:
958 *type = ipi_N_dispatch_register;
959 *index = 1;
960 break;
961 case 0x060:
962 *type = ipi_N_dispatch_register;
963 *index = 2;
964 break;
965 case 0x070:
966 *type = ipi_N_dispatch_register;
967 *index = 3;
968 break;
969 case 0x080:
970 *type = current_task_priority_register_N;
971 break;
972 case 0x0a0:
973 *type = interrupt_acknowledge_register_N;
974 break;
975 case 0x0b0:
976 *type = end_of_interrupt_register_N;
977 break;
978 default:
979 *type = invalid_opic_register;
980 break;
982 DTRACE(opic, ("per-processor register %d:0x%lx - %s[%d]\n",
983 space, (unsigned long)address,
984 opic_register_name(*type),
985 *index));
986 return;
989 /* try for an interrupt source unit */
990 for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
991 if (opic->isu_block[isb].space == space
992 && address >= opic->isu_block[isb].address
993 && address < (opic->isu_block[isb].address + opic->isu_block[isb].size)) {
994 unsigned_word block_offset = address - opic->isu_block[isb].address;
995 unsigned_word offset = block_offset % sizeof_isu_register_block;
996 *index = (opic->isu_block[isb].int_number
997 + (block_offset / sizeof_isu_register_block));
998 switch (offset) {
999 case 0x00:
1000 *type = interrupt_source_N_vector_priority_register;
1001 break;
1002 case 0x10:
1003 *type = interrupt_source_N_destination_register;
1004 break;
1005 default:
1006 *type = invalid_opic_register;
1007 break;
1009 DTRACE(opic, ("isu register %d:0x%lx - %s[%d]\n",
1010 space, (unsigned long)address,
1011 opic_register_name(*type),
1012 *index));
1013 return;
1017 /* try for a timer */
1018 if (space == opic->idu.space
1019 && address >= (opic->idu.address + idu_timer_base)
1020 && address < (opic->idu.address + idu_timer_base
1021 + opic->nr_timer_interrupts * sizeof_timer_register_block)) {
1022 unsigned_word offset = address % sizeof_timer_register_block;
1023 *index = ((address - opic->idu.address - idu_timer_base)
1024 / sizeof_timer_register_block);
1025 switch (offset) {
1026 case 0x00:
1027 *type = timer_N_current_count_register;
1028 break;
1029 case 0x10:
1030 *type = timer_N_base_count_register;
1031 break;
1032 case 0x20:
1033 *type = timer_N_vector_priority_register;
1034 break;
1035 case 0x30:
1036 *type = timer_N_destination_register;
1037 break;
1038 default:
1039 *type = invalid_opic_register;
1040 break;
1042 DTRACE(opic, ("timer register %d:0x%lx - %s[%d]\n",
1043 space, (unsigned long)address,
1044 opic_register_name(*type),
1045 *index));
1046 return;
1049 /* finally some other misc global register */
1050 if (space == opic->idu.space
1051 && address >= opic->idu.address
1052 && address < opic->idu.address + opic->idu.size) {
1053 unsigned_word block_offset = address - opic->idu.address;
1054 switch (block_offset) {
1055 case 0x010f0:
1056 *type = timer_frequency_reporting_register;
1057 *index = -1;
1058 break;
1059 case 0x010e0:
1060 *type = spurious_vector_register;
1061 *index = -1;
1062 break;
1063 case 0x010d0:
1064 case 0x010c0:
1065 case 0x010b0:
1066 case 0x010a0:
1067 *type = ipi_N_vector_priority_register;
1068 *index = (block_offset - 0x010a0) / 16;
1069 break;
1070 case 0x01090:
1071 *type = processor_init_register;
1072 *index = -1;
1073 break;
1074 case 0x01080:
1075 *type = vendor_identification_register;
1076 *index = -1;
1077 break;
1078 case 0x01020:
1079 *type = global_configuration_register_N;
1080 *index = 0;
1081 break;
1082 case 0x01000:
1083 *type = feature_reporting_register_N;
1084 *index = 0;
1085 break;
1086 default:
1087 *type = invalid_opic_register;
1088 *index = -1;
1089 break;
1091 DTRACE(opic, ("global register %d:0x%lx - %s[%d]\n",
1092 space, (unsigned long)address,
1093 opic_register_name(*type),
1094 *index));
1095 return;
1098 /* nothing matched */
1099 *type = invalid_opic_register;
1100 DTRACE(opic, ("invalid register %d:0x%lx\n",
1101 space, (unsigned long)address));
1102 return;
1106 /* Processor init register:
1108 The bits in this register (one per processor) are directly wired to
1109 output "init" interrupt ports. */
1111 static unsigned
1112 do_processor_init_register_read(device *me,
1113 hw_opic_device *opic)
1115 unsigned reg = opic->init;
1116 DTRACE(opic, ("processor init register - read 0x%lx\n",
1117 (long)reg));
1118 return reg;
1121 static void
1122 do_processor_init_register_write(device *me,
1123 hw_opic_device *opic,
1124 unsigned reg)
1126 int i;
1127 for (i = 0; i < opic->nr_interrupt_destinations; i++) {
1128 opic_interrupt_destination *dest = &opic->interrupt_destination[i];
1129 if ((reg & dest->bit) != (opic->init & dest->bit)) {
1130 if (reg & dest->bit) {
1131 DTRACE(opic, ("processor init register - write 0x%lx - asserting init%d\n",
1132 (long)reg, i));
1133 opic->init |= dest->bit;
1134 device_interrupt_event(me, dest->init_port, 1, NULL, 0);
1136 else {
1137 DTRACE(opic, ("processor init register - write 0x%lx - negating init%d\n",
1138 (long)reg, i));
1139 opic->init &= ~dest->bit;
1140 device_interrupt_event(me, dest->init_port, 0, NULL, 0);
1148 /* Interrupt Source Vector/Priority Register: */
1150 static unsigned
1151 read_vector_priority_register(device *me,
1152 hw_opic_device *opic,
1153 opic_interrupt_source *interrupt,
1154 const char *reg_name,
1155 int reg_index)
1157 unsigned reg;
1158 reg = 0;
1159 reg |= interrupt->is_masked;
1160 reg |= (interrupt->in_service || interrupt->pending
1161 ? isu_active_bit : 0); /* active */
1162 reg |= interrupt->is_multicast;
1163 reg |= interrupt->is_positive_polarity;
1164 reg |= interrupt->is_level_triggered; /* sense? */
1165 reg |= interrupt->priority << isu_priority_shift;
1166 reg |= interrupt->vector;
1167 DTRACE(opic, ("%s %d vector/priority register - read 0x%lx\n",
1168 reg_name, reg_index, (unsigned long)reg));
1169 return reg;
1172 static unsigned
1173 do_interrupt_source_N_vector_priority_register_read(device *me,
1174 hw_opic_device *opic,
1175 int index)
1177 unsigned reg;
1178 ASSERT(index < opic->nr_external_interrupts);
1179 reg = read_vector_priority_register(me, opic,
1180 &opic->interrupt_source[index],
1181 "interrupt source", index);
1182 return reg;
1185 static void
1186 write_vector_priority_register(device *me,
1187 hw_opic_device *opic,
1188 opic_interrupt_source *interrupt,
1189 unsigned reg,
1190 const char *reg_name,
1191 int reg_index)
1193 interrupt->is_masked = (reg & isu_mask_bit);
1194 interrupt->is_multicast = (reg & isu_multicast_bit);
1195 interrupt->is_positive_polarity = (reg & isu_positive_polarity_bit);
1196 interrupt->is_level_triggered = (reg & isu_level_triggered_bit);
1197 interrupt->priority = ((reg >> isu_priority_shift)
1198 % max_nr_task_priorities);
1199 interrupt->vector = (reg & isu_vector_bits);
1200 DTRACE(opic, ("%s %d vector/priority register - write 0x%lx - %s%s%s-polarity, %s-triggered, priority %ld vector %ld\n",
1201 reg_name,
1202 reg_index,
1203 (unsigned long)reg,
1204 interrupt->is_masked ? "masked, " : "",
1205 interrupt->is_multicast ? "multicast, " : "",
1206 interrupt->is_positive_polarity ? "positive" : "negative",
1207 interrupt->is_level_triggered ? "level" : "edge",
1208 (long)interrupt->priority,
1209 (long)interrupt->vector));
1212 static void
1213 do_interrupt_source_N_vector_priority_register_write(device *me,
1214 hw_opic_device *opic,
1215 int index,
1216 unsigned reg)
1218 ASSERT(index < opic->nr_external_interrupts);
1219 reg &= ~isu_multicast_bit; /* disable multicast */
1220 write_vector_priority_register(me, opic,
1221 &opic->interrupt_source[index],
1222 reg, "interrupt source", index);
1227 /* Interrupt Source Destination Register: */
1229 static unsigned
1230 read_destination_register(device *me,
1231 hw_opic_device *opic,
1232 opic_interrupt_source *interrupt,
1233 const char *reg_name,
1234 int reg_index)
1236 unsigned long reg;
1237 reg = interrupt->destination;
1238 DTRACE(opic, ("%s %d destination register - read 0x%lx\n",
1239 reg_name, reg_index, reg));
1240 return reg;
1243 static unsigned
1244 do_interrupt_source_N_destination_register_read(device *me,
1245 hw_opic_device *opic,
1246 int index)
1248 unsigned reg;
1249 ASSERT(index < opic->nr_external_interrupts);
1250 reg = read_destination_register(me, opic, &opic->external_interrupt_source[index],
1251 "interrupt source", index);
1252 return reg;
1255 static void
1256 write_destination_register(device *me,
1257 hw_opic_device *opic,
1258 opic_interrupt_source *interrupt,
1259 unsigned reg,
1260 const char *reg_name,
1261 int reg_index)
1263 reg &= (1 << opic->nr_interrupt_destinations) - 1; /* mask out invalid */
1264 DTRACE(opic, ("%s %d destination register - write 0x%x\n",
1265 reg_name, reg_index, reg));
1266 interrupt->destination = reg;
1269 static void
1270 do_interrupt_source_N_destination_register_write(device *me,
1271 hw_opic_device *opic,
1272 int index,
1273 unsigned reg)
1275 ASSERT(index < opic->nr_external_interrupts);
1276 write_destination_register(me, opic, &opic->external_interrupt_source[index],
1277 reg, "interrupt source", index);
1282 /* Spurious vector register: */
1284 static unsigned
1285 do_spurious_vector_register_read(device *me,
1286 hw_opic_device *opic)
1288 unsigned long reg = opic->spurious_vector;
1289 DTRACE(opic, ("spurious vector register - read 0x%lx\n", reg));
1290 return reg;
1293 static void
1294 do_spurious_vector_register_write(device *me,
1295 hw_opic_device *opic,
1296 unsigned reg)
1298 reg &= 0xff; /* mask off invalid */
1299 DTRACE(opic, ("spurious vector register - write 0x%x\n", reg));
1300 opic->spurious_vector = reg;
1305 /* current task priority register: */
1307 static unsigned
1308 do_current_task_priority_register_N_read(device *me,
1309 hw_opic_device *opic,
1310 int index)
1312 opic_interrupt_destination *interrupt_destination = &opic->interrupt_destination[index];
1313 unsigned reg;
1314 ASSERT(index >= 0 && index < opic->nr_interrupt_destinations);
1315 reg = interrupt_destination->base_priority;
1316 DTRACE(opic, ("current task priority register %d - read 0x%x\n", index, reg));
1317 return reg;
1320 static void
1321 do_current_task_priority_register_N_write(device *me,
1322 hw_opic_device *opic,
1323 int index,
1324 unsigned reg)
1326 opic_interrupt_destination *interrupt_destination = &opic->interrupt_destination[index];
1327 ASSERT(index >= 0 && index < opic->nr_interrupt_destinations);
1328 reg %= max_nr_task_priorities;
1329 DTRACE(opic, ("current task priority register %d - write 0x%x\n", index, reg));
1330 interrupt_destination->base_priority = reg;
1335 /* Timer Frequency Reporting Register: */
1337 static unsigned
1338 do_timer_frequency_reporting_register_read(device *me,
1339 hw_opic_device *opic)
1341 unsigned reg;
1342 reg = opic->timer_frequency;
1343 DTRACE(opic, ("timer frequency reporting register - read 0x%x\n", reg));
1344 return reg;
1347 static void
1348 do_timer_frequency_reporting_register_write(device *me,
1349 hw_opic_device *opic,
1350 unsigned reg)
1352 DTRACE(opic, ("timer frequency reporting register - write 0x%x\n", reg));
1353 opic->timer_frequency = reg;
1357 /* timer registers: */
1359 static unsigned
1360 do_timer_N_current_count_register_read(device *me,
1361 hw_opic_device *opic,
1362 int index)
1364 opic_timer *timer = &opic->timer[index];
1365 unsigned reg;
1366 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1367 if (timer->inhibited)
1368 reg = timer->count; /* stalled value */
1369 else
1370 reg = timer->count - device_event_queue_time(me); /* time remaining */
1371 DTRACE(opic, ("timer %d current count register - read 0x%x\n", index, reg));
1372 return reg;
1376 static unsigned
1377 do_timer_N_base_count_register_read(device *me,
1378 hw_opic_device *opic,
1379 int index)
1381 opic_timer *timer = &opic->timer[index];
1382 unsigned reg;
1383 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1384 reg = timer->base_count;
1385 DTRACE(opic, ("timer %d base count register - read 0x%x\n", index, reg));
1386 return reg;
1390 static void
1391 timer_event(void *data)
1393 opic_timer *timer = data;
1394 device *me = timer->me;
1395 if (timer->inhibited)
1396 device_error(timer->me, "internal-error - timer event occured when timer %d inhibited",
1397 timer->nr);
1398 handle_interrupt(timer->me, timer->opic, timer->interrupt_source, 1);
1399 timer->timeout_event = device_event_queue_schedule(me, timer->base_count,
1400 timer_event, timer);
1401 DTRACE(opic, ("timer %d - interrupt at %ld, next at %d\n",
1402 timer->nr, (long)device_event_queue_time(me), timer->base_count));
1406 static void
1407 do_timer_N_base_count_register_write(device *me,
1408 hw_opic_device *opic,
1409 int index,
1410 unsigned reg)
1412 opic_timer *timer = &opic->timer[index];
1413 int inhibit;
1414 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1415 inhibit = reg & 0x80000000;
1416 if (timer->inhibited && !inhibit) {
1417 timer->inhibited = 0;
1418 if (timer->timeout_event != NULL)
1419 device_event_queue_deschedule(me, timer->timeout_event);
1420 timer->count = device_event_queue_time(me) + reg;
1421 timer->base_count = reg;
1422 timer->timeout_event = device_event_queue_schedule(me, timer->base_count,
1423 timer_event, (void*)timer);
1424 DTRACE(opic, ("timer %d base count register - write 0x%x - timer started\n",
1425 index, reg));
1427 else if (!timer->inhibited && inhibit) {
1428 if (timer->timeout_event != NULL)
1429 device_event_queue_deschedule(me, timer->timeout_event);
1430 timer->count = timer->count - device_event_queue_time(me);
1431 timer->inhibited = 1;
1432 timer->base_count = reg;
1433 DTRACE(opic, ("timer %d base count register - write 0x%x - timer stopped\n",
1434 index, reg));
1436 else {
1437 ASSERT((timer->inhibited && inhibit) || (!timer->inhibited && !inhibit));
1438 DTRACE(opic, ("timer %d base count register - write 0x%x\n", index, reg));
1439 timer->base_count = reg;
1444 static unsigned
1445 do_timer_N_vector_priority_register_read(device *me,
1446 hw_opic_device *opic,
1447 int index)
1449 unsigned reg;
1450 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1451 reg = read_vector_priority_register(me, opic,
1452 &opic->timer_interrupt_source[index],
1453 "timer", index);
1454 return reg;
1457 static void
1458 do_timer_N_vector_priority_register_write(device *me,
1459 hw_opic_device *opic,
1460 int index,
1461 unsigned reg)
1463 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1464 reg &= ~isu_level_triggered_bit; /* force edge trigger */
1465 reg |= isu_positive_polarity_bit; /* force rising (positive) edge */
1466 reg |= isu_multicast_bit; /* force multicast */
1467 write_vector_priority_register(me, opic,
1468 &opic->timer_interrupt_source[index],
1469 reg, "timer", index);
1473 static unsigned
1474 do_timer_N_destination_register_read(device *me,
1475 hw_opic_device *opic,
1476 int index)
1478 unsigned reg;
1479 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1480 reg = read_destination_register(me, opic, &opic->timer_interrupt_source[index],
1481 "timer", index);
1482 return reg;
1485 static void
1486 do_timer_N_destination_register_write(device *me,
1487 hw_opic_device *opic,
1488 int index,
1489 unsigned reg)
1491 ASSERT(index >= 0 && index < opic->nr_timer_interrupts);
1492 write_destination_register(me, opic, &opic->timer_interrupt_source[index],
1493 reg, "timer", index);
1497 /* IPI registers */
1499 static unsigned
1500 do_ipi_N_vector_priority_register_read(device *me,
1501 hw_opic_device *opic,
1502 int index)
1504 unsigned reg;
1505 ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
1506 reg = read_vector_priority_register(me, opic,
1507 &opic->interprocessor_interrupt_source[index],
1508 "ipi", index);
1509 return reg;
1512 static void
1513 do_ipi_N_vector_priority_register_write(device *me,
1514 hw_opic_device *opic,
1515 int index,
1516 unsigned reg)
1518 ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
1519 reg &= ~isu_level_triggered_bit; /* force edge trigger */
1520 reg |= isu_positive_polarity_bit; /* force rising (positive) edge */
1521 reg |= isu_multicast_bit; /* force a multicast source */
1522 write_vector_priority_register(me, opic,
1523 &opic->interprocessor_interrupt_source[index],
1524 reg, "ipi", index);
1527 static void
1528 do_ipi_N_dispatch_register_write(device *me,
1529 hw_opic_device *opic,
1530 int index,
1531 unsigned reg)
1533 opic_interrupt_source *source = &opic->interprocessor_interrupt_source[index];
1534 ASSERT(index >= 0 && index < opic->nr_interprocessor_interrupts);
1535 DTRACE(opic, ("ipi %d interrupt dispatch register - write 0x%x\n", index, reg));
1536 source->destination = reg;
1537 handle_interrupt(me, opic, source, 1);
1541 /* vendor and other global registers */
1543 static unsigned
1544 do_vendor_identification_register_read(device *me,
1545 hw_opic_device *opic)
1547 unsigned reg;
1548 reg = opic->vendor_identification;
1549 DTRACE(opic, ("vendor identification register - read 0x%x\n", reg));
1550 return reg;
1553 static unsigned
1554 do_feature_reporting_register_N_read(device *me,
1555 hw_opic_device *opic,
1556 int index)
1558 unsigned reg = 0;
1559 ASSERT(index == 0);
1560 switch (index) {
1561 case 0:
1562 reg |= (opic->nr_external_interrupts << 16);
1563 reg |= (opic->nr_interrupt_destinations << 8);
1564 reg |= (2/*version 1.2*/);
1565 break;
1567 DTRACE(opic, ("feature reporting register %d - read 0x%x\n", index, reg));
1568 return reg;
1571 static unsigned
1572 do_global_configuration_register_N_read(device *me,
1573 hw_opic_device *opic,
1574 int index)
1576 unsigned reg = 0;
1577 ASSERT(index == 0);
1578 switch (index) {
1579 case 0:
1580 reg |= gcr0_8259_bit; /* hardwire 8259 disabled */
1581 break;
1583 DTRACE(opic, ("global configuration register %d - read 0x%x\n", index, reg));
1584 return reg;
1587 static void
1588 do_global_configuration_register_N_write(device *me,
1589 hw_opic_device *opic,
1590 int index,
1591 unsigned reg)
1593 ASSERT(index == 0);
1594 if (reg & gcr0_reset_bit) {
1595 DTRACE(opic, ("global configuration register %d - write 0x%x - reseting opic\n", index, reg));
1596 hw_opic_init_data(me);
1598 if (!(reg & gcr0_8259_bit)) {
1599 DTRACE(opic, ("global configuration register %d - write 0x%x - ignoring 8259 enable\n", index, reg));
1605 /* register read-write */
1607 static unsigned
1608 hw_opic_io_read_buffer(device *me,
1609 void *dest,
1610 int space,
1611 unsigned_word addr,
1612 unsigned nr_bytes,
1613 cpu *processor,
1614 unsigned_word cia)
1616 hw_opic_device *opic = (hw_opic_device*)device_data(me);
1617 opic_register type;
1618 int index;
1619 decode_opic_address(me, opic, space, addr, nr_bytes, &type, &index);
1620 if (type == invalid_opic_register) {
1621 device_error(me, "invalid opic read access to %d:0x%lx (%d bytes)",
1622 space, (unsigned long)addr, nr_bytes);
1624 else {
1625 unsigned reg;
1626 switch (type) {
1627 case processor_init_register:
1628 reg = do_processor_init_register_read(me, opic);
1629 break;
1630 case interrupt_source_N_vector_priority_register:
1631 reg = do_interrupt_source_N_vector_priority_register_read(me, opic, index);
1632 break;
1633 case interrupt_source_N_destination_register:
1634 reg = do_interrupt_source_N_destination_register_read(me, opic, index);
1635 break;
1636 case interrupt_acknowledge_register_N:
1637 reg = do_interrupt_acknowledge_register_N_read(me, opic, index);
1638 break;
1639 case spurious_vector_register:
1640 reg = do_spurious_vector_register_read(me, opic);
1641 break;
1642 case current_task_priority_register_N:
1643 reg = do_current_task_priority_register_N_read(me, opic, index);
1644 break;
1645 case timer_frequency_reporting_register:
1646 reg = do_timer_frequency_reporting_register_read(me, opic);
1647 break;
1648 case timer_N_current_count_register:
1649 reg = do_timer_N_current_count_register_read(me, opic, index);
1650 break;
1651 case timer_N_base_count_register:
1652 reg = do_timer_N_base_count_register_read(me, opic, index);
1653 break;
1654 case timer_N_vector_priority_register:
1655 reg = do_timer_N_vector_priority_register_read(me, opic, index);
1656 break;
1657 case timer_N_destination_register:
1658 reg = do_timer_N_destination_register_read(me, opic, index);
1659 break;
1660 case ipi_N_vector_priority_register:
1661 reg = do_ipi_N_vector_priority_register_read(me, opic, index);
1662 break;
1663 case feature_reporting_register_N:
1664 reg = do_feature_reporting_register_N_read(me, opic, index);
1665 break;
1666 case global_configuration_register_N:
1667 reg = do_global_configuration_register_N_read(me, opic, index);
1668 break;
1669 case vendor_identification_register:
1670 reg = do_vendor_identification_register_read(me, opic);
1671 break;
1672 default:
1673 reg = 0;
1674 device_error(me, "unimplemented read of register %s[%d]",
1675 opic_register_name(type), index);
1677 *(unsigned_4*)dest = H2LE_4(reg);
1679 return nr_bytes;
1683 static unsigned
1684 hw_opic_io_write_buffer(device *me,
1685 const void *source,
1686 int space,
1687 unsigned_word addr,
1688 unsigned nr_bytes,
1689 cpu *processor,
1690 unsigned_word cia)
1692 hw_opic_device *opic = (hw_opic_device*)device_data(me);
1693 opic_register type;
1694 int index;
1695 decode_opic_address(me, opic, space, addr, nr_bytes, &type, &index);
1696 if (type == invalid_opic_register) {
1697 device_error(me, "invalid opic write access to %d:0x%lx (%d bytes)",
1698 space, (unsigned long)addr, nr_bytes);
1700 else {
1701 unsigned reg = LE2H_4(*(unsigned_4*)source);
1702 switch (type) {
1703 case processor_init_register:
1704 do_processor_init_register_write(me, opic, reg);
1705 break;
1706 case interrupt_source_N_vector_priority_register:
1707 do_interrupt_source_N_vector_priority_register_write(me, opic, index, reg);
1708 break;
1709 case interrupt_source_N_destination_register:
1710 do_interrupt_source_N_destination_register_write(me, opic, index, reg);
1711 break;
1712 case end_of_interrupt_register_N:
1713 do_end_of_interrupt_register_N_write(me, opic, index, reg);
1714 break;
1715 case spurious_vector_register:
1716 do_spurious_vector_register_write(me, opic, reg);
1717 break;
1718 case current_task_priority_register_N:
1719 do_current_task_priority_register_N_write(me, opic, index, reg);
1720 break;
1721 case timer_frequency_reporting_register:
1722 do_timer_frequency_reporting_register_write(me, opic, reg);
1723 break;
1724 case timer_N_base_count_register:
1725 do_timer_N_base_count_register_write(me, opic, index, reg);
1726 break;
1727 case timer_N_vector_priority_register:
1728 do_timer_N_vector_priority_register_write(me, opic, index, reg);
1729 break;
1730 case timer_N_destination_register:
1731 do_timer_N_destination_register_write(me, opic, index, reg);
1732 break;
1733 case ipi_N_dispatch_register:
1734 do_ipi_N_dispatch_register_write(me, opic, index, reg);
1735 break;
1736 case ipi_N_vector_priority_register:
1737 do_ipi_N_vector_priority_register_write(me, opic, index, reg);
1738 break;
1739 case global_configuration_register_N:
1740 do_global_configuration_register_N_write(me, opic, index, reg);
1741 break;
1742 default:
1743 device_error(me, "unimplemented write to register %s[%d]",
1744 opic_register_name(type), index);
1747 return nr_bytes;
1751 static void
1752 hw_opic_interrupt_event(device *me,
1753 int my_port,
1754 device *source,
1755 int source_port,
1756 int level,
1757 cpu *processor,
1758 unsigned_word cia)
1760 hw_opic_device *opic = (hw_opic_device*)device_data(me);
1762 int isb;
1763 int src_nr = 0;
1765 /* find the corresponding internal input port */
1766 for (isb = 0; isb < opic->nr_isu_blocks; isb++) {
1767 if (my_port >= opic->isu_block[isb].int_number
1768 && my_port < opic->isu_block[isb].int_number + opic->isu_block[isb].range) {
1769 src_nr += my_port - opic->isu_block[isb].int_number;
1770 break;
1772 else
1773 src_nr += opic->isu_block[isb].range;
1775 if (isb == opic->nr_isu_blocks)
1776 device_error(me, "interrupt %d out of range", my_port);
1777 DTRACE(opic, ("external-interrupt %d, internal %d, level %d\n",
1778 my_port, src_nr, level));
1780 /* pass it on */
1781 ASSERT(src_nr >= 0 && src_nr < opic->nr_external_interrupts);
1782 handle_interrupt(me, opic, &opic->external_interrupt_source[src_nr], level);
1786 static const device_interrupt_port_descriptor hw_opic_interrupt_ports[] = {
1787 { "irq", 0, max_nr_interrupt_sources, input_port, },
1788 { "intr", 0, max_nr_interrupt_destinations, output_port, },
1789 { "init", max_nr_interrupt_destinations, max_nr_interrupt_destinations, output_port, },
1790 { NULL }
1794 static device_callbacks const hw_opic_callbacks = {
1795 { generic_device_init_address,
1796 hw_opic_init_data },
1797 { NULL, }, /* address */
1798 { hw_opic_io_read_buffer,
1799 hw_opic_io_write_buffer }, /* IO */
1800 { NULL, }, /* DMA */
1801 { hw_opic_interrupt_event, NULL, hw_opic_interrupt_ports }, /* interrupt */
1802 { NULL, }, /* unit */
1803 NULL, /* instance */
1806 static void *
1807 hw_opic_create(const char *name,
1808 const device_unit *unit_address,
1809 const char *args)
1811 hw_opic_device *opic = ZALLOC(hw_opic_device);
1812 return opic;
1817 const device_descriptor hw_opic_device_descriptor[] = {
1818 { "opic", hw_opic_create, &hw_opic_callbacks },
1819 { NULL },
1822 #endif /* _HW_OPIC_C_ */