OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [sim/] [ppc/] [hw_opic.c] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 jlechner
/*  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
 
155
typedef struct _hw_opic_device hw_opic_device;
156
 
157
 
158
/* bounds */
159
 
160
enum {
161
  max_nr_interrupt_sources = 2048,
162
  max_nr_interrupt_destinations = 32,
163
  max_nr_task_priorities = 16,
164
};
165
 
166
 
167
enum {
168
  opic_alignment = 16,
169
};
170
 
171
 
172
/* global configuration register */
173
 
174
enum {
175
  gcr0_8259_bit = 0x20000000,
176
  gcr0_reset_bit = 0x80000000,
177
};
178
 
179
 
180
/* offsets and sizes */
181
 
182
enum {
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
 
194
enum {
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
 
205
typedef 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
 
222
typedef 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
 
235
typedef 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
 
245
typedef struct _opic_idu { /* interrupt delivery unit */
246
  int reg;
247
  int space;
248
  unsigned_word address;
249
  unsigned size;
250
} opic_idu;
251
 
252
typedef 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
 
279
static const char *
280
opic_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
 
309
typedef 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
 
323
struct _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
 
366
static void
367
hw_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
 
602
static void
603
assert_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
 
614
static void
615
negate_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
 
626
static int
627
can_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
 
638
static unsigned
639
deliver_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
 
658
typedef enum {
659
  pending_interrupt,
660
  in_service_interrupt,
661
} interrupt_class;
662
 
663
static opic_interrupt_source *
664
find_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
 
694
static opic_interrupt_destination *
695
find_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
 
725
static void
726
handle_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
 
828
static unsigned
829
do_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
 
871
static void
872
do_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
 
927
static void
928
decode_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
 
1116
static unsigned
1117
do_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
 
1126
static void
1127
do_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
 
1155
static unsigned
1156
read_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
 
1177
static unsigned
1178
do_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
 
1190
static void
1191
write_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
 
1217
static void
1218
do_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
 
1234
static unsigned
1235
read_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
 
1248
static unsigned
1249
do_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
 
1260
static void
1261
write_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
 
1274
static void
1275
do_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
 
1289
static unsigned
1290
do_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
 
1298
static void
1299
do_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
 
1312
static unsigned
1313
do_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
 
1325
static void
1326
do_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
 
1342
static unsigned
1343
do_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
 
1352
static void
1353
do_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
 
1364
static unsigned
1365
do_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
 
1381
static unsigned
1382
do_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
 
1395
static void
1396
timer_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
 
1411
static void
1412
do_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
 
1449
static unsigned
1450
do_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
 
1462
static void
1463
do_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
 
1478
static unsigned
1479
do_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
 
1490
static void
1491
do_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
 
1504
static unsigned
1505
do_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
 
1517
static void
1518
do_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
 
1532
static void
1533
do_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
 
1548
static unsigned
1549
do_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
 
1558
static unsigned
1559
do_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
 
1576
static unsigned
1577
do_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
 
1592
static void
1593
do_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
 
1612
static unsigned
1613
hw_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
 
1688
static unsigned
1689
hw_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
 
1756
static void
1757
hw_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
 
1791
static 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
 
1799
static 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
 
1811
static void *
1812
hw_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
 
1822
const device_descriptor hw_opic_device_descriptor[] = {
1823
  { "opic", hw_opic_create, &hw_opic_callbacks },
1824
  { NULL },
1825
};
1826
 
1827
#endif /* _HW_OPIC_C_ */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.