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