diff options
author | Karthik Sangaiah <karthik.sangaiah@arm.com> | 2015-09-18 16:49:28 +0100 |
---|---|---|
committer | Karthik Sangaiah <karthik.sangaiah@arm.com> | 2015-09-18 16:49:28 +0100 |
commit | 6fa936b021ac4d3030d20de5d037f1e7dd902cd9 (patch) | |
tree | bbbaf5a03f3b79caeae43a6c7bc257dc208b3f52 /src | |
parent | 413f3088eabf385507e854d74c0a5861e4d2856b (diff) | |
download | gem5-6fa936b021ac4d3030d20de5d037f1e7dd902cd9.tar.xz |
dev, arm: Add gem5 extensions to support more than 8 cores
Previous ARM-based simulations were limited to 8 cores due to
limitations in GICv2 and earlier. This changeset adds a set of
gem5-specific extensions that enable support for up to 256 cores.
When the gem5 extensions are enabled, the GIC uses CPU IDs instead of
a CPU bitmask in the GIC's register interface. To OS can enable the
extensions by setting bit 0x200 in ICDICTR.
This changeset is based on previous work by Matt Evans.
Diffstat (limited to 'src')
-rw-r--r-- | src/dev/arm/gic_pl390.cc | 186 | ||||
-rw-r--r-- | src/dev/arm/gic_pl390.hh | 13 |
2 files changed, 143 insertions, 56 deletions
diff --git a/src/dev/arm/gic_pl390.cc b/src/dev/arm/gic_pl390.cc index 0de8a86c4..a6827ffe3 100644 --- a/src/dev/arm/gic_pl390.cc +++ b/src/dev/arm/gic_pl390.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013 ARM Limited + * Copyright (c) 2010, 2013, 2015 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -93,6 +93,8 @@ Pl390::Pl390(const Params *p) for (int x = 0; x < CPU_MAX; x++) { cpuPpiActive[x] = 0; cpuPpiPending[x] = 0; + cpuSgiActiveExt[x] = 0; + cpuSgiPendingExt[x] = 0; } for (int i = 0; i < CPU_MAX; i++) { @@ -100,6 +102,8 @@ Pl390::Pl390(const Params *p) bankedIntPriority[i][j] = 0; } } + + gem5ExtensionsEnabled = false; } Tick @@ -226,8 +230,13 @@ Pl390::readDistributor(PacketPtr pkt) } } else { assert(ctx_id < sys->numRunningContexts()); + uint32_t ctx_mask; + if (gem5ExtensionsEnabled) { + ctx_mask = ctx_id; + } else { // convert the CPU id number into a bit mask - uint32_t ctx_mask = power(2, ctx_id); + ctx_mask = power(2, ctx_id); + } // replicate the 8-bit mask 4 times in a 32-bit word ctx_mask |= ctx_mask << 8; ctx_mask |= ctx_mask << 16; @@ -252,7 +261,12 @@ Pl390::readDistributor(PacketPtr pkt) case ICDICTR: uint32_t tmp; tmp = ((sys->numRunningContexts() - 1) << 5) | - (itLines/INT_BITS_MAX -1); + (itLines/INT_BITS_MAX -1) | + 0x100; + /* The 0x100 is a made-up flag to show that gem5 extensions + * are available, + * write 0x200 to this register to enable it. + */ pkt->set<uint32_t>(tmp); break; default: @@ -297,21 +311,27 @@ Pl390::readCpu(PacketPtr pkt) 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", + if (!gem5ExtensionsEnabled) { + panic_if(!cpuSgiPending[active_int], + "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; + for (int x = 0; x < sys->numRunningContexts(); 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 { + uint64_t sgi_num = ULL(1) << iar.ack_id; + cpuSgiActiveExt[ctx_id] |= sgi_num; + cpuSgiPendingExt[ctx_id] &= ~sgi_num; } - 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 if (active_int < (SGI_MAX + PPI_MAX) ) { uint32_t int_num = 1 << (cpuHighestInt[ctx_id] - SGI_MAX); cpuPpiActive[ctx_id] |= int_num; @@ -478,6 +498,13 @@ Pl390::writeDistributor(PacketPtr pkt) enabled = pkt->get<uint32_t>(); DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled); break; + case ICDICTR: + /* 0x200 is a made-up flag to enable gem5 extension functionality. + * This reg is not normally written. + */ + gem5ExtensionsEnabled = !!(pkt->get<uint32_t>() & 0x200); + DPRINTF(GIC, "gem5 extensions %s\n", gem5ExtensionsEnabled ? "enabled" : "disabled"); + break; case ICDSGIR: softInt(ctx_id, pkt->get<uint32_t>()); break; @@ -518,13 +545,18 @@ Pl390::writeCpu(PacketPtr pkt) if (iar.ack_id < SGI_MAX) { // Clear out the bit that corrseponds to the cleared int uint64_t clr_int = ULL(1) << (ctx_id + 8 * iar.cpu_id); - if (!(cpuSgiActive[iar.ack_id] & clr_int)) + if (!(cpuSgiActive[iar.ack_id] & clr_int) && + !(cpuSgiActiveExt[ctx_id] & (1 << iar.ack_id))) panic("Done handling a SGI that isn't active?\n"); - cpuSgiActive[iar.ack_id] &= ~clr_int; + if (gem5ExtensionsEnabled) + cpuSgiActiveExt[ctx_id] &= ~(1 << iar.ack_id); + else + cpuSgiActive[iar.ack_id] &= ~clr_int; } else if (iar.ack_id < (SGI_MAX + PPI_MAX) ) { uint32_t int_num = 1 << (iar.ack_id - SGI_MAX); if (!(cpuPpiActive[ctx_id] & int_num)) - panic("CPU %d Done handling a PPI interrupt that isn't active?\n", ctx_id); + panic("CPU %d Done handling a PPI interrupt " + "that isn't active?\n", ctx_id); cpuPpiActive[ctx_id] &= ~int_num; } else { uint32_t int_num = 1 << intNumToBit(iar.ack_id); @@ -549,31 +581,69 @@ Pl390::writeCpu(PacketPtr pkt) void Pl390::softInt(ContextID ctx_id, SWI swi) { - 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 - } + if (gem5ExtensionsEnabled) { + switch (swi.list_type) { + case 0: { + // interrupt cpus specified + int dest = swi.cpu_list; + DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n", + ctx_id, dest); + if (cpuEnabled[dest]) { + cpuSgiPendingExt[dest] |= (1 << swi.sgi_id); + DPRINTF(IPI, "SGI[%d]=%#x\n", dest, + cpuSgiPendingExt[dest]); + } + } break; + case 1: { + // interrupt all + for (int i = 0; i < sys->numContexts(); i++) { + DPRINTF(IPI, "Processing CPU %d\n", i); + if (!cpuEnabled[i]) + continue; + cpuSgiPendingExt[i] |= 1 << swi.sgi_id; + DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id, + cpuSgiPendingExt[i]); + } + } break; + case 2: { + // Interrupt requesting cpu only + DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n", + ctx_id, ctx_id); + if (cpuEnabled[ctx_id]) { + cpuSgiPendingExt[ctx_id] |= (1 << swi.sgi_id); + DPRINTF(IPI, "SGI[%d]=%#x\n", ctx_id, + cpuSgiPendingExt[ctx_id]); + } + } break; + } + } else { + switch (swi.list_type) { + case 1: + // interrupt all + uint8_t cpu_list; + cpu_list = 0; + for (int x = 0; x < sys->numContexts(); 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]); + DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx_id, + swi.cpu_list); + for (int i = 0; i < sys->numContexts(); 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); } @@ -581,7 +651,7 @@ Pl390::softInt(ContextID ctx_id, SWI swi) uint64_t Pl390::genSwiMask(int cpu) { - if (cpu > 7) + if (cpu > sys->numContexts()) panic("Invalid CPU ID\n"); return ULL(0x0101010101010101) << cpu; } @@ -589,11 +659,9 @@ Pl390::genSwiMask(int cpu) void Pl390::updateIntState(int hint) { - for (int cpu = 0; cpu < CPU_MAX; cpu++) { + for (int cpu = 0; cpu < sys->numContexts(); cpu++) { if (!cpuEnabled[cpu]) continue; - if (cpu >= sys->numContexts()) - break; /*@todo use hint to do less work. */ int highest_int = SPURIOUS_INT; @@ -602,9 +670,10 @@ Pl390::updateIntState(int hint) // Check SGIs for (int swi = 0; swi < SGI_MAX; swi++) { - if (!cpuSgiPending[swi]) + if (!cpuSgiPending[swi] && !cpuSgiPendingExt[cpu]) continue; - if (cpuSgiPending[swi] & genSwiMask(cpu)) + if ((cpuSgiPending[swi] & genSwiMask(cpu)) || + (cpuSgiPendingExt[cpu] & (1 << swi))) if (highest_pri > bankedIntPriority[cpu][swi]) { highest_pri = bankedIntPriority[cpu][swi]; highest_int = swi; @@ -635,7 +704,10 @@ Pl390::updateIntState(int hint) */ if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) && (intPriority[int_nm] < highest_pri)) - if ( (!mp_sys) || (cpuTarget[int_nm] & (1 << cpu))) { + if ( (!mp_sys) || + (!gem5ExtensionsEnabled && (cpuTarget[int_nm] & (1 << cpu))) || + (gem5ExtensionsEnabled && (cpuTarget[int_nm] == cpu)) + ) { highest_pri = intPriority[int_nm]; highest_int = int_nm; } @@ -664,13 +736,14 @@ Pl390::updateIntState(int hint) void Pl390::updateRunPri() { - for (int cpu = 0; cpu < CPU_MAX; cpu++) { + for (int cpu = 0; cpu < sys->numContexts(); cpu++) { if (!cpuEnabled[cpu]) continue; uint8_t maxPriority = 0xff; for (int i = 0; i < itLines; i++){ if (i < SGI_MAX) { - if ((cpuSgiActive[i] & genSwiMask(cpu)) && + if (((cpuSgiActive[i] & genSwiMask(cpu)) || + (cpuSgiActiveExt[cpu] & (1 << i))) && (bankedIntPriority[cpu][i] < maxPriority)) maxPriority = bankedIntPriority[cpu][i]; } else if (i < (SGI_MAX + PPI_MAX)) { @@ -693,7 +766,7 @@ Pl390::sendInt(uint32_t num) { DPRINTF(Interrupt, "Received Interupt number %d, cpuTarget %#x: \n", num, cpuTarget[num]); - if (cpuTarget[num] & (cpuTarget[num] - 1)) + if ((cpuTarget[num] & (cpuTarget[num] - 1)) && !gem5ExtensionsEnabled) panic("Multiple targets for peripheral interrupts is not supported\n"); pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num); updateIntState(intNumToWord(num)); @@ -766,6 +839,8 @@ Pl390::serialize(CheckpointOut &cp) const SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX); SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX); SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX); + SERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX); + SERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX); SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX); SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX)); @@ -778,7 +853,7 @@ Pl390::serialize(CheckpointOut &cp) const } } SERIALIZE_ARRAY(interrupt_time, CPU_MAX); - + SERIALIZE_SCALAR(gem5ExtensionsEnabled); } void @@ -806,6 +881,8 @@ Pl390::unserialize(CheckpointIn &cp) UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX); UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX); UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX); + UNSERIALIZE_ARRAY(cpuSgiActiveExt, CPU_MAX); + UNSERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX); UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX); UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX)); @@ -818,7 +895,8 @@ Pl390::unserialize(CheckpointIn &cp) if (interrupt_time[cpu]) schedule(postIntEvent[cpu], interrupt_time[cpu]); } - + if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled)) + gem5ExtensionsEnabled = false; } Pl390 * diff --git a/src/dev/arm/gic_pl390.hh b/src/dev/arm/gic_pl390.hh index bc7bd8c81..cddd0d912 100644 --- a/src/dev/arm/gic_pl390.hh +++ b/src/dev/arm/gic_pl390.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013 ARM Limited + * Copyright (c) 2010, 2013, 2015 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -108,7 +108,7 @@ class Pl390 : public BaseGic /** 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 CPU_MAX = 256; // 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; @@ -143,6 +143,9 @@ class Pl390 : public BaseGic /** Gic enabled */ bool enabled; + /** gem5 many-core extension enabled by driver */ + bool gem5ExtensionsEnabled; + /** Number of itLines enabled */ uint32_t itLines; @@ -196,6 +199,12 @@ class Pl390 : public BaseGic uint64_t cpuSgiPending[SGI_MAX]; uint64_t cpuSgiActive[SGI_MAX]; + /** SGI pending arrays for gem5 GIC extension mode, which instead keeps + * 16 SGI pending bits for each of the (large number of) CPUs. + */ + uint32_t cpuSgiPendingExt[CPU_MAX]; + uint32_t cpuSgiActiveExt[CPU_MAX]; + /** One bit per private peripheral interrupt. Only upper 16 bits * will be used since PPI interrupts are numberred from 16 to 32 */ uint32_t cpuPpiPending[CPU_MAX]; |