diff -r f6403cdda87d -r 5e8d11e12241 src/dev/arm/gic.hh --- a/src/dev/arm/gic.hh Sun Apr 10 18:52:15 2011 -0500 +++ b/src/dev/arm/gic.hh Sun Apr 10 18:52:16 2011 -0500 @@ -97,7 +97,18 @@ static const int ICCIIDR = 0xfc; // cpu interface id register static const int CPU_SIZE = 0xff; + static const int SGI_MAX = 16; // Number of Software Gen Interrupts + + /** Mask off SGI's when setting/clearing pending bits */ + static const int SGI_MASK = 0xFFFF0000; + + /** Mask for bits that config N:N mode in ICDICFR's */ + static const int NN_CONFIG_MASK = 0x55555555; + + static const int CPU_MAX = 8; // Max number of supported CPU interfaces static const int SPURIOUS_INT = 1023; + static const int INT_BITS_MAX = 32; + static const int INT_LINES_MAX = 1020; BitUnion32(SWI) Bitfield<3,0> sgi_id; @@ -105,6 +116,11 @@ Bitfield<25,24> list_type; EndBitUnion(SWI) + BitUnion32(IAR) + Bitfield<9,0> ack_id; + Bitfield<12,10> cpu_id; + EndBitUnion(IAR) + /** Distributor address GIC listens at */ Addr distAddr; @@ -128,44 +144,51 @@ /** interrupt enable bits for all possible 1020 interupts. * one bit per interrupt, 32 bit per word = 32 words */ - uint32_t intEnabled[32]; + uint32_t intEnabled[INT_BITS_MAX]; /** interrupt pending bits for all possible 1020 interupts. * one bit per interrupt, 32 bit per word = 32 words */ - uint32_t pendingInt[32]; + uint32_t pendingInt[INT_BITS_MAX]; /** interrupt active bits for all possible 1020 interupts. * one bit per interrupt, 32 bit per word = 32 words */ - uint32_t activeInt[32]; + uint32_t activeInt[INT_BITS_MAX]; /** read only running priroity register, 1 per cpu*/ - uint32_t iccrpr[8]; + uint32_t iccrpr[CPU_MAX]; /** an 8 bit priority (lower is higher priority) for each * of the 1020 possible supported interrupts. */ - uint8_t intPriority[1020]; + uint8_t intPriority[INT_LINES_MAX]; /** an 8 bit cpu target id for each shared peripheral interrupt * of the 1020 possible supported interrupts. */ - uint8_t cpuTarget[1020]; + uint8_t cpuTarget[INT_LINES_MAX]; /** 2 bit per interrupt signaling if it's level or edge sensitive * and if it is 1:N or N:N */ - uint32_t intConfig[64]; + uint32_t intConfig[INT_BITS_MAX*2]; /** CPU enabled */ - bool cpuEnabled[8]; + bool cpuEnabled[CPU_MAX]; /** CPU priority */ - uint8_t cpuPriority[8]; + uint8_t cpuPriority[CPU_MAX]; /** Binary point registers */ - uint8_t cpuBpr[8]; + uint8_t cpuBpr[CPU_MAX]; /** highest interrupt that is interrupting CPU */ - uint32_t cpuHighestInt[8]; + uint32_t cpuHighestInt[CPU_MAX]; + + /** One bit per cpu per software interrupt that is pending for each possible + * sgi source. Indexed by SGI number. Each byte in generating cpu id and + * bits in position is destination id. e.g. 0x4 = CPU 0 generated interrupt + * for CPU 2. */ + uint64_t cpuSgiPending[SGI_MAX]; + uint64_t cpuSgiActive[SGI_MAX]; /** IRQ Enable Used for debug */ bool irqEnable; @@ -173,7 +196,7 @@ /** software generated interrupt * @param data data to decode that indicates which cpus to interrupt */ - void softInt(SWI swi); + void softInt(int ctx_id, SWI swi); /** See if some processor interrupt flags need to be enabled/disabled * @param hint which set of interrupts needs to be checked @@ -184,6 +207,9 @@ * active interrupt*/ void updateRunPri(); + /** generate a bit mask to check cpuSgi for an interrupt. */ + uint64_t genSwiMask(int cpu); + int intNumToWord(int num) const { return num >> 5; } int intNumToBit(int num) const { return num % 32; } diff -r f6403cdda87d -r 5e8d11e12241 src/dev/arm/gic.cc --- a/src/dev/arm/gic.cc Sun Apr 10 18:52:15 2011 -0500 +++ b/src/dev/arm/gic.cc Sun Apr 10 18:52:16 2011 -0500 @@ -56,28 +56,35 @@ { itLinesLog2 = ceilLog2(itLines); - for (int x = 0; x < 8; x++) { + for (int x = 0; x < CPU_MAX; x++) { cpuEnabled[x] = false; - cpuPriority[x] = 0; + cpuPriority[x] = 0xff; cpuBpr[x] = 0; // Initialize cpu highest int cpuHighestInt[x] = SPURIOUS_INT; } + DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0], + cpuEnabled[1]); - for (int x = 0; x < 32; x++) { + for (int x = 0; x < INT_BITS_MAX; x++) { intEnabled[x] = 0; pendingInt[x] = 0; activeInt[x] = 0; } - for (int x = 0; x < 1020; x++) { + for (int x = 0; x < INT_LINES_MAX; x++) { intPriority[x] = 0; cpuTarget[x] = 0; } - for (int x = 0; x < 64; x++) { + for (int x = 0; x < INT_BITS_MAX*2; x++) { intConfig[x] = 0; } + + for (int x = 0; x < SGI_MAX; x++) { + cpuSgiActive[x] = 0; + cpuSgiPending[x] = 0; + } } Tick @@ -225,30 +232,56 @@ Addr daddr = pkt->getAddr() - cpuAddr; pkt->allocate(); - DPRINTF(Interrupt, "gic cpu read register %#x\n", daddr); + assert(pkt->req->hasContextId()); + int ctx_id = pkt->req->contextId(); + + DPRINTF(Interrupt, "gic cpu read register %#x cpu context: %d\n", daddr, + ctx_id); switch(daddr) { case ICCICR: - pkt->set(cpuEnabled[0]); + pkt->set(cpuEnabled[ctx_id]); break; case ICCPMR: - pkt->set(cpuPriority[0]); + pkt->set(cpuPriority[ctx_id]); break; case ICCBPR: - pkt->set(cpuBpr[0]); + pkt->set(cpuBpr[ctx_id]); break; case ICCIAR: - DPRINTF(Interrupt, "CPU reading IAR = %d\n", cpuHighestInt[0]); - if(enabled && cpuEnabled[0]){ - pkt->set(cpuHighestInt[0]); - activeInt[intNumToWord(cpuHighestInt[0])] |= - 1 << intNumToBit(cpuHighestInt[0]); - updateRunPri(); - pendingInt[intNumToWord(cpuHighestInt[0])] &= - ~(1 << intNumToBit(cpuHighestInt[0])); - cpuHighestInt[0] = SPURIOUS_INT; + if(enabled && cpuEnabled[ctx_id]){ + int active_int = cpuHighestInt[ctx_id]; + IAR iar = 0; + iar.ack_id = active_int; + iar.cpu_id = 0; + if (active_int < SGI_MAX) { + // this is a software interrupt from another CPU + if (!cpuSgiPending[active_int]) + panic("Interrupt %d active but no CPU generated it?\n", + active_int); + for (int x = 0; x < CPU_MAX; x++) { + // See which CPU generated the interrupt + uint8_t cpugen = bits(cpuSgiPending[active_int], 7+8*x, 8*x); + if (cpugen & (1 << ctx_id)) { + iar.cpu_id = x; + break; + } + } + cpuSgiActive[iar.ack_id] |= (1 << (ctx_id + 8 * iar.cpu_id)); + cpuSgiPending[iar.ack_id] &= ~(1 << (ctx_id + 8 * iar.cpu_id)); + } else { + activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= + 1 << intNumToBit(cpuHighestInt[ctx_id]); + updateRunPri(); + pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= + ~(1 << intNumToBit(cpuHighestInt[ctx_id])); + } + DPRINTF(Interrupt, "CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n", ctx_id, + iar.ack_id, iar.cpu_id, iar); + cpuHighestInt[ctx_id] = SPURIOUS_INT; updateIntState(-1); - platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0); + pkt->set(iar); + platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0); } else { pkt->set(SPURIOUS_INT); } @@ -276,6 +309,9 @@ Addr daddr = pkt->getAddr() - distAddr; pkt->allocate(); + assert(pkt->req->hasContextId()); + int ctx_id = pkt->req->contextId(); + DPRINTF(Interrupt, "gic distributor write register %#x size %#x\n", daddr, pkt->getSize()); @@ -294,6 +330,7 @@ if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) { assert((daddr-ICDISPR_ST) >> 2 < 32); pendingInt[(daddr-ICDISPR_ST)>>2] |= pkt->get(); + pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed updateIntState((daddr-ICDISPR_ST)>>2); goto done; } @@ -301,6 +338,7 @@ if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) { assert((daddr-ICDICPR_ST) >> 2 < 32); pendingInt[(daddr-ICDICPR_ST)>>2] &= ~pkt->get(); + pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed updateIntState((daddr-ICDICPR_ST)>>2); goto done; } @@ -354,6 +392,8 @@ if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) { assert((daddr-ICDICFR_ST) >> 2 < 64); intConfig[(daddr-ICDICFR_ST)>>2] = pkt->get(); + if (pkt->get() & NN_CONFIG_MASK) + panic("N:N mode selected and not supported at this time\n"); goto done; } @@ -363,7 +403,7 @@ DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled); break; case ICDSGIR: - softInt(pkt->get()); + softInt(ctx_id, pkt->get()); break; default: panic("Tried to write Gic distributor at offset %#x\n", daddr); @@ -381,93 +421,181 @@ Addr daddr = pkt->getAddr() - cpuAddr; pkt->allocate(); - DPRINTF(Interrupt, "gic cpu write register %#x val: %#x\n", - daddr, pkt->get()); + assert(pkt->req->hasContextId()); + int ctx_id = pkt->req->contextId(); + IAR iar; + + DPRINTF(Interrupt, "gic cpu write register cpu:%d %#x val: %#x\n", + ctx_id, daddr, pkt->get()); switch(daddr) { case ICCICR: - cpuEnabled[0] = pkt->get(); - updateIntState(-1); + cpuEnabled[ctx_id] = pkt->get(); break; case ICCPMR: - cpuPriority[0] = pkt->get(); - updateIntState(-1); + cpuPriority[ctx_id] = pkt->get(); break; case ICCBPR: - cpuBpr[0] = pkt->get(); - updateIntState(-1); + cpuBpr[ctx_id] = pkt->get(); break; case ICCEOIR: - uint32_t tmp; - tmp = pkt->get(); - if (!(activeInt[intNumToWord(tmp)] & (1 << intNumToBit(tmp)))) - panic("Done handling interrupt that isn't active?\n"); - activeInt[intNumToWord(tmp)] &= ~(1 << intNumToBit(tmp)); + iar = pkt->get(); + if (iar.ack_id < SGI_MAX) { + // Clear out the bit that corrseponds to the cleared int + if (! (cpuSgiActive[iar.ack_id] & (1 << (ctx_id + 8 * iar.cpu_id)))) + panic("Done handling a SGI that isn't active?\n"); + cpuSgiActive[iar.ack_id] &= ~(1 << (ctx_id + 8 * iar.cpu_id)); + } else { + if (!(activeInt[intNumToWord(iar.ack_id)] & (1 << intNumToBit(iar.ack_id)))) + panic("Done handling interrupt that isn't active?\n"); + activeInt[intNumToWord(iar.ack_id)] &= ~(1 << intNumToBit(iar.ack_id)); + } updateRunPri(); - DPRINTF(Interrupt, "CPU done handling interrupt IAR = %d\n", tmp); + DPRINTF(Interrupt, "CPU %d done handling interrupt IAR = %d from cpu %d\n", + ctx_id, iar.ack_id, iar.cpu_id); break; default: panic("Tried to write Gic cpu at offset %#x\n", daddr); break; } + if (cpuEnabled[ctx_id]) updateIntState(-1); pkt->makeAtomicResponse(); return cpuPioDelay; } void -Gic::softInt(SWI swi) +Gic::softInt(int ctx_id, SWI swi) { - warn("Should be causing software interrupt"); + switch (swi.list_type) { + case 1: + // interrupt all + uint8_t cpu_list; + cpu_list = 0; + for (int x = 0; x < CPU_MAX; x++) + cpu_list |= cpuEnabled[x] ? 1 << x : 0; + swi.cpu_list = cpu_list; + break; + case 2: + // interrupt requesting cpu only + swi.cpu_list = 1 << ctx_id; + break; + // else interrupt cpus specified + } + + DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx_id, + swi.cpu_list); + for (int i = 0; i < CPU_MAX; i++) { + DPRINTF(IPI, "Processing CPU %d\n", i); + if (!cpuEnabled[i]) + continue; + if (swi.cpu_list & (1 << i)) + cpuSgiPending[swi.sgi_id] |= (1 << i) << 8*ctx_id; + DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id, cpuSgiPending[swi.sgi_id]); + } + updateIntState(-1); } +uint64_t +Gic::genSwiMask(int cpu) +{ + switch (cpu) { + case 0: + return 0x0101010101010101; + case 1: + return 0x0202020202020202; + case 2: + return 0x0404040404040404; + case 3: + return 0x0808080808080808; + case 4: + return 0x1010101010101010; + case 5: + return 0x2020202020202020; + case 6: + return 0x4040404040404040; + case 7: + return 0x8080808080808080; + default: + panic("Invalid CPU ID\n"); + } +} void Gic::updateIntState(int hint) { - /*@todo use hint to do less work. */ - int highest_int = SPURIOUS_INT; - // Priorities below that set in ICCPMR can be ignored - uint8_t highest_pri = cpuPriority[0]; + for (int cpu = 0; cpu < CPU_MAX; cpu++) { + if (!cpuEnabled[cpu]) + continue; + if (cpu >= sys->numContexts()) + break; - for (int x = 0; x < (itLines/32) ; x++) { - if (intEnabled[x] & pendingInt[x]) { - for (int y = 0; y < 32; y++) { - if (bits(intEnabled[x], y) & bits(pendingInt[x], y)) - if (intPriority[x*32+y] < highest_pri) { - highest_pri = intPriority[x*32+y]; - highest_int = x*32 + y; - } + /*@todo use hint to do less work. */ + int highest_int = SPURIOUS_INT; + // Priorities below that set in ICCPMR can be ignored + uint8_t highest_pri = cpuPriority[cpu]; + + // Check SGIs + for (int swi = 0; swi < SGI_MAX; swi++) { + if (!cpuSgiPending[swi]) + continue; + if (cpuSgiPending[swi] & genSwiMask(cpu)) + if (highest_pri > intPriority[swi]) { + highest_pri = intPriority[swi]; + highest_int = swi; + } + } + // Check other ints + for (int x = 0; x < (itLines/32) ; x++) { + if (intEnabled[x] & pendingInt[x]) { + for (int y = 0; y < 32; y++) { + if (bits(intEnabled[x], y) & bits(pendingInt[x], y)) + if (intPriority[x*32+y] < highest_pri) { + highest_pri = intPriority[x*32+y]; + highest_int = x*32 + y; + } + } } } - } - if (highest_int == SPURIOUS_INT) - return; + cpuHighestInt[cpu] = highest_int; - cpuHighestInt[0] = highest_int; + if (highest_int == SPURIOUS_INT) + continue; + /* @todo make this work for more than one cpu, need to handle 1:N, N:N + * models */ + if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) && + !(activeInt[intNumToWord(highest_int)] & (1 << intNumToBit(highest_int)))) { + /* @todo delay interrupt by some time to deal with calculation delay */ - /* @todo make this work for more than one cpu, need to handle 1:N, N:N - * models */ - if (enabled && cpuEnabled[0] && (highest_pri < cpuPriority[0])) { - /* @todo delay interrupt by some time to deal with calculation delay */ - /* @todo only interrupt if we've haven't already interrupted for this - * int !!!!!!!!!! */ - DPRINTF(Interrupt, "Posting interrupt %d to cpu0\n", highest_int); - platform->intrctrl->post(0, ArmISA::INT_IRQ, 0); + /* @todo only interrupt if we've haven't already interrupted for this + * int !!!!!!!!!! <-- Done*/ + DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int, + cpu); + platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0); + } } } void Gic::updateRunPri() { - uint8_t maxPriority = 0xff; - for (int i = 0 ; i < itLines ; i++){ - if ( activeInt[intNumToWord(i)] & (1 << intNumToBit(i))){ - if (intPriority[i] < maxPriority) maxPriority = intPriority[i]; + for (int cpu = 0; cpu < CPU_MAX; cpu++) { + uint8_t maxPriority = 0xff; + for (int i = 0 ; i < itLines ; i++){ + if (i < SGI_MAX) { + if ((cpuSgiActive[i] & genSwiMask(cpu)) && + (intPriority[i] < maxPriority)) + maxPriority = intPriority[i]; + } else { + if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i))) + if (intPriority[i] < maxPriority) + maxPriority = intPriority[i]; + } } + iccrpr[cpu] = maxPriority; } - iccrpr[0] = maxPriority; } + void Gic::sendInt(uint32_t num) { @@ -504,17 +632,19 @@ SERIALIZE_SCALAR(enabled); SERIALIZE_SCALAR(itLines); SERIALIZE_SCALAR(itLinesLog2); - SERIALIZE_ARRAY(intEnabled, 32); - SERIALIZE_ARRAY(pendingInt, 32); - SERIALIZE_ARRAY(activeInt, 32); - SERIALIZE_ARRAY(iccrpr, 8); - SERIALIZE_ARRAY(intPriority, 1020); - SERIALIZE_ARRAY(cpuTarget, 1020); + SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX); + SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX); + SERIALIZE_ARRAY(activeInt, INT_BITS_MAX); + SERIALIZE_ARRAY(iccrpr, CPU_MAX); + SERIALIZE_ARRAY(intPriority, INT_LINES_MAX); + SERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX); SERIALIZE_ARRAY(intConfig, 64); - SERIALIZE_ARRAY(cpuEnabled, 8); - SERIALIZE_ARRAY(cpuPriority, 8); - SERIALIZE_ARRAY(cpuBpr, 8); - SERIALIZE_ARRAY(cpuHighestInt, 8); + SERIALIZE_ARRAY(cpuEnabled, CPU_MAX); + SERIALIZE_ARRAY(cpuPriority, CPU_MAX); + SERIALIZE_ARRAY(cpuBpr, CPU_MAX); + SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX); + SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX); + SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX); SERIALIZE_SCALAR(irqEnable); } @@ -530,17 +660,19 @@ UNSERIALIZE_SCALAR(enabled); UNSERIALIZE_SCALAR(itLines); UNSERIALIZE_SCALAR(itLinesLog2); - UNSERIALIZE_ARRAY(intEnabled, 32); - UNSERIALIZE_ARRAY(pendingInt, 32); - UNSERIALIZE_ARRAY(activeInt, 32); - UNSERIALIZE_ARRAY(iccrpr, 8); - UNSERIALIZE_ARRAY(intPriority, 1020); - UNSERIALIZE_ARRAY(cpuTarget, 1020); - UNSERIALIZE_ARRAY(intConfig, 64); - UNSERIALIZE_ARRAY(cpuEnabled, 8); - UNSERIALIZE_ARRAY(cpuPriority, 8); - UNSERIALIZE_ARRAY(cpuBpr, 8); - UNSERIALIZE_ARRAY(cpuHighestInt, 8); + UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX); + UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX); + UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX); + UNSERIALIZE_ARRAY(iccrpr, CPU_MAX); + UNSERIALIZE_ARRAY(intPriority, INT_LINES_MAX); + UNSERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX); + UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX*2); + UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX); + UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX); + UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX); + UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX); + UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX); + UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX); UNSERIALIZE_SCALAR(irqEnable); }