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