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