From 6fa936b021ac4d3030d20de5d037f1e7dd902cd9 Mon Sep 17 00:00:00 2001 From: Karthik Sangaiah Date: Fri, 18 Sep 2015 16:49:28 +0100 Subject: 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. --- src/dev/arm/gic_pl390.cc | 186 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 132 insertions(+), 54 deletions(-) (limited to 'src/dev/arm/gic_pl390.cc') 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(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(); 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() & 0x200); + DPRINTF(GIC, "gem5 extensions %s\n", gem5ExtensionsEnabled ? "enabled" : "disabled"); + break; case ICDSGIR: softInt(ctx_id, pkt->get()); 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 * -- cgit v1.2.3