struct intrinfo_entry * add_interrupt(const struct startup_intrinfo *startup_intr) { struct intrinfo_entry *intr; unsigned i; if(intr_prev_output_rtn == NULL) { //Hook into the sizing/writing list intr_prev_output_rtn = callout_output_rtn; callout_output_rtn = (output_callout_t *)callout_output_intr; } intr = grow_syspage_section(&lsp.intrinfo, sizeof(*intr)); //Point at newly allocated entry intr = (void *)((uint8_t *)intr + lsp.intrinfo.size - sizeof(*intr)); *intr = *(struct intrinfo_entry *)startup_intr; if(startup_intr->id.rtn != NULL) { intr->id.size = startup_intr->id.rtn->rtn_size; } if(startup_intr->eoi.rtn != NULL) { intr->eoi.size = startup_intr->eoi.rtn->rtn_size; } for(i = 0; i < NUM_ELTS(offsets); ++i) { void (**rtn)(void) = (void (**)(void))((uintptr_t)intr + offsets[i]); callout_register_data(rtn, startup_intr->patch_data); } return(intr); }
char *InitSys( void ) { static char name[] = "\\\\.\\DBGPORT1"; int i; if( !(GetVersion() & 0x80000000) ) { PortHdl = CreateFile( name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if ( PortHdl == INVALID_HANDLE_VALUE ) return( TRP_ERR_cannot_access_parallel_ports ); } PortsFound = 0; for( i = 0; i < NUM_ELTS( PortTest ); ++i ) { if( CheckForPort( i, 0x55 ) && CheckForPort( i, 0xaa ) ) { PortAddress[ PortsFound++ ] = PortTest[ i ]; } } return( NULL ); }
mad_status RegInit() { unsigned i; unsigned max; unsigned curr; unsigned half_idx = 0; mad_status ms; max = 0; for( i = 0; i < NUM_ELTS( RegList ); ++i ) { switch( RegList[i].sublist_code ) { case RS_DWORD: curr = TYPEIDX( RegList[i].info.bit_start, unsigned_64 ); if( curr > max ) max = curr; RegListHalf[half_idx] = RegList[i]; #if defined( __BIG_ENDIAN__ ) // kludge for 64-bit registers displayed as 32-bit - need to // skip 32 bits! RegListHalf[half_idx].info.bit_start += 32; #endif RegListHalf[half_idx].info.bit_size = 32; ++half_idx; break; } } RegSubList = MCAlloc( ( max + 1 ) * sizeof( *RegSubList ) ); if( RegSubList == NULL ) return( MS_ERR | MS_NO_MEM ); memset( RegSubList, 0, ( max + 1 ) * sizeof( *RegSubList ) ); for( i = 0; i < NUM_ELTS( RegList ); ++i ) { switch( RegList[i].sublist_code ) { case RS_DWORD: ms = AddSubList( i, IntRegSubData, NUM_ELTS( IntRegSubData ) ); if( ms != MS_OK ) return( ms ); break; } } return( MS_OK ); }
void config_cpu(unsigned pvr, const struct exc_copy_block **entry, const struct exc_copy_block **exitlocal) { // The 970 doesn't support the "tlbia" instruction, which is what // tlb_flush_all defaults to using. However, the tlb_flush_all_64 // routine doesn't flush enough entries. We can get away without defining // a proper routine however because the only thing this is used for is // handling IPI_TLB_FLUSH and that is only needed if PPC_CPU_SW_TLBSYNC // is on, which it won't be for any 900 series processor. // tlb_flush_all = tlb_flush_all_64; CRASHCHECK(__cpu_flags & PPC_CPU_SW_TLBSYNC); trap_install_set(ppc_traps, NUM_ELTS(ppc_traps)); /* * Install the Altivec exception handler if this CPU supports it. */ if(__cpu_flags & PPC_CPU_ALTIVEC) { trap_install_set(ppc_traps_altivec, NUM_ELTS(ppc_traps_altivec)); alt_souls.size = sizeof(PPC_VMX_REGISTERS); } if(fpuemul) { // Emulation trap_install(PPC_EXC_FPU_UNAVAILABLE, __exc_fpu_emulation, &__common_exc_entry); } else { // Real floating point trap_install(PPC_EXC_FPU_UNAVAILABLE, __exc_fpu_unavail, &__exc_ffpu); } if(__cpu_flags & PPC_CPU_EAR) { *entry++ = &ctx_save_ear; *exitlocal++ = &ctx_restore_ear; } if(__cpu_flags & PPC_CPU_ALTIVEC) { *entry++ = &ctx_save_vmx; } *entry = NULL; *exitlocal = NULL; }
static return_val initHashTables( void ) { int loop; return_val error; error = createHashTables(); if( error == OKAY ) { for( loop = 0; loop < NUM_ELTS( RecognizedName ); loop++ ) { HashTableInsert( NameRecognitionTable, (hash_value) RecognizedName[loop].name, RecognizedName[loop].type ); } } return( error ); }
mad_status RegInit( void ) { unsigned i; unsigned max; unsigned curr; mad_status ms; max = 0; for( i = 0; i < NUM_ELTS( RegList ); ++i ) { switch( RegList[i].sublist_code ) { case RS_INT: case RS_FLT: curr = TYPEIDX( RegList[i].info.bit_start, axpreg ); if( curr > max ) max = curr; break; } } RegSubList = MCAlloc( ( max + 1 ) * sizeof( *RegSubList ) ); if( RegSubList == NULL ) return( MS_ERR | MS_NO_MEM ); memset( RegSubList, 0, ( max + 1 ) * sizeof( *RegSubList ) ); for( i = 0; i < NUM_ELTS( RegList ); ++i ) { switch( RegList[i].sublist_code ) { case RS_INT: ms = AddSubList( i, IntRegSubData, NUM_ELTS( IntRegSubData ) ); if( ms != MS_OK ) return( ms ); break; case RS_FLT: ms = AddSubList( i, FltRegSubData, NUM_ELTS( FltRegSubData ) ); if( ms != MS_OK ) return( ms ); break; } } return( MS_OK ); }
static return_val initHashTables( void ) { int i; return_val error; hash_entry_data key_entry; error = createHashTables(); if( error == RC_OKAY ) { for( i = 0; i < NUM_ELTS( RecognizedName ); i++ ) { key_entry.key.u.string = RecognizedName[i].name; key_entry.data.u.sec_type = RecognizedName[i].type; HashTableInsert( NameRecognitionTable, &key_entry ); } } return( error ); }
char *InitSys() { int i; PortsFound = 0; for( i = 0; i < NUM_ELTS( PortTest ); ++i ) { if (!AccessPorts(PortTest[i], PortTest[i])) { printf("Failed to get I/O permissions. This program must run as root!\n"); exit(-1); } if( CheckForPort( i, 0x55 ) && CheckForPort( i, 0xaa ) ) { PortAddress[ PortsFound++ ] = PortTest[ i ]; } FreePorts(PortTest[i], PortTest[i]); } return( NULL ); }
void set_debug(unsigned channel, const struct debug_device *dev, const char *options) { unsigned base; unsigned i; dev->init(channel, options, dev->defaults[channel]); if(channel == 0) set_print_char(dev->put); base = offsetof(struct callout_entry, debug); base += channel * sizeof(struct debug_callout); for(i = 0; i < NUM_ELTS(dev->callouts); ++i) { const struct callout_rtn *rtn = dev->callouts[i]; if(rtn != NULL) { add_callout(base + i*sizeof(callout_fp_t), rtn); } } }
static output_callout_t * callout_output_intr(int sizing) { unsigned i; unsigned nelts; nelts = lsp.intrinfo.size / sizeof(*lsp.intrinfo.p); for(i = 0; i < nelts; ++i) { uint8_t *base = (uint8_t *)&lsp.intrinfo.p[i]; unsigned j; for(j = 0; j < NUM_ELTS(offsets); ++j) { void (**rtn)(void) = (void (**)(void))(base + offsets[j]); callout_output_one(sizing, rtn); } } return(intr_prev_output_rtn); }
void RegFini() { unsigned i; unsigned max; unsigned curr; max = 0; for( i = 0; i < NUM_ELTS( RegList ); ++i ) { switch( RegList[i].sublist_code ) { case RS_DWORD: curr = RegList[i].info.bit_start / (sizeof(unsigned_64)*BITS_PER_BYTE); if( curr > max ) max = curr; break; } } for( i = 0; i <= max; ++i ) MCFree( RegSubList[i] ); MCFree( RegSubList ); RegSubList = NULL; }
char *InitSys() { SEL global; SEL local; int i; DosGetInfoSeg( &global, &local ); GInfoSeg = MK_FP( global, 0 ); PortsFound = 0; for( i = 0; i < NUM_ELTS( PortTest ); ++i ) { AccessPorts( PortTest[i], PortTest[i] ); if( CheckForPort( i, 0x55 ) && CheckForPort( i, 0xaa ) ) { PortAddress[ PortsFound++ ] = PortTest[ i ]; } FreePorts( PortTest[i], PortTest[i] ); } return( 0 ); }
void RegFini( void ) { unsigned i; unsigned max; unsigned curr; max = 0; for( i = 0; i < NUM_ELTS( RegList ); ++i ) { switch( RegList[i].sublist_code ) { case RS_INT: case RS_FLT: curr = TYPEIDX( RegList[i].info.bit_start, axpreg ); if( curr > max ) max = curr; break; } } for( i = 0; i <= max; ++i ) MCFree( RegSubList[i] ); MCFree( RegSubList ); RegSubList = NULL; }
/* * We've run out of intrevent structures. This means that some process * has messed up its ISR. We'll find the errant process and kill it * without mercy. * * This code is actually bogus, since it doesn't really solve the * problem - the messed up ISR may not be adding any events to the * intrevent_pending queue, so it won't be found by scanning the * list. We'd need to keep track of active interrupts and find the * deepest nesting one that keeps on asserting when we re-enable interrupts * in the kernel interrupt exit processing, but I can't see any way * of doing that without slowing down the normal interrupt handling code, * which we don't want to do. It's also got race conditions - think * about what happens if another nested interrupt goes off while in * here and the code is re-entrantly started. Things to think about... * * Beginings of an idea. * In intrevent_add(), when get down to a critical number of * free INTREVENT's (~20), turn on a flag. In the interrupt() * processing loop, if that flag is on, mask any interrupt that * occurs and set a flag on the INTERRUPT structure saying that * it's been masked. Eventually the problem interrupt will be masked * and forward progress will be made. Once we get into intrevent_drain(), * and have drained all the pending events, check the global flag. If * it's on, scan the INTERRUPT structures looking for ones that have * been masked by the interrupt() loop. For each, clear a state flag, * unmask the level and then set the state flag. In the interrupt() loop, * more code counts the number of times it gets entered. If we get above * a predetermined number (~100) without seeing the state flag gets set, * we assume that this is the permanently asserted interrupt and * remask it. All the processes with ISR's attached to that interrupt * need to be killed. Where this has problems is with SMP, since the * interrupt() loop may be handled by a different CPU than the one * that's doing intrevent_drain(). */ static int intrevent_error(THREAD *thp, INTERRUPT *isr) { INTREVENT *curr_intr; INTREVENT **owner; PROCESS *curr_proc; PROCESS *high_intrs_proc; pid_t curr_pid; int high_intrs_count; INTRLEVEL *intr_level; unsigned intr_vector; INTREVENT *killer; /* * First, run thru the pending interrupt list and 'mark' each process * with the number of pending events. */ INTR_LOCK(&intrevent_lock); for(curr_intr = intrevent_pending; curr_intr != NULL; curr_intr = curr_intr->next) { curr_intr->thread->process->pending_interrupts++; } INTR_UNLOCK(&intrevent_lock); /* * Walk the process table and find the process with the most pending * interrupts. Zero the list behind us (so we don't have to do another * pass later). */ high_intrs_proc = NULL; high_intrs_count = 0; for(curr_pid = 2; curr_pid < process_vector.nentries; ++curr_pid) { if(VECP(curr_proc, &process_vector, curr_pid)) { if(curr_proc->pending_interrupts > high_intrs_count) { high_intrs_count = curr_proc->pending_interrupts; high_intrs_proc = curr_proc; } curr_proc->pending_interrupts = 0; } } intr_level = &interrupt_level[isr->level]; intr_vector = intr_level->info->vector_base + isr->level - intr_level->level_base; #define MIN_INTRS_BAD 10 if(high_intrs_count < MIN_INTRS_BAD) { /* There wasn't enough pending interrupts on any particular process to justify * canceling them. */ char *name = thp->process->debug_name; if(name == NULL) name = ""; kprintf("Out of interrupt events! (vector=%u process=%u [%s])\n", intr_vector, thp->process->pid, name); if(ker_verbose >= 2) { /* debug assist information when of out interrupt events occurs */ unsigned i; INTREVENT * irplocal = intrevent_pending; #if defined(__GNUC__) /* this enum order safe init is not supported by the WATCOM compiler */ #define ARRAY_EL(e) [(e)] = #else #define ARRAY_EL(e) #endif static const char * const fmt[] = { ARRAY_EL(SIGEV_NONE) "t-%02u: SIGEV_NONE(%u) -> %u (%s) (--/--/--/--)\n", ARRAY_EL(SIGEV_SIGNAL) "t-%02u: SIGEV_SIGNAL(%u) -> %u (%s) (0x%x/0x%x/--/--)\n", ARRAY_EL(SIGEV_SIGNAL_CODE) "t-%02u: SIGEV_SIGNAL_CODE(%u) -> %u (%s) (0x%x/0x%x/0x%x/--)\n", ARRAY_EL(SIGEV_SIGNAL_THREAD) "t-%02u: SIGEV_SIGNAL_THREAD(%u) -> %u (%s) (0x%x/0x%x/0x%x/--)\n", ARRAY_EL(SIGEV_PULSE) "t-%02u: SIGEV_PULSE(%u) -> %u (%s) (0x%x/0x%x/0x%x/0x%x)\n", ARRAY_EL(SIGEV_UNBLOCK) "t-%02u: SIGEV_UNBLOCK(%u) -> %u (%s) (--/--/--/--)\n", ARRAY_EL(SIGEV_INTR) "t-%02u: SIGEV_INTR(%u) -> %u (%s) (--/--/--/--)\n", ARRAY_EL(SIGEV_THREAD) "t-%02u: SIGEV_THREAD(%u) -> %u (%s) (--/--/--/--)\n", }; kprintf("Last %u: event -> pid (signo/val/code/pri)\n", 2 * MIN_INTRS_BAD); for (i=0; i<(2 * MIN_INTRS_BAD); i++, irplocal=irplocal->next) kprintf(fmt[SIGEV_GET_TYPE(&irplocal->event) % NUM_ELTS(fmt)], i+1, SIGEV_GET_TYPE(&irplocal->event), (irplocal->thread && irplocal->thread->process) ? irplocal->thread->process->pid : 0, (irplocal->thread && irplocal->thread->process) ? irplocal->thread->process->debug_name : "?", irplocal->event.sigev_signo, irplocal->event.sigev_value.sival_int, irplocal->event.sigev_code, irplocal->event.sigev_priority); } return 0; } /* * Cancel all interrupts pending for that process. */ killer = NULL; INTR_LOCK(&intrevent_lock); owner = &intrevent_pending; for( ;; ) { curr_intr = *owner; if(curr_intr == NULL) break; if(curr_intr->thread->process == high_intrs_proc) { *owner = curr_intr->next; if(intrevent_tail == &curr_intr->next) { intrevent_tail = owner; } if(killer == NULL) { killer = curr_intr; } else { curr_intr->next = intrevent_free; intrevent_free = curr_intr; ++num_pev_free; } } else { owner = &curr_intr->next; } } if((killer == NULL) || (high_intrs_proc == NULL)) crash(); killer->thread = high_intrs_proc->valid_thp; // Use a uniqe code that people can recognize SIGEV_SIGNAL_CODE_INIT(&killer->event, SIGKILL, 1, SI_IRQ); killer->next = intrevent_pending; intrevent_pending = killer; INTR_UNLOCK(&intrevent_lock); if(high_intrs_proc == thp->process) { if(intr_vector != SYSPAGE_ENTRY(qtime)->intr) { // The current interrupt came from the failed process. Mask it. //NYI: There should be a tracevent for this.... (void) interrupt_mask(isr->level, isr); } } // Tell intrevent_add() to try again, we've freed stuff up. return 1; }
unsigned short ); extern unsigned short pascal far DosPortAccess( unsigned short reserverd, unsigned short req_release, unsigned short first_port, unsigned short last_port ); #define NUM_ELTS( a ) (sizeof( a ) / sizeof( a[0] )) GINFOSEG far *GInfoSeg; unsigned short PortTest[] = { 0x378, 0x3bc, 0x278 }; unsigned short PortAddress[NUM_ELTS( PortTest )] = { 0,0,0 }; unsigned PortsFound; int NumPrinters() { char num_printers; unsigned short rc; rc = DosDevConfig( &num_printers, 0, 0 ); if( rc != 0 ) return( 0 ); if( num_printers > PortsFound ) num_printers = PortsFound; return( num_printers ); }
void config_cpu(unsigned pvr, const struct exc_copy_block **entry, const struct exc_copy_block **exitlocal) { set_spr( PPCBKE_SPR_DBCR0, 0 ); #ifdef VARIANT_booke SYSPAGE_CPU_ENTRY(ppc,kerinfo)->init_msr |= PPC_MSR_DE; #endif switch(PPC_GET_FAM_MEMBER(pvr)) { case PPC_440GP: ppcbke_tlb_select = PPCBKE_TLB_SELECT_IBM; trap_install_set(traps_440gp, NUM_ELTS(traps_440gp)); fix_pgsizes(); break; case PPC_440GX: ppcbke_tlb_select = PPCBKE_TLB_SELECT_IBM; trap_install_set(traps_440gx, NUM_ELTS(traps_440gx)); fix_pgsizes(); break; case PPC_E500V2: ppcbke_tlb_select = PPCBKE_TLB_SELECT_E500v2; trap_install_set(traps_e500, NUM_ELTS(traps_e500)); alt_souls.size = sizeof(PPC_SPE_REGISTERS); *entry++ = &ctx_save_e500_extra; *exitlocal++ = &ctx_restore_e500_extra; break; case PPC_E500: ppcbke_tlb_select = PPCBKE_TLB_SELECT_E500; trap_install_set(traps_e500, NUM_ELTS(traps_e500)); alt_souls.size = sizeof(PPC_SPE_REGISTERS); *entry++ = &ctx_save_e500_extra; *exitlocal++ = &ctx_restore_e500_extra; break; default: kprintf("Unsupported PVR value: %x\n", pvr); crash(); break; } trap_install_set(traps_booke, NUM_ELTS(traps_booke)); if(__cpu_flags & CPU_FLAG_FPU) { if(fpuemul) { // Emulation trap_install(PPCBKE_SPR_IVOR7, __exc_fpu_emulation, &__common_exc_entry); } else { // Real floating point trap_install(PPCBKE_SPR_IVOR7, __exc_fpu_unavail, &__exc_ffpu); } } // Make data & instruction TLB misses go to the // data and instruction storage exceptions. This will // be changed if/when copy_vm_code() gets called and // we know we're running in virtual mode. set_spr(PPCBKE_SPR_IVOR13, get_spr(PPCBKE_SPR_IVOR2)); set_spr(PPCBKE_SPR_IVOR14, get_spr(PPCBKE_SPR_IVOR3)); *entry++ = &ctx_save_usprg0; *exitlocal++ = &ctx_restore_usprg0; *entry = NULL; *exitlocal = NULL; ppc_ienable_bits |= PPC_MSR_CE | PPC_MSR_ME; }
int main(int argc, char *argv[]) { int opt; char *devicename = NULL; int baud; int nbytes; FILE *imagefp; int devicefd; int n; int r; unsigned i; char *expect = NULL; int timeout = -1; // Calculate the endian of the host this program is running on. n = 1; host_endian = (*(char *)&n != 1); // assume target is the same for the moment target_endian = host_endian; gdb_pc_regnum = -1; gdb_pc_regsize = 4; baud = -1; while ((opt = getopt(argc, argv, "b:d:ei:l:LvqE:p:P:w:")) != -1) { switch(opt) { case 'E': force_error = atoi(optarg); break; case 'b': baud = atoi(optarg); break; case 'd': devicename = optarg; outputdevice(); break; case 'i': devicename = optarg; outputinet(); break; case 'v': verbose++; break; case 'e': echo = 1; break; case 'l': laplink = atoi(optarg); break; case 'L': devicename = "loopback"; outputpipe(); break; case 'q': quiet = 1; break; case 'p': i = 0; for( ;; ) { if(i >= NUM_ELTS(xfers)) { fprintf(stderr, "unrecognized protocol '%s'\n", optarg); return(EXIT_FAILURE); } if(strcmp(optarg, xfers[i].name) == 0) break; ++i; } xfer = &xfers[i]; break; case 'P': { char *p; gdb_pc_regnum = strtoul(optarg, &p, 0); if(*p == ',') { gdb_pc_regsize = strtoul(p + 1, NULL, 0); } } break; case 'w': { char *p; timeout = strtoul(optarg, &p, 0); if(timeout == 0) timeout = 10; if(*p == ':') ++p; if(*p != '\0') expect = p; } break; default: fprintf(stderr, "Unknown option.\n"); break; } } if(devicename == NULL) { fprintf(stderr, "You must specify a device name using the -d option.\n"); exit(EXIT_FAILURE); } output.init(); // Open the device to send the image over. devicefd = output.open(devicename, baud); if(devicefd == -1) { fprintf(stderr, "%s : %s\n", optarg, strerror(errno)); exit(EXIT_FAILURE); } // If a file open it, otherwise assume piped input from stdin if(optind < argc) { if((imagefp = fopen(imagename = argv[optind], "rb")) == NULL) { fprintf(stderr, "%s : %s\n", argv[optind], strerror(errno)); exit(EXIT_FAILURE); } } else { imagename = "-stdin-"; imagefp = stdin; MAKE_BINARY_FP(imagefp); } //Discard any echo'd input output.flush(devicefd); nbytes = fread(data, 1, sizeof(data), imagefp); if(nbytes != sizeof(data)) { fprintf(stderr, "Short read for source file header %d\n", nbytes); return(EXIT_FAILURE); } i = 0; do { r = send_func[i++](imagefp, devicefd, data, nbytes); } while(r < 0); if(timeout > 0) { int c; char *p; time_t start_time; start_time = time(0); p = expect; for( ;; ) { c = output.get(devicefd, 10); if(expect != NULL) { if(c == *p) { ++p; if(*p == '\0') break; } else if(c != -1) { // didn't match the expected char - restart the // search from the begining p = expect; } } if((time(0) - start_time) > timeout) { // We've timed out if(expect != NULL) { // If we were expecting a response string, that's // a failure fprintf(stderr, "Timed out waiting for '%s'\n", expect); r = EXIT_FAILURE; } break; } } } output.close(devicefd); return(r); }
/******************************************************************************* * ep9301_config_pic * * This routine will initialize the 2 Vectored Interrupt Controllers in the * Cirrus Logic EP93xx family of processors. * * In order to handle the number of interrupts within the EP93xx, 2 separate * interrupt controllers are cascaded together to form 1 larger controller. * There is not much documentation on how this cascading of interrupts works as * it is not a true cascade. There is some logic which allows the second * controller to be daisy chained through the first controller which is actually * connected to the processor. There is no documentation on how prioritization * works for non vectored interrupts or the prioritization of the second * controller relative to the first. The only remote suggestion that they are * handled as 32 priority interrupts starting with controller 1 followed by * controller 2 is on page 118 of the User Guide which says ... * * "Vector Control Registers. The 32 VICxVectCntl0 through VICxVectCnt15 * registers select the interrupt source for the vectored interrupt." * * My interpretation is that vector 0 through 15 on controller 1 followed by * vector 0 through 15 on controller 2 is the prioritization. * * This still leaves the problem that we don't know which controller to look * at first without looking at the status register for each ... which implies * that the prioritization is completely under software control. In other words, * software must decide to either read controller 1 or 2 status first, effectively * prioritizing one set of 32 interrupts over the other 32. Then, because some of * the interrupts are not vectored, we must choose bits in the status register. * However, if the vector address read when none of the interrupts programmed as * vectored interrupts is the default vector, then the sequence can flow as * follows (I will prioritize controller 1 interrupts over controller 2) * * if (vic1_status != 0) * { * if (vic1_vector != default vector) * id = vect_table[vic1_vector] * else * id = first bit set in vic1_status * } * else if (vic2_status != 0) * { * if (vic1_vector != default vector) * id = vect_table[vic2_vector] * else * id = first bit set in vic2_status * } * else * spurious interrupt * * return id * * This is all greatly complicated by the fact that only 1/2 of the interrupts * in each controller are vectored and prioritized not to mention the * prioritization between IRQ and FIQ interrupts. * To properly support prioritized interrupts and decouple them from the assigned * internal id's is going to require some more thought so for now I am not going * to use the hardware prioritization of the vectored interrupts and instead * simply do a first bit set prioritization of interrupts as follows * * VIC1, 31 -> 0 * VIC2, 31 -> 0 * * implying that in the case of multiple occurring interrupts, VIC1, interrupt * 31 (documented interrupt source 31) is the highest in the system and VIC2, * interrupt 0 (documented interrupt source 32) is the lowest. * * Additionally, FIQ is not going to be used for now. * * Returns: the number of interrupt vectors assigned * * Implementation Note: * */ uint32_t ep9301_config_pic(uint32_t os_vector_base, uint32_t pic_vector_base, vector_tbl_t *reg_vectors) { uintptr_t base = startup_io_map((EP93xx_VIC_CTRL2_BASE - EP93xx_VIC_CTRL1_BASE) + EP93xx_VIC_CTRL2_SIZE, EP93xx_VIC_CTRL1_BASE); unsigned hwi_off; unsigned i; /* * check the peripheral ID registers. We will assert on the truth of valid_pic_id() since a change * may suggest a difference in the device behaviour which may need to be reflected in a * code change */ ASSERT(valid_pic_id()); ASSERT(pic_vector_base == os_vector_base); // re-mapping not supported (yet) reg_vectors->start = pic_vector_base; reg_vectors->num = 0; /* set all the vector bases */ intrs[0].vector_base = os_vector_base; ASSERT(intrs[0].num_vectors > 0); reg_vectors->num += intrs[0].num_vectors; for (i=1; i<NUM_ELTS(intrs); i++) { intrs[i].vector_base = intrs[i - 1].vector_base + intrs[i - 1].num_vectors; ASSERT(intrs[i].num_vectors > 0); reg_vectors->num += intrs[i].num_vectors; } /* add the interrupt info section */ add_interrupt_array(intrs, sizeof(intrs)); /* disable and clear all interrupts. Note that we do not check EP93xx_VIC_INT_RAW because * some devices do actually have interrupts asserted and this is reflected in the RAW register(s) */ out32(VIC1(EP93xx_VIC_INT_CLEAR), 0xFFFFFFFFU); out32(VIC1(EP93xx_VIC_SWINT_CLEAR), 0xFFFFFFFFU); ASSERT(in32(VIC1(EP93xx_VIC_INT_ENABLE)) == 0); ASSERT(in32(VIC1(EP93xx_VIC_SWINT_ENABLE)) == 0); ASSERT(in32(VIC1(EP93xx_VIC_IRQ_STATUS)) == 0); ASSERT(in32(VIC1(EP93xx_VIC_FIQ_STATUS)) == 0); out32(VIC2(EP93xx_VIC_INT_CLEAR), 0xFFFFFFFFU); out32(VIC2(EP93xx_VIC_SWINT_CLEAR), 0xFFFFFFFFU); ASSERT(in32(VIC2(EP93xx_VIC_INT_ENABLE)) == 0); ASSERT(in32(VIC2(EP93xx_VIC_SWINT_ENABLE)) == 0); ASSERT(in32(VIC2(EP93xx_VIC_IRQ_STATUS)) == 0); ASSERT(in32(VIC2(EP93xx_VIC_FIQ_STATUS)) == 0); /* set privileged access to interrupt controller registers */ out32(VIC1(EP93xx_VIC_PROTECTION), 0x0); out32(VIC2(EP93xx_VIC_PROTECTION), 0x0); /* by default, all interrupts will generate an IRQ (FIQ not used) */ out32(VIC1(EP93xx_VIC_INT_SELECT), 0); out32(VIC2(EP93xx_VIC_INT_SELECT), 0); /* place HWI_ILLEGAL_VECTOR into the default vector(s) */ out32(VIC1(EP93xx_VIC_VEC_ADDR_DFLT), HWI_ILLEGAL_VECTOR); out32(VIC2(EP93xx_VIC_VEC_ADDR_DFLT), HWI_ILLEGAL_VECTOR); /* disable the use of vectored interrupts for now */ in32(VIC1(EP93xx_VIC_VEC_ADDR_CURR)); out32(VIC1(EP93xx_VIC_VEC_ADDR_CURR), 0); in32(VIC2(EP93xx_VIC_VEC_ADDR_CURR)); out32(VIC2(EP93xx_VIC_VEC_ADDR_CURR), 0); for (i=0; i<16; i++) { out32(VIC1(EP93xx_VIC_VEC_ADDR(i)), HWI_ILLEGAL_VECTOR); out32(VIC1(EP93xx_VIC_VEC_CTRL(i)), 0); out32(VIC2(EP93xx_VIC_VEC_ADDR(i)), HWI_ILLEGAL_VECTOR); out32(VIC2(EP93xx_VIC_VEC_CTRL(i)), 0); } /* TIMER1 - interrupt 4 */ hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_TIMER, 0), -1, 4); /* TIMER2 - interrupt 5 */ hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_TIMER, 1), -1, 5); /* TIMER3 - interrupt 51 */ hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_TIMER, 2), -1, 51); /* WATCHDOG TIMER - interrupt 36 */ hwitag_set_avail_ivec(hwi_find_device(EP93xx_HWI_WDOG, 0), -1, 36); /* DMA channels - Note that the order of vector assignment in the HWINFO section will be * memory to memory 0 - 17 * memory to memory 1 - 18 * memory to peripheral 0 - 7 * memory to peripheral 1 - 8 * memory to peripheral 2 - 9 * memory to peripheral 3 - 10 * memory to peripheral 4 - 11 * memory to peripheral 5 - 12 * memory to peripheral 6 - 13 * memory to peripheral 7 - 14 * memory to peripheral 8 - 15 * memory to peripheral 9 - 16 */ if ((hwi_off = hwi_find_device(EP93xx_HWI_DMA, 0)) != HWI_NULL_OFF) { hwitag_set_ivec(hwi_off, 0, 17); hwitag_set_ivec(hwi_off, 1, 18); hwitag_set_ivec(hwi_off, 2, 7); hwitag_set_ivec(hwi_off, 3, 8); hwitag_set_ivec(hwi_off, 4, 9); hwitag_set_ivec(hwi_off, 5, 10); hwitag_set_ivec(hwi_off, 6, 11); hwitag_set_ivec(hwi_off, 7, 12); hwitag_set_ivec(hwi_off, 8, 13); hwitag_set_ivec(hwi_off, 9, 14); hwitag_set_ivec(hwi_off, 10, 15); hwitag_set_ivec(hwi_off, 11, 16); } /* GPIO * 19 of the EP9301 GPIO ports are interruptible and are handled via a * cascaded interrupt entry. In order for devices specifically connected to * those GPIO pins to have a driver InterruptAttach() we provide the assigned * vector ranges with 3 irqrange tags corresponding to the PORTA, PORTB and * PORTF interrupting port pins respectively. Within the range tag assignments, * the 'irq' field corresponds to the LSb (pin 0 of the port) and 'irq' + 'num' - 1 * corresponds to the MSb (pin 7 of the port). */ if ((hwi_off = hwi_find_device(EP93xx_HWI_GPIO, 0)) != HWI_NULL_OFF) { const unsigned num_pAB_vectors = intrs[1].num_vectors / 2; const unsigned num_pF_vectors = intrs[2].num_vectors + intrs[3].num_vectors + intrs[4].num_vectors; hwitag_set_ivecrange(hwi_off, 0, intrs[1].vector_base, num_pAB_vectors); // PORT A hwitag_set_ivecrange(hwi_off, 1, intrs[1].vector_base + num_pAB_vectors, num_pAB_vectors); // PORT B hwitag_set_ivecrange(hwi_off, 2, intrs[2].vector_base, num_pF_vectors); // PORT F } /* UART1 - Note that the order of vector assignment in the HWINFO section will be * combined - 52 * Rx - 23 * Tx - 24 */ if ((hwi_off = hwi_find_device(EP93xx_HWI_UART, 0)) != HWI_NULL_OFF) { hwitag_set_ivec(hwi_off, 0, 52); hwitag_set_ivec(hwi_off, 1, 23); hwitag_set_ivec(hwi_off, 2, 24); } /* UART2 - Note that the order of vector assignment in the HWINFO section will be * combined - 54 * Rx - 25 * Tx - 26 */ if ((hwi_off = hwi_find_device(EP93xx_HWI_UART, 1)) != HWI_NULL_OFF) { hwitag_set_ivec(hwi_off, 0, 54); hwitag_set_ivec(hwi_off, 1, 25); hwitag_set_ivec(hwi_off, 2, 26); } /* EXTERNAL IRQ - 2 interrupts 32, 33 and 40 for IQR0, IRQ1 and IRQ2 respectively */ if ((hwi_off = hwi_find_device(EP93xx_HWI_EXT_IRQ, 0)) != HWI_NULL_OFF) { hwitag_set_ivec(hwi_off, 0, 32); hwitag_set_ivec(hwi_off, 1, 33); hwitag_set_ivec(hwi_off, 2, 40); } /* RTC - Note that the order of vector assignment in the HWINFO section will be * rtc - 37 * 64 Hz clock - 35 * 1 Hz clock - 42 (edge sensitive) */ if ((hwi_off = hwi_find_device(EP93xx_HWI_RTC, 0)) != HWI_NULL_OFF) { hwitag_set_ivec(hwi_off, 0, 37); hwitag_set_ivec(hwi_off, 1, 35); hwitag_set_ivec(hwi_off, 2, 42); } /* IrDA Device - 38 */ if ((hwi_off = hwi_find_device(EP93xx_HWI_IrDA, 0)) != HWI_NULL_OFF) { hwitag_set_avail_ivec(hwi_off, 0, 38); } /* Ethernet Device */ if ((hwi_off = hwi_find_device(EP93xx_HWI_ENET, 0)) != HWI_NULL_OFF) { hwitag_set_avail_ivec(hwi_off, 0, 39); } /* SSP - Note that the order of vector assignment in the HWINFO section will be * combined - 53 * Rx - 45 * Tx - 46 */ if ((hwi_off = hwi_find_bus(EP93xx_HWI_SSP, 0)) != HWI_NULL_OFF) { hwitag_set_ivec(hwi_off, 0, 53); hwitag_set_ivec(hwi_off, 1, 45); hwitag_set_ivec(hwi_off, 2, 46); } /* USB host controller - 56 */ if ((hwi_off = hwi_find_bus(EP93xx_HWI_USB, 0)) != HWI_NULL_OFF) { hwitag_set_avail_ivec(hwi_off, 0, 56); } /* I2S device - 60 */ if ((hwi_off = hwi_find_device(EP93xx_HWI_I2S, 0)) != HWI_NULL_OFF) { hwitag_set_avail_ivec(hwi_off, 0, 60); } /* ACC (AC97) device - 6 */ if ((hwi_off = hwi_find_device(EP93xx_HWI_AUDIO, 0)) != HWI_NULL_OFF) { hwitag_set_avail_ivec(hwi_off, 0, 6); } startup_io_unmap(base); return reg_vectors->num; }