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_ */
1828