changeset ea5a46abdcca in /z/repo/m5 details: http://repo.m5sim.org/m5?cmd=changeset;node=ea5a46abdcca description: ARM: Make GIC handle IPIs and multiple processors.
diffstat: src/dev/arm/RealView.py | 3 +- src/dev/arm/gic.cc | 450 +++++++++++++++++++++++++++++++++-------------- src/dev/arm/gic.hh | 75 ++++++- 3 files changed, 377 insertions(+), 151 deletions(-) diffs (truncated from 881 to 300 lines): diff -r 0cc4594abf28 -r ea5a46abdcca src/dev/arm/RealView.py --- a/src/dev/arm/RealView.py Wed May 04 20:38:27 2011 -0500 +++ b/src/dev/arm/RealView.py Wed May 04 20:38:27 2011 -0500 @@ -82,7 +82,8 @@ dist_addr = Param.Addr(0x1f001000, "Address for distributor") cpu_addr = Param.Addr(0x1f000100, "Address for cpu") dist_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to distributor") - cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu") + cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu interface") + int_latency = Param.Latency('10ns', "Delay for interrupt to get to CPU") it_lines = Param.UInt32(128, "Number of interrupt lines supported (max = 1020)") class AmbaFake(AmbaDevice): diff -r 0cc4594abf28 -r ea5a46abdcca src/dev/arm/gic.cc --- a/src/dev/arm/gic.cc Wed May 04 20:38:27 2011 -0500 +++ b/src/dev/arm/gic.cc Wed May 04 20:38:27 2011 -0500 @@ -42,11 +42,10 @@ */ #include "base/trace.hh" -#include "cpu/intr_control.hh" #include "debug/Checkpoint.hh" #include "debug/GIC.hh" +#include "debug/IPI.hh" #include "dev/arm/gic.hh" -#include "dev/platform.hh" #include "dev/terminal.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" @@ -54,32 +53,40 @@ Gic::Gic(const Params *p) : PioDevice(p),distAddr(p->dist_addr), cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay), cpuPioDelay(p->cpu_pio_delay), - enabled(false), itLines(p->it_lines) + intLatency(p->int_latency), enabled(false), itLines(p->it_lines) { 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; + postIntEvent[x] = new PostIntEvent(x, p->platform); } + 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 @@ -117,7 +124,7 @@ Addr daddr = pkt->getAddr() - distAddr; pkt->allocate(); - DPRINTF(Interrupt, "gic distributor read register %#x\n", daddr); + DPRINTF(GIC, "gic distributor read register %#x\n", daddr); if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) { assert((daddr-ICDISER_ST) >> 2 < 32); @@ -152,9 +159,9 @@ if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) { Addr int_num; int_num = daddr - ICDIPR_ST; - assert(int_num < 1020); + assert(int_num < INT_LINES_MAX); DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num); - switch(pkt->getSize()){ + switch(pkt->getSize()) { case 1: pkt->set<uint8_t>(intPriority[int_num]); break; @@ -169,25 +176,35 @@ intPriority[int_num+3] << 24); break; default: - panic("Invalid access size while reading, priority registers in Gic: %d", pkt->getSize()); + panic("Invalid size while reading priority regs in GIC: %d\n", + pkt->getSize()); } goto done; } if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) { Addr int_num; - int_num = (daddr-ICDIPTR_ST) << 2; - assert(int_num < 1020); + int_num = (daddr-ICDIPTR_ST) ; + DPRINTF(GIC, "Reading processor target register for int# %#x \n", + int_num); + assert(int_num < INT_LINES_MAX); - // First 31 interrupts only target single processor + // First 31 interrupts only target single processor (SGI) if (int_num > 31) { - pkt->set<uint32_t>(cpuTarget[int_num] | - cpuTarget[int_num+1] << 8 | - cpuTarget[int_num+2] << 16 | - cpuTarget[int_num+3] << 24) ; + if (pkt->getSize() == 1) { + pkt->set<uint8_t>(cpuTarget[int_num]); + } else { + assert(pkt->getSize() == 4); + int_num = mbits(int_num, 31, 2); + pkt->set<uint32_t>(cpuTarget[int_num] | + cpuTarget[int_num+1] << 8 | + cpuTarget[int_num+2] << 16 | + cpuTarget[int_num+3] << 24) ; + } } else { - /** @todo should be processor id */ - pkt->set<uint32_t>(0); + int ctx_id = pkt->req->contextId(); + assert(ctx_id < sys->numRunningContexts()); + pkt->set<uint32_t>(ctx_id); } goto done; } @@ -206,10 +223,9 @@ pkt->set<uint32_t>(enabled); break; case ICDICTR: - /* @todo this needs to refelct the number of CPUs in the system */ uint32_t tmp; - tmp = 0 << 5 | // cpu number - (itLines/32 -1); + tmp = ((sys->numRunningContexts() - 1) << 5) | + (itLines/INT_BITS_MAX -1); pkt->set<uint32_t>(tmp); break; default: @@ -227,30 +243,59 @@ 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(); + assert(ctx_id < sys->numRunningContexts()); + + DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr, + ctx_id); switch(daddr) { case ICCICR: - pkt->set<uint32_t>(cpuEnabled[0]); + pkt->set<uint32_t>(cpuEnabled[ctx_id]); break; case ICCPMR: - pkt->set<uint32_t>(cpuPriority[0]); + pkt->set<uint32_t>(cpuPriority[ctx_id]); break; case ICCBPR: - pkt->set<uint32_t>(cpuBpr[0]); + pkt->set<uint32_t>(cpuBpr[ctx_id]); break; case ICCIAR: - DPRINTF(Interrupt, "CPU reading IAR = %d\n", cpuHighestInt[0]); - if(enabled && cpuEnabled[0]){ - pkt->set<uint32_t>(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; + } + } + uint64_t sgi_num = ULL(1) << (ctx_id + 8 * iar.cpu_id); + cpuSgiActive[iar.ack_id] |= sgi_num; + cpuSgiPending[iar.ack_id] &= ~sgi_num; + } else { + uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]); + activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num; + updateRunPri(); + pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num; + } + + 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<uint32_t>(iar); + platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0); } else { pkt->set<uint32_t>(SPURIOUS_INT); } @@ -278,58 +323,64 @@ Addr daddr = pkt->getAddr() - distAddr; pkt->allocate(); - DPRINTF(Interrupt, "gic distributor write register %#x size %#x\n", - daddr, pkt->getSize()); + assert(pkt->req->hasContextId()); + int ctx_id = pkt->req->contextId(); + + DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n", + daddr, pkt->getSize(), pkt->get<uint32_t>()); if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) { assert((daddr-ICDISER_ST) >> 2 < 32); - intEnabled[(daddr-ICDISER_ST)>>2] |= pkt->get<uint32_t>(); + intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get<uint32_t>(); goto done; } if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) { assert((daddr-ICDICER_ST) >> 2 < 32); - intEnabled[(daddr-ICDICER_ST)>>2] &= ~pkt->get<uint32_t>(); + intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get<uint32_t>(); goto done; } if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) { assert((daddr-ICDISPR_ST) >> 2 < 32); - pendingInt[(daddr-ICDISPR_ST)>>2] |= pkt->get<uint32_t>(); - updateIntState((daddr-ICDISPR_ST)>>2); + pendingInt[(daddr-ICDISPR_ST) >> 2] |= pkt->get<uint32_t>(); + pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed + updateIntState((daddr-ICDISPR_ST) >> 2); goto done; } if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) { assert((daddr-ICDICPR_ST) >> 2 < 32); - pendingInt[(daddr-ICDICPR_ST)>>2] &= ~pkt->get<uint32_t>(); - updateIntState((daddr-ICDICPR_ST)>>2); + pendingInt[(daddr-ICDICPR_ST) >> 2] &= ~pkt->get<uint32_t>(); + pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed + updateIntState((daddr-ICDICPR_ST) >> 2); goto done; } if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) { Addr int_num = daddr - ICDIPR_ST; - assert(int_num < 1020); + assert(int_num < INT_LINES_MAX); uint32_t tmp; - switch(pkt->getSize()){ + switch(pkt->getSize()) { case 1: tmp = pkt->get<uint8_t>(); - intPriority[int_num] = tmp & 0xff; + intPriority[int_num] = bits(tmp, 7, 0); break; case 2: tmp = pkt->get<uint16_t>(); - intPriority[int_num] = tmp & 0xff; - intPriority[int_num + 1] = (tmp >> 8) & 0xff; + intPriority[int_num] = bits(tmp, 7, 0); + intPriority[int_num + 1] = bits(tmp, 15, 8); break; case 4: tmp = pkt->get<uint32_t>(); - intPriority[int_num] = tmp & 0xff; - intPriority[int_num + 1] = (tmp >> 8) & 0xff; - intPriority[int_num + 2] = (tmp >> 16) & 0xff; _______________________________________________ m5-dev mailing list m5-dev@m5sim.org http://m5sim.org/mailman/listinfo/m5-dev