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