From 81be8b9d157a038c1d8f3ebf7e2ec8eba0eac935 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Thu, 25 Oct 2012 14:05:24 +0100 Subject: arm: Create a GIC base class and make the PL390 derive from it This patch moves the GIC interface to a separate base class and makes all interrupt devices use that base class instead of a pointer to the PL390 implementation. This allows us to have multiple GIC implementations. Future implementations will allow in-kernel GIC implementations when using hardware virtualization. --HG-- rename : src/dev/arm/gic.cc => src/dev/arm/gic_pl390.cc rename : src/dev/arm/gic.hh => src/dev/arm/gic_pl390.hh --- src/dev/arm/Gic.py | 61 +++ src/dev/arm/RealView.py | 28 +- src/dev/arm/SConscript | 4 +- src/dev/arm/amba_device.hh | 6 +- src/dev/arm/base_gic.cc | 58 +++ src/dev/arm/base_gic.hh | 94 +++++ src/dev/arm/gic.cc | 843 ------------------------------------------ src/dev/arm/gic.hh | 320 ---------------- src/dev/arm/gic_pl390.cc | 843 ++++++++++++++++++++++++++++++++++++++++++ src/dev/arm/gic_pl390.hh | 319 ++++++++++++++++ src/dev/arm/kmi.hh | 2 - src/dev/arm/pl011.cc | 2 +- src/dev/arm/pl011.hh | 4 +- src/dev/arm/pl111.cc | 3 +- src/dev/arm/pl111.hh | 1 - src/dev/arm/realview.cc | 2 +- src/dev/arm/realview.hh | 6 +- src/dev/arm/timer_cpulocal.cc | 2 +- src/dev/arm/timer_cpulocal.hh | 4 +- src/dev/arm/timer_sp804.cc | 2 +- src/dev/arm/timer_sp804.hh | 4 +- 21 files changed, 1405 insertions(+), 1203 deletions(-) create mode 100644 src/dev/arm/Gic.py create mode 100644 src/dev/arm/base_gic.cc create mode 100644 src/dev/arm/base_gic.hh delete mode 100644 src/dev/arm/gic.cc delete mode 100644 src/dev/arm/gic.hh create mode 100644 src/dev/arm/gic_pl390.cc create mode 100644 src/dev/arm/gic_pl390.hh (limited to 'src/dev/arm') diff --git a/src/dev/arm/Gic.py b/src/dev/arm/Gic.py new file mode 100644 index 000000000..0461758ed --- /dev/null +++ b/src/dev/arm/Gic.py @@ -0,0 +1,61 @@ +# Copyright (c) 2012 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Andreas Sandberg + +from m5.params import * +from m5.proxy import * + +from Device import PioDevice +from Platform import Platform + +class BaseGic(PioDevice): + type = 'BaseGic' + abstract = True + cxx_header = "dev/arm/base_gic.hh" + + platform = Param.Platform(Parent.any, "Platform this device is part of.") + +class Pl390(BaseGic): + type = 'Pl390' + cxx_header = "dev/arm/gic_pl390.hh" + + 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 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)") + diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py index f2fc9c0af..f01572e40 100644 --- a/src/dev/arm/RealView.py +++ b/src/dev/arm/RealView.py @@ -50,6 +50,7 @@ from Platform import Platform from Terminal import Terminal from Uart import Uart from SimpleMemory import SimpleMemory +from Gic import * class AmbaDevice(BasicPioDevice): type = 'AmbaDevice' @@ -61,7 +62,7 @@ class AmbaIntDevice(AmbaDevice): type = 'AmbaIntDevice' abstract = True cxx_header = "dev/arm/amba_device.hh" - gic = Param.Gic(Parent.any, "Gic to use for interrupting") + gic = Param.BaseGic(Parent.any, "Gic to use for interrupting") int_num = Param.UInt32("Interrupt number that connects to GIC") int_delay = Param.Latency("100ns", "Time between action and interrupt generation by device") @@ -72,7 +73,7 @@ class AmbaDmaDevice(DmaDevice): cxx_header = "dev/arm/amba_device.hh" pio_addr = Param.Addr("Address for AMBA slave interface") pio_latency = Param.Latency("10ns", "Time between action and write/read result by AMBA DMA Device") - gic = Param.Gic(Parent.any, "Gic to use for interrupting") + gic = Param.BaseGic(Parent.any, "Gic to use for interrupting") int_num = Param.UInt32("Interrupt number that connects to GIC") amba_id = Param.UInt32("ID of AMBA device for kernel detection") @@ -87,17 +88,6 @@ class RealViewCtrl(BasicPioDevice): proc_id1 = Param.UInt32(0x0C000222, "Processor ID, SYS_PROCID1") idreg = Param.UInt32(0x00000000, "ID Register, SYS_ID") -class Gic(PioDevice): - type = 'Gic' - cxx_header = "dev/arm/gic.hh" - platform = Param.Platform(Parent.any, "Platform this device is part of.") - 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 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): type = 'AmbaFake' cxx_header = "dev/arm/amba_fake.hh" @@ -107,7 +97,7 @@ class AmbaFake(AmbaDevice): class Pl011(Uart): type = 'Pl011' cxx_header = "dev/arm/pl011.hh" - gic = Param.Gic(Parent.any, "Gic to use for interrupting") + gic = Param.BaseGic(Parent.any, "Gic to use for interrupting") int_num = Param.UInt32("Interrupt number that connects to GIC") end_on_eot = Param.Bool(False, "End the simulation when a EOT is received on the UART") int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART") @@ -115,7 +105,7 @@ class Pl011(Uart): class Sp804(AmbaDevice): type = 'Sp804' cxx_header = "dev/arm/timer_sp804.hh" - gic = Param.Gic(Parent.any, "Gic to use for interrupting") + gic = Param.BaseGic(Parent.any, "Gic to use for interrupting") int_num0 = Param.UInt32("Interrupt number that connects to GIC") clock0 = Param.Clock('1MHz', "Clock speed of the input") int_num1 = Param.UInt32("Interrupt number that connects to GIC") @@ -125,7 +115,7 @@ class Sp804(AmbaDevice): class CpuLocalTimer(BasicPioDevice): type = 'CpuLocalTimer' cxx_header = "dev/arm/timer_cpulocal.hh" - gic = Param.Gic(Parent.any, "Gic to use for interrupting") + gic = Param.BaseGic(Parent.any, "Gic to use for interrupting") int_num_timer = Param.UInt32("Interrrupt number used per-cpu to GIC") int_num_watchdog = Param.UInt32("Interrupt number for per-cpu watchdog to GIC") # Override the default clock @@ -174,7 +164,7 @@ class RealView(Platform): class RealViewPBX(RealView): uart = Pl011(pio_addr=0x10009000, int_num=44) realview_io = RealViewCtrl(pio_addr=0x10000000) - gic = Gic() + gic = Pl390() timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000) timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000) local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x1f000600) @@ -262,7 +252,7 @@ class RealViewPBX(RealView): class RealViewEB(RealView): uart = Pl011(pio_addr=0x10009000, int_num=44) realview_io = RealViewCtrl(pio_addr=0x10000000) - gic = Gic(dist_addr=0x10041000, cpu_addr=0x10040000) + gic = Pl390(dist_addr=0x10041000, cpu_addr=0x10040000) timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000) timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000) clcd = Pl111(pio_addr=0x10020000, int_num=23) @@ -338,7 +328,7 @@ class VExpress_EMM(RealView): pci_cfg_base = 0x30000000 uart = Pl011(pio_addr=0x1c090000, int_num=37) realview_io = RealViewCtrl(proc_id0=0x14000000, proc_id1=0x14000000, pio_addr=0x1C010000) - gic = Gic(dist_addr=0x2C001000, cpu_addr=0x2C002000) + gic = Pl390(dist_addr=0x2C001000, cpu_addr=0x2C002000) local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x2C080000) timer0 = Sp804(int_num0=34, int_num1=34, pio_addr=0x1C110000, clock0='1MHz', clock1='1MHz') timer1 = Sp804(int_num0=35, int_num1=35, pio_addr=0x1C120000, clock0='1MHz', clock1='1MHz') diff --git a/src/dev/arm/SConscript b/src/dev/arm/SConscript index a6ead28be..048fe2444 100644 --- a/src/dev/arm/SConscript +++ b/src/dev/arm/SConscript @@ -40,12 +40,14 @@ Import('*') if env['TARGET_ISA'] == 'arm': + SimObject('Gic.py') SimObject('RealView.py') Source('a9scu.cc') Source('amba_device.cc') Source('amba_fake.cc') - Source('gic.cc') + Source('base_gic.cc') + Source('gic_pl390.cc') Source('pl011.cc') Source('pl111.cc') Source('kmi.cc') diff --git a/src/dev/arm/amba_device.hh b/src/dev/arm/amba_device.hh index 92dfed541..6a3ed1c9e 100644 --- a/src/dev/arm/amba_device.hh +++ b/src/dev/arm/amba_device.hh @@ -49,7 +49,7 @@ #ifndef __DEV_ARM_AMBA_DEVICE_HH__ #define __DEV_ARM_AMBA_DEVICE_HH__ -#include "dev/arm/gic.hh" +#include "dev/arm/base_gic.hh" #include "dev/dma_device.hh" #include "dev/io_device.hh" #include "mem/packet.hh" @@ -86,7 +86,7 @@ class AmbaIntDevice : public AmbaDevice { protected: int intNum; - Gic *gic; + BaseGic *gic; Tick intDelay; public: @@ -102,7 +102,7 @@ class AmbaDmaDevice : public DmaDevice Addr pioSize; Tick pioDelay; int intNum; - Gic *gic; + BaseGic *gic; public: typedef AmbaDmaDeviceParams Params; diff --git a/src/dev/arm/base_gic.cc b/src/dev/arm/base_gic.cc new file mode 100644 index 000000000..47e211077 --- /dev/null +++ b/src/dev/arm/base_gic.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#include "dev/arm/base_gic.hh" + +#include "params/BaseGic.hh" + +BaseGic::BaseGic(const Params *p) + : PioDevice(p), + platform(p->platform) +{ +} + +BaseGic::~BaseGic() +{ +} + +const BaseGic::Params * +BaseGic::params() const +{ + return dynamic_cast(_params); +} diff --git a/src/dev/arm/base_gic.hh b/src/dev/arm/base_gic.hh new file mode 100644 index 000000000..d177487ed --- /dev/null +++ b/src/dev/arm/base_gic.hh @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +/** @file + * Base class for ARM GIC implementations + */ + +#ifndef __DEV_ARM_BASE_GIC_H__ +#define __DEV_ARM_BASE_GIC_H__ + +#include "dev/io_device.hh" + +class Platform; + +class BaseGic : public PioDevice +{ + public: + typedef struct BaseGicParams Params; + + BaseGic(const Params *p); + virtual ~BaseGic(); + + const Params * params() const; + + /** + * Post an interrupt from a device that is connected to the GIC. + * + * Depending on the configuration, the GIC will pass this interrupt + * on through to a CPU. + * + * @param num number of interrupt to send + */ + virtual void sendInt(uint32_t num) = 0; + + /** + * Interface call for private peripheral interrupts. + * + * @param num number of interrupt to send + * @param cpu CPU to forward interrupt to + */ + virtual void sendPPInt(uint32_t num, uint32_t cpu) = 0; + + /** + * Clear an interrupt from a device that is connected to the GIC. + * + * Depending on the configuration, the GIC may de-assert it's CPU + * line. + * + * @param num number of interrupt to send + */ + virtual void clearInt(uint32_t num) = 0; + + protected: + /** Platform this GIC belongs to. */ + Platform *platform; +}; + +#endif diff --git a/src/dev/arm/gic.cc b/src/dev/arm/gic.cc deleted file mode 100644 index 725199bc4..000000000 --- a/src/dev/arm/gic.cc +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Copyright (c) 2010 ARM Limited - * All rights reserved - * - * The license below extends only to copyright in the software and shall - * not be construed as granting a license to any other intellectual - * property including but not limited to intellectual property relating - * to a hardware implementation of the functionality of the software - * licensed hereunder. You may use the software subject to the license - * terms below provided that you ensure that this notice is replicated - * unmodified and in its entirety in all distributions of the software, - * modified or unmodified, in source code or in binary form. - * - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Ali Saidi - * Prakash Ramrakhyani - */ - -#include "base/trace.hh" -#include "debug/Checkpoint.hh" -#include "debug/GIC.hh" -#include "debug/IPI.hh" -#include "debug/Interrupt.hh" -#include "dev/arm/gic.hh" -#include "dev/arm/realview.hh" -#include "dev/terminal.hh" -#include "mem/packet.hh" -#include "mem/packet_access.hh" - -Gic::Gic(const Params *p) - : PioDevice(p), platform(p->platform), distAddr(p->dist_addr), - cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay), - cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency), - enabled(false), itLines(p->it_lines) -{ - itLinesLog2 = ceilLog2(itLines); - - for (int x = 0; x < CPU_MAX; x++) { - cpuEnabled[x] = false; - 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 < INT_BITS_MAX; x++) { - intEnabled[x] = 0; - pendingInt[x] = 0; - activeInt[x] = 0; - } - - for (int x = 0; x < INT_LINES_MAX; x++) { - intPriority[x] = 0; - cpuTarget[x] = 0; - } - - 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; - } - for (int x = 0; x < CPU_MAX; x++) { - cpuPpiActive[x] = 0; - cpuPpiPending[x] = 0; - } - - for (int i = 0; i < CPU_MAX; i++) { - for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) { - bankedIntPriority[i][j] = 0; - } - } - - RealView *rv = dynamic_cast(p->platform); - assert(rv); - rv->setGic(this); - -} - -Tick -Gic::read(PacketPtr pkt) -{ - - Addr addr = pkt->getAddr(); - - if (addr >= distAddr && addr < distAddr + DIST_SIZE) - return readDistributor(pkt); - else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE) - return readCpu(pkt); - else - panic("Read to unknown address %#x\n", pkt->getAddr()); -} - - -Tick -Gic::write(PacketPtr pkt) -{ - - Addr addr = pkt->getAddr(); - - if (addr >= distAddr && addr < distAddr + DIST_SIZE) - return writeDistributor(pkt); - else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE) - return writeCpu(pkt); - else - panic("Write to unknown address %#x\n", pkt->getAddr()); -} - -Tick -Gic::readDistributor(PacketPtr pkt) -{ - Addr daddr = pkt->getAddr() - distAddr; - pkt->allocate(); - - int ctx_id = pkt->req->contextId(); - - DPRINTF(GIC, "gic distributor read register %#x\n", daddr); - - if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) { - assert((daddr-ICDISER_ST) >> 2 < 32); - pkt->set(intEnabled[(daddr-ICDISER_ST)>>2]); - goto done; - } - - if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) { - assert((daddr-ICDICER_ST) >> 2 < 32); - pkt->set(intEnabled[(daddr-ICDICER_ST)>>2]); - goto done; - } - - if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) { - assert((daddr-ICDISPR_ST) >> 2 < 32); - pkt->set(pendingInt[(daddr-ICDISPR_ST)>>2]); - goto done; - } - - if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) { - assert((daddr-ICDICPR_ST) >> 2 < 32); - pkt->set(pendingInt[(daddr-ICDICPR_ST)>>2]); - goto done; - } - - if (daddr >= ICDABR_ST && daddr < ICDABR_ED + 4) { - assert((daddr-ICDABR_ST) >> 2 < 32); - pkt->set(activeInt[(daddr-ICDABR_ST)>>2]); - goto done; - } - - if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) { - Addr int_num; - int_num = daddr - ICDIPR_ST; - assert(int_num < INT_LINES_MAX); - DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num); - - uint8_t* int_p; - if (int_num < (SGI_MAX + PPI_MAX)) - int_p = bankedIntPriority[ctx_id]; - else - int_p = intPriority; - - switch (pkt->getSize()) { - case 1: - pkt->set(int_p[int_num]); - break; - case 2: - assert((int_num + 1) < INT_LINES_MAX); - pkt->set(int_p[int_num] | - int_p[int_num+1] << 8); - break; - case 4: - assert((int_num + 3) < INT_LINES_MAX); - pkt->set(int_p[int_num] | - int_p[int_num+1] << 8 | - int_p[int_num+2] << 16 | - int_p[int_num+3] << 24); - break; - default: - 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) ; - 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 (SGI) - if (int_num > 31) { - if (pkt->getSize() == 1) { - pkt->set(cpuTarget[int_num]); - } else { - assert(pkt->getSize() == 4); - int_num = mbits(int_num, 31, 2); - pkt->set(cpuTarget[int_num] | - cpuTarget[int_num+1] << 8 | - cpuTarget[int_num+2] << 16 | - cpuTarget[int_num+3] << 24) ; - } - } else { - int ctx_id = pkt->req->contextId(); - assert(ctx_id < sys->numRunningContexts()); - pkt->set(ctx_id); - } - goto done; - } - - if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) { - assert((daddr-ICDICFR_ST) >> 2 < 64); - /** @todo software generated interrutps and PPIs - * can't be configured in some ways - */ - pkt->set(intConfig[(daddr-ICDICFR_ST)>>2]); - goto done; - } - - switch(daddr) { - case ICDDCR: - pkt->set(enabled); - break; - case ICDICTR: - uint32_t tmp; - tmp = ((sys->numRunningContexts() - 1) << 5) | - (itLines/INT_BITS_MAX -1); - pkt->set(tmp); - break; - default: - panic("Tried to read Gic distributor at offset %#x\n", daddr); - break; - } -done: - pkt->makeAtomicResponse(); - return distPioDelay; -} - -Tick -Gic::readCpu(PacketPtr pkt) -{ - Addr daddr = pkt->getAddr() - cpuAddr; - pkt->allocate(); - - 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(cpuEnabled[ctx_id]); - break; - case ICCPMR: - pkt->set(cpuPriority[ctx_id]); - break; - case ICCBPR: - pkt->set(cpuBpr[ctx_id]); - break; - case ICCIAR: - 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 if (active_int < (SGI_MAX + PPI_MAX) ) { - uint32_t int_num = 1 << (cpuHighestInt[ctx_id] - SGI_MAX); - cpuPpiActive[ctx_id] |= int_num; - updateRunPri(); - cpuPpiPending[ctx_id] &= ~int_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); - pkt->set(iar); - platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0); - } else { - pkt->set(SPURIOUS_INT); - } - - break; - case ICCRPR: - pkt->set(iccrpr[0]); - break; - case ICCHPIR: - pkt->set(0); - panic("Need to implement HPIR"); - break; - default: - panic("Tried to read Gic cpu at offset %#x\n", daddr); - break; - } - pkt->makeAtomicResponse(); - return cpuPioDelay; -} - - -Tick -Gic::writeDistributor(PacketPtr pkt) -{ - Addr daddr = pkt->getAddr() - distAddr; - pkt->allocate(); - - 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()); - - if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) { - assert((daddr-ICDISER_ST) >> 2 < 32); - intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get(); - goto done; - } - - if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) { - assert((daddr-ICDICER_ST) >> 2 < 32); - intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get(); - goto done; - } - - 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; - } - - 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; - } - - if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) { - Addr int_num = daddr - ICDIPR_ST; - assert(int_num < INT_LINES_MAX); - uint8_t* int_p; - if (int_num < (SGI_MAX + PPI_MAX)) - int_p = bankedIntPriority[ctx_id]; - else - int_p = intPriority; - uint32_t tmp; - switch(pkt->getSize()) { - case 1: - tmp = pkt->get(); - int_p[int_num] = bits(tmp, 7, 0); - break; - case 2: - tmp = pkt->get(); - int_p[int_num] = bits(tmp, 7, 0); - int_p[int_num + 1] = bits(tmp, 15, 8); - break; - case 4: - tmp = pkt->get(); - int_p[int_num] = bits(tmp, 7, 0); - int_p[int_num + 1] = bits(tmp, 15, 8); - int_p[int_num + 2] = bits(tmp, 23, 16); - int_p[int_num + 3] = bits(tmp, 31, 24); - break; - default: - panic("Invalid size when writing to priority regs in Gic: %d\n", - pkt->getSize()); - } - - updateIntState(-1); - updateRunPri(); - goto done; - } - - if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) { - Addr int_num = (daddr-ICDIPTR_ST) ; - assert(int_num < INT_LINES_MAX); - // First 31 interrupts only target single processor - if (int_num >= SGI_MAX) { - if (pkt->getSize() == 1) { - uint8_t tmp = pkt->get(); - cpuTarget[int_num] = tmp & 0xff; - } else { - assert (pkt->getSize() == 4); - int_num = mbits(int_num, 31, 2); - uint32_t tmp = pkt->get(); - cpuTarget[int_num] = bits(tmp, 7, 0); - cpuTarget[int_num+1] = bits(tmp, 15, 8); - cpuTarget[int_num+2] = bits(tmp, 23, 16); - cpuTarget[int_num+3] = bits(tmp, 31, 24); - } - updateIntState((daddr-ICDIPTR_ST)>>2); - } - goto done; - } - - 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) - warn("GIC N:N mode selected and not supported at this time\n"); - goto done; - } - - switch(daddr) { - case ICDDCR: - enabled = pkt->get(); - DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled); - break; - case ICDSGIR: - softInt(ctx_id, pkt->get()); - break; - default: - panic("Tried to write Gic distributor at offset %#x\n", daddr); - break; - } - -done: - pkt->makeAtomicResponse(); - return distPioDelay; -} - -Tick -Gic::writeCpu(PacketPtr pkt) -{ - Addr daddr = pkt->getAddr() - cpuAddr; - pkt->allocate(); - - assert(pkt->req->hasContextId()); - int ctx_id = pkt->req->contextId(); - IAR iar; - - DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n", - ctx_id, daddr, pkt->get()); - - switch(daddr) { - case ICCICR: - cpuEnabled[ctx_id] = pkt->get(); - break; - case ICCPMR: - cpuPriority[ctx_id] = pkt->get(); - break; - case ICCBPR: - cpuBpr[ctx_id] = pkt->get(); - break; - case ICCEOIR: - iar = pkt->get(); - 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)) - panic("Done handling a SGI that isn't active?\n"); - 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); - cpuPpiActive[ctx_id] &= ~int_num; - } else { - uint32_t int_num = 1 << intNumToBit(iar.ack_id); - if (!(activeInt[intNumToWord(iar.ack_id)] & int_num)) - panic("Done handling interrupt that isn't active?\n"); - activeInt[intNumToWord(iar.ack_id)] &= ~int_num; - } - updateRunPri(); - DPRINTF(Interrupt, "CPU %d done handling intr 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(int 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 - } - - 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) -{ - if (cpu > 7) - panic("Invalid CPU ID\n"); - return ULL(0x0101010101010101) << cpu; -} - -void -Gic::updateIntState(int hint) -{ - for (int cpu = 0; cpu < CPU_MAX; cpu++) { - if (!cpuEnabled[cpu]) - continue; - if (cpu >= sys->numContexts()) - break; - - /*@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 > bankedIntPriority[cpu][swi]) { - highest_pri = bankedIntPriority[cpu][swi]; - highest_int = swi; - } - } - - // Check PPIs - if (cpuPpiPending[cpu]) { - for (int ppi = 0; ppi < PPI_MAX; ppi++) { - if (cpuPpiPending[cpu] & (1 << ppi)) - if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) { - highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi]; - highest_int = SGI_MAX + ppi; - } - } - } - - bool mp_sys = sys->numRunningContexts() > 1; - // Check other ints - for (int x = 0; x < (itLines/INT_BITS_MAX); x++) { - if (intEnabled[x] & pendingInt[x]) { - for (int y = 0; y < INT_BITS_MAX; y++) { - uint32_t int_nm = x * INT_BITS_MAX + y; - DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm); - /* Set current pending int as highest int for current cpu - if the interrupt's priority higher than current prioirty - and if currrent cpu is the target (for mp configs only) - */ - if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) && - (intPriority[int_nm] < highest_pri)) - if ( (!mp_sys) || (cpuTarget[int_nm] & (1 << cpu))) { - highest_pri = intPriority[int_nm]; - highest_int = int_nm; - } - } - } - } - - cpuHighestInt[cpu] = 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)))) { - - DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int, - cpu); - postInt(cpu, curTick() + intLatency); - } - } -} - -void -Gic::updateRunPri() -{ - for (int cpu = 0; cpu < CPU_MAX; 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)) && - (bankedIntPriority[cpu][i] < maxPriority)) - maxPriority = bankedIntPriority[cpu][i]; - } else if (i < (SGI_MAX + PPI_MAX)) { - if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) && - (bankedIntPriority[cpu][i] < maxPriority)) - maxPriority = bankedIntPriority[cpu][i]; - - } else { - if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i))) - if (intPriority[i] < maxPriority) - maxPriority = intPriority[i]; - } - } - iccrpr[cpu] = maxPriority; - } -} - -void -Gic::sendInt(uint32_t num) -{ - DPRINTF(Interrupt, "Received Interupt number %d, cpuTarget %#x: \n", - num, cpuTarget[num]); - if (cpuTarget[num] & (cpuTarget[num] - 1)) - panic("Multiple targets for peripheral interrupts is not supported\n"); - pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num); - updateIntState(intNumToWord(num)); - -} - -void -Gic::sendPPInt(uint32_t num, uint32_t cpu) -{ - DPRINTF(Interrupt, "Received Interrupt number %d, cpuTarget %#x: \n", - num, cpu); - cpuPpiPending[cpu] |= 1 << (num - SGI_MAX); - updateIntState(intNumToWord(num)); -} - -void -Gic::clearInt(uint32_t number) -{ - /* @todo assume edge triggered only at the moment. Nothing to do. */ -} - -void -Gic::postInt(uint32_t cpu, Tick when) -{ - if (!(postIntEvent[cpu]->scheduled())) - eventq->schedule(postIntEvent[cpu], when); -} - -AddrRangeList -Gic::getAddrRanges() const -{ - AddrRangeList ranges; - ranges.push_back(RangeSize(distAddr, DIST_SIZE)); - ranges.push_back(RangeSize(cpuAddr, CPU_SIZE)); - return ranges; -} - - -void -Gic::serialize(std::ostream &os) -{ - DPRINTF(Checkpoint, "Serializing Arm GIC\n"); - - SERIALIZE_SCALAR(distAddr); - SERIALIZE_SCALAR(cpuAddr); - SERIALIZE_SCALAR(distPioDelay); - SERIALIZE_SCALAR(cpuPioDelay); - SERIALIZE_SCALAR(enabled); - SERIALIZE_SCALAR(itLines); - SERIALIZE_SCALAR(itLinesLog2); - 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, INT_BITS_MAX * 2); - 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_ARRAY(cpuPpiActive, CPU_MAX); - SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); - SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX)); - SERIALIZE_SCALAR(irqEnable); - Tick interrupt_time[CPU_MAX]; - for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) { - interrupt_time[cpu] = 0; - if (postIntEvent[cpu]->scheduled()) { - interrupt_time[cpu] = postIntEvent[cpu]->when(); - } - } - SERIALIZE_ARRAY(interrupt_time, CPU_MAX); - -} - -void -Gic::unserialize(Checkpoint *cp, const std::string §ion) -{ - DPRINTF(Checkpoint, "Unserializing Arm GIC\n"); - - UNSERIALIZE_SCALAR(distAddr); - UNSERIALIZE_SCALAR(cpuAddr); - UNSERIALIZE_SCALAR(distPioDelay); - UNSERIALIZE_SCALAR(cpuPioDelay); - UNSERIALIZE_SCALAR(enabled); - UNSERIALIZE_SCALAR(itLines); - UNSERIALIZE_SCALAR(itLinesLog2); - 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_ARRAY(cpuPpiActive, CPU_MAX); - UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); - UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX)); - UNSERIALIZE_SCALAR(irqEnable); - - Tick interrupt_time[CPU_MAX]; - UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX); - - for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) { - if (interrupt_time[cpu]) - schedule(postIntEvent[cpu], interrupt_time[cpu]); - } - -} - -Gic * -GicParams::create() -{ - return new Gic(this); -} - -/* Functions for debugging and testing */ -void -Gic::driveSPI(unsigned int spiVect) -{ - DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable); - pendingInt[1] |= spiVect; - if (irqEnable && enabled) { - updateIntState(-1); - } -} - -void -Gic::driveIrqEn( bool state) -{ - irqEnable = state; - DPRINTF(GIC, " Enabling Irq\n"); - updateIntState(-1); -} - -void -Gic::driveLegIRQ(bool state) -{ - if (irqEnable && !(!enabled && cpuEnabled[0])) { - if (state) { - DPRINTF(GIC, "Driving Legacy Irq\n"); - platform->intrctrl->post(0, ArmISA::INT_IRQ, 0); - } - else platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0); - } -} - -void -Gic::driveLegFIQ(bool state) -{ - if (state) - platform->intrctrl->post(0, ArmISA::INT_FIQ, 0); - else platform->intrctrl->clear(0, ArmISA::INT_FIQ, 0); -} diff --git a/src/dev/arm/gic.hh b/src/dev/arm/gic.hh deleted file mode 100644 index 02448f651..000000000 --- a/src/dev/arm/gic.hh +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2010 ARM Limited - * All rights reserved - * - * The license below extends only to copyright in the software and shall - * not be construed as granting a license to any other intellectual - * property including but not limited to intellectual property relating - * to a hardware implementation of the functionality of the software - * licensed hereunder. You may use the software subject to the license - * terms below provided that you ensure that this notice is replicated - * unmodified and in its entirety in all distributions of the software, - * modified or unmodified, in source code or in binary form. - * - * Copyright (c) 2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Ali Saidi - */ - - -/** @file - * Implementiation of a PL390 GIC - */ - -#ifndef __DEV_ARM_GIC_H__ -#define __DEV_ARM_GIC_H__ - -#include "base/bitunion.hh" -#include "dev/io_device.hh" -#include "dev/platform.hh" -#include "cpu/intr_control.hh" -#include "params/Gic.hh" - -/** @todo this code only assumes one processor for now. Low word - * of intEnabled and pendingInt need to be replicated per CPU. - * bottom 31 interrupts (7 words) need to be replicated for - * for interrupt priority register, processor target registers - * interrupt config registers */ - -class Gic : public PioDevice -{ - protected: - // distributor memory addresses - static const int ICDDCR = 0x000; // control register - static const int ICDICTR = 0x004; // controller type - static const int ICDIIDR = 0x008; // implementer id - static const int ICDISER_ST = 0x100; // interrupt set enable - static const int ICDISER_ED = 0x17c; - static const int ICDICER_ST = 0x180; // interrupt clear enable - static const int ICDICER_ED = 0x1fc; - static const int ICDISPR_ST = 0x200; // set pending interrupt - static const int ICDISPR_ED = 0x27c; - static const int ICDICPR_ST = 0x280; // clear pending interrupt - static const int ICDICPR_ED = 0x2fc; - static const int ICDABR_ST = 0x300; // active bit registers - static const int ICDABR_ED = 0x37c; - static const int ICDIPR_ST = 0x400; // interrupt priority registers - static const int ICDIPR_ED = 0x7f8; - static const int ICDIPTR_ST = 0x800; // processor target registers - static const int ICDIPTR_ED = 0xbf8; - static const int ICDICFR_ST = 0xc00; // interrupt config registers - static const int ICDICFR_ED = 0xcfc; - static const int ICDSGIR = 0xf00; // software generated interrupt - static const int DIST_SIZE = 0xfff; - - // cpu memory addressesa - static const int ICCICR = 0x00; // CPU control register - static const int ICCPMR = 0x04; // Interrupt priority mask - static const int ICCBPR = 0x08; // binary point register - static const int ICCIAR = 0x0C; // interrupt ack register - static const int ICCEOIR = 0x10; // end of interrupt - static const int ICCRPR = 0x14; // runing priority - static const int ICCHPIR = 0x18; // highest pending interrupt - static const int ICCABPR = 0x1c; // aliased binary point - 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 - static const int PPI_MAX = 16; // Number of Private Peripheral 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; - Bitfield<23,16> cpu_list; - Bitfield<25,24> list_type; - EndBitUnion(SWI) - - BitUnion32(IAR) - Bitfield<9,0> ack_id; - Bitfield<12,10> cpu_id; - EndBitUnion(IAR) - - Platform *platform; - - /** Distributor address GIC listens at */ - Addr distAddr; - - /** CPU address GIC listens at */ - /** @todo is this one per cpu? */ - Addr cpuAddr; - - /** Latency for a distributor operation */ - Tick distPioDelay; - - /** Latency for a cpu operation */ - Tick cpuPioDelay; - - /** Latency for a interrupt to get to CPU */ - Tick intLatency; - - /** Gic enabled */ - bool enabled; - - /** Number of itLines enabled */ - uint32_t itLines; - - uint32_t itLinesLog2; - - /** interrupt enable bits for all possible 1020 interupts. - * one bit per interrupt, 32 bit per word = 32 words */ - 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[INT_BITS_MAX]; - - /** interrupt active bits for all possible 1020 interupts. - * one bit per interrupt, 32 bit per word = 32 words */ - uint32_t activeInt[INT_BITS_MAX]; - - /** read only running priroity register, 1 per cpu*/ - uint32_t iccrpr[CPU_MAX]; - - /** an 8 bit priority (lower is higher priority) for each - * of the 1020 possible supported interrupts. - */ - 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[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[INT_BITS_MAX*2]; - - /** CPU enabled */ - bool cpuEnabled[CPU_MAX]; - - /** CPU priority */ - uint8_t cpuPriority[CPU_MAX]; - - /** Binary point registers */ - uint8_t cpuBpr[CPU_MAX]; - - /** highest interrupt that is interrupting CPU */ - 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]; - - /** 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]; - uint32_t cpuPpiActive[CPU_MAX]; - - /** Banked interrupt prioirty registers for SGIs and PPIs */ - uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX]; - - /** IRQ Enable Used for debug */ - bool irqEnable; - - /** software generated interrupt - * @param data data to decode that indicates which cpus to interrupt - */ - 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 - */ - void updateIntState(int hint); - - /** Update the register that records priority of the highest priority - * 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; } - - /** Post an interrupt to a CPU - */ - void postInt(uint32_t cpu, Tick when); - - /** Event definition to post interrupt to CPU after a delay - */ - class PostIntEvent : public Event - { - private: - uint32_t cpu; - Platform *platform; - public: - PostIntEvent( uint32_t c, Platform* p) - : cpu(c), platform(p) - { } - void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);} - const char *description() const { return "Post Interrupt to CPU"; } - }; - PostIntEvent *postIntEvent[CPU_MAX]; - - public: - typedef GicParams Params; - const Params * - params() const - { - return dynamic_cast(_params); - } - Gic(const Params *p); - - /** Return the address ranges used by the Gic - * This is the distributor address + all cpu addresses - */ - virtual AddrRangeList getAddrRanges() const; - - /** A PIO read to the device, immediately split up into - * readDistributor() or readCpu() - */ - virtual Tick read(PacketPtr pkt); - - /** A PIO read to the device, immediately split up into - * writeDistributor() or writeCpu() - */ - virtual Tick write(PacketPtr pkt); - - /** Handle a read to the distributor poriton of the GIC - * @param pkt packet to respond to - */ - Tick readDistributor(PacketPtr pkt); - - /** Handle a read to the cpu poriton of the GIC - * @param pkt packet to respond to - */ - Tick readCpu(PacketPtr pkt); - - /** Handle a write to the distributor poriton of the GIC - * @param pkt packet to respond to - */ - Tick writeDistributor(PacketPtr pkt); - - /** Handle a write to the cpu poriton of the GIC - * @param pkt packet to respond to - */ - Tick writeCpu(PacketPtr pkt); - - /** Post an interrupt from a device that is connected to the Gic. - * Depending on the configuration, the gic will pass this interrupt - * on through to a CPU. - * @param number number of interrupt to send */ - void sendInt(uint32_t number); - - /** Interface call for private peripheral interrupts */ - void sendPPInt(uint32_t num, uint32_t cpu); - - /** Clear an interrupt from a device that is connected to the Gic - * Depending on the configuration, the gic may de-assert it's cpu line - * @param number number of interrupt to send */ - void clearInt(uint32_t number); - - /* Various functions fer testing and debugging */ - void driveSPI(uint32_t spi); - void driveLegIRQ(bool state); - void driveLegFIQ(bool state); - void driveIrqEn(bool state); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -}; - -#endif //__DEV_ARM_GIC_H__ diff --git a/src/dev/arm/gic_pl390.cc b/src/dev/arm/gic_pl390.cc new file mode 100644 index 000000000..0cd435938 --- /dev/null +++ b/src/dev/arm/gic_pl390.cc @@ -0,0 +1,843 @@ +/* + * Copyright (c) 2010 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + * Prakash Ramrakhyani + */ + +#include "base/trace.hh" +#include "debug/Checkpoint.hh" +#include "debug/GIC.hh" +#include "debug/IPI.hh" +#include "debug/Interrupt.hh" +#include "dev/arm/gic_pl390.hh" +#include "dev/arm/realview.hh" +#include "dev/terminal.hh" +#include "mem/packet.hh" +#include "mem/packet_access.hh" + +Pl390::Pl390(const Params *p) + : BaseGic(p), distAddr(p->dist_addr), + cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay), + cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency), + enabled(false), itLines(p->it_lines) +{ + itLinesLog2 = ceilLog2(itLines); + + for (int x = 0; x < CPU_MAX; x++) { + cpuEnabled[x] = false; + 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 < INT_BITS_MAX; x++) { + intEnabled[x] = 0; + pendingInt[x] = 0; + activeInt[x] = 0; + } + + for (int x = 0; x < INT_LINES_MAX; x++) { + intPriority[x] = 0; + cpuTarget[x] = 0; + } + + 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; + } + for (int x = 0; x < CPU_MAX; x++) { + cpuPpiActive[x] = 0; + cpuPpiPending[x] = 0; + } + + for (int i = 0; i < CPU_MAX; i++) { + for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) { + bankedIntPriority[i][j] = 0; + } + } + + RealView *rv = dynamic_cast(p->platform); + assert(rv); + rv->setGic(this); + +} + +Tick +Pl390::read(PacketPtr pkt) +{ + + Addr addr = pkt->getAddr(); + + if (addr >= distAddr && addr < distAddr + DIST_SIZE) + return readDistributor(pkt); + else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE) + return readCpu(pkt); + else + panic("Read to unknown address %#x\n", pkt->getAddr()); +} + + +Tick +Pl390::write(PacketPtr pkt) +{ + + Addr addr = pkt->getAddr(); + + if (addr >= distAddr && addr < distAddr + DIST_SIZE) + return writeDistributor(pkt); + else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE) + return writeCpu(pkt); + else + panic("Write to unknown address %#x\n", pkt->getAddr()); +} + +Tick +Pl390::readDistributor(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - distAddr; + pkt->allocate(); + + int ctx_id = pkt->req->contextId(); + + DPRINTF(GIC, "gic distributor read register %#x\n", daddr); + + if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) { + assert((daddr-ICDISER_ST) >> 2 < 32); + pkt->set(intEnabled[(daddr-ICDISER_ST)>>2]); + goto done; + } + + if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) { + assert((daddr-ICDICER_ST) >> 2 < 32); + pkt->set(intEnabled[(daddr-ICDICER_ST)>>2]); + goto done; + } + + if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) { + assert((daddr-ICDISPR_ST) >> 2 < 32); + pkt->set(pendingInt[(daddr-ICDISPR_ST)>>2]); + goto done; + } + + if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) { + assert((daddr-ICDICPR_ST) >> 2 < 32); + pkt->set(pendingInt[(daddr-ICDICPR_ST)>>2]); + goto done; + } + + if (daddr >= ICDABR_ST && daddr < ICDABR_ED + 4) { + assert((daddr-ICDABR_ST) >> 2 < 32); + pkt->set(activeInt[(daddr-ICDABR_ST)>>2]); + goto done; + } + + if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) { + Addr int_num; + int_num = daddr - ICDIPR_ST; + assert(int_num < INT_LINES_MAX); + DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num); + + uint8_t* int_p; + if (int_num < (SGI_MAX + PPI_MAX)) + int_p = bankedIntPriority[ctx_id]; + else + int_p = intPriority; + + switch (pkt->getSize()) { + case 1: + pkt->set(int_p[int_num]); + break; + case 2: + assert((int_num + 1) < INT_LINES_MAX); + pkt->set(int_p[int_num] | + int_p[int_num+1] << 8); + break; + case 4: + assert((int_num + 3) < INT_LINES_MAX); + pkt->set(int_p[int_num] | + int_p[int_num+1] << 8 | + int_p[int_num+2] << 16 | + int_p[int_num+3] << 24); + break; + default: + 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) ; + 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 (SGI) + if (int_num > 31) { + if (pkt->getSize() == 1) { + pkt->set(cpuTarget[int_num]); + } else { + assert(pkt->getSize() == 4); + int_num = mbits(int_num, 31, 2); + pkt->set(cpuTarget[int_num] | + cpuTarget[int_num+1] << 8 | + cpuTarget[int_num+2] << 16 | + cpuTarget[int_num+3] << 24) ; + } + } else { + int ctx_id = pkt->req->contextId(); + assert(ctx_id < sys->numRunningContexts()); + pkt->set(ctx_id); + } + goto done; + } + + if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) { + assert((daddr-ICDICFR_ST) >> 2 < 64); + /** @todo software generated interrutps and PPIs + * can't be configured in some ways + */ + pkt->set(intConfig[(daddr-ICDICFR_ST)>>2]); + goto done; + } + + switch(daddr) { + case ICDDCR: + pkt->set(enabled); + break; + case ICDICTR: + uint32_t tmp; + tmp = ((sys->numRunningContexts() - 1) << 5) | + (itLines/INT_BITS_MAX -1); + pkt->set(tmp); + break; + default: + panic("Tried to read Gic distributor at offset %#x\n", daddr); + break; + } +done: + pkt->makeAtomicResponse(); + return distPioDelay; +} + +Tick +Pl390::readCpu(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - cpuAddr; + pkt->allocate(); + + 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(cpuEnabled[ctx_id]); + break; + case ICCPMR: + pkt->set(cpuPriority[ctx_id]); + break; + case ICCBPR: + pkt->set(cpuBpr[ctx_id]); + break; + case ICCIAR: + 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 if (active_int < (SGI_MAX + PPI_MAX) ) { + uint32_t int_num = 1 << (cpuHighestInt[ctx_id] - SGI_MAX); + cpuPpiActive[ctx_id] |= int_num; + updateRunPri(); + cpuPpiPending[ctx_id] &= ~int_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); + pkt->set(iar); + platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0); + } else { + pkt->set(SPURIOUS_INT); + } + + break; + case ICCRPR: + pkt->set(iccrpr[0]); + break; + case ICCHPIR: + pkt->set(0); + panic("Need to implement HPIR"); + break; + default: + panic("Tried to read Gic cpu at offset %#x\n", daddr); + break; + } + pkt->makeAtomicResponse(); + return cpuPioDelay; +} + + +Tick +Pl390::writeDistributor(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - distAddr; + pkt->allocate(); + + 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()); + + if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) { + assert((daddr-ICDISER_ST) >> 2 < 32); + intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get(); + goto done; + } + + if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) { + assert((daddr-ICDICER_ST) >> 2 < 32); + intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get(); + goto done; + } + + 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; + } + + 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; + } + + if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) { + Addr int_num = daddr - ICDIPR_ST; + assert(int_num < INT_LINES_MAX); + uint8_t* int_p; + if (int_num < (SGI_MAX + PPI_MAX)) + int_p = bankedIntPriority[ctx_id]; + else + int_p = intPriority; + uint32_t tmp; + switch(pkt->getSize()) { + case 1: + tmp = pkt->get(); + int_p[int_num] = bits(tmp, 7, 0); + break; + case 2: + tmp = pkt->get(); + int_p[int_num] = bits(tmp, 7, 0); + int_p[int_num + 1] = bits(tmp, 15, 8); + break; + case 4: + tmp = pkt->get(); + int_p[int_num] = bits(tmp, 7, 0); + int_p[int_num + 1] = bits(tmp, 15, 8); + int_p[int_num + 2] = bits(tmp, 23, 16); + int_p[int_num + 3] = bits(tmp, 31, 24); + break; + default: + panic("Invalid size when writing to priority regs in Gic: %d\n", + pkt->getSize()); + } + + updateIntState(-1); + updateRunPri(); + goto done; + } + + if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) { + Addr int_num = (daddr-ICDIPTR_ST) ; + assert(int_num < INT_LINES_MAX); + // First 31 interrupts only target single processor + if (int_num >= SGI_MAX) { + if (pkt->getSize() == 1) { + uint8_t tmp = pkt->get(); + cpuTarget[int_num] = tmp & 0xff; + } else { + assert (pkt->getSize() == 4); + int_num = mbits(int_num, 31, 2); + uint32_t tmp = pkt->get(); + cpuTarget[int_num] = bits(tmp, 7, 0); + cpuTarget[int_num+1] = bits(tmp, 15, 8); + cpuTarget[int_num+2] = bits(tmp, 23, 16); + cpuTarget[int_num+3] = bits(tmp, 31, 24); + } + updateIntState((daddr-ICDIPTR_ST)>>2); + } + goto done; + } + + 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) + warn("GIC N:N mode selected and not supported at this time\n"); + goto done; + } + + switch(daddr) { + case ICDDCR: + enabled = pkt->get(); + DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled); + break; + case ICDSGIR: + softInt(ctx_id, pkt->get()); + break; + default: + panic("Tried to write Gic distributor at offset %#x\n", daddr); + break; + } + +done: + pkt->makeAtomicResponse(); + return distPioDelay; +} + +Tick +Pl390::writeCpu(PacketPtr pkt) +{ + Addr daddr = pkt->getAddr() - cpuAddr; + pkt->allocate(); + + assert(pkt->req->hasContextId()); + int ctx_id = pkt->req->contextId(); + IAR iar; + + DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n", + ctx_id, daddr, pkt->get()); + + switch(daddr) { + case ICCICR: + cpuEnabled[ctx_id] = pkt->get(); + break; + case ICCPMR: + cpuPriority[ctx_id] = pkt->get(); + break; + case ICCBPR: + cpuBpr[ctx_id] = pkt->get(); + break; + case ICCEOIR: + iar = pkt->get(); + 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)) + panic("Done handling a SGI that isn't active?\n"); + 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); + cpuPpiActive[ctx_id] &= ~int_num; + } else { + uint32_t int_num = 1 << intNumToBit(iar.ack_id); + if (!(activeInt[intNumToWord(iar.ack_id)] & int_num)) + panic("Done handling interrupt that isn't active?\n"); + activeInt[intNumToWord(iar.ack_id)] &= ~int_num; + } + updateRunPri(); + DPRINTF(Interrupt, "CPU %d done handling intr 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 +Pl390::softInt(int 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 + } + + 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 +Pl390::genSwiMask(int cpu) +{ + if (cpu > 7) + panic("Invalid CPU ID\n"); + return ULL(0x0101010101010101) << cpu; +} + +void +Pl390::updateIntState(int hint) +{ + for (int cpu = 0; cpu < CPU_MAX; cpu++) { + if (!cpuEnabled[cpu]) + continue; + if (cpu >= sys->numContexts()) + break; + + /*@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 > bankedIntPriority[cpu][swi]) { + highest_pri = bankedIntPriority[cpu][swi]; + highest_int = swi; + } + } + + // Check PPIs + if (cpuPpiPending[cpu]) { + for (int ppi = 0; ppi < PPI_MAX; ppi++) { + if (cpuPpiPending[cpu] & (1 << ppi)) + if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) { + highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi]; + highest_int = SGI_MAX + ppi; + } + } + } + + bool mp_sys = sys->numRunningContexts() > 1; + // Check other ints + for (int x = 0; x < (itLines/INT_BITS_MAX); x++) { + if (intEnabled[x] & pendingInt[x]) { + for (int y = 0; y < INT_BITS_MAX; y++) { + uint32_t int_nm = x * INT_BITS_MAX + y; + DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm); + /* Set current pending int as highest int for current cpu + if the interrupt's priority higher than current prioirty + and if currrent cpu is the target (for mp configs only) + */ + if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) && + (intPriority[int_nm] < highest_pri)) + if ( (!mp_sys) || (cpuTarget[int_nm] & (1 << cpu))) { + highest_pri = intPriority[int_nm]; + highest_int = int_nm; + } + } + } + } + + cpuHighestInt[cpu] = 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)))) { + + DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int, + cpu); + postInt(cpu, curTick() + intLatency); + } + } +} + +void +Pl390::updateRunPri() +{ + for (int cpu = 0; cpu < CPU_MAX; 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)) && + (bankedIntPriority[cpu][i] < maxPriority)) + maxPriority = bankedIntPriority[cpu][i]; + } else if (i < (SGI_MAX + PPI_MAX)) { + if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) && + (bankedIntPriority[cpu][i] < maxPriority)) + maxPriority = bankedIntPriority[cpu][i]; + + } else { + if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i))) + if (intPriority[i] < maxPriority) + maxPriority = intPriority[i]; + } + } + iccrpr[cpu] = maxPriority; + } +} + +void +Pl390::sendInt(uint32_t num) +{ + DPRINTF(Interrupt, "Received Interupt number %d, cpuTarget %#x: \n", + num, cpuTarget[num]); + if (cpuTarget[num] & (cpuTarget[num] - 1)) + panic("Multiple targets for peripheral interrupts is not supported\n"); + pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num); + updateIntState(intNumToWord(num)); + +} + +void +Pl390::sendPPInt(uint32_t num, uint32_t cpu) +{ + DPRINTF(Interrupt, "Received Interrupt number %d, cpuTarget %#x: \n", + num, cpu); + cpuPpiPending[cpu] |= 1 << (num - SGI_MAX); + updateIntState(intNumToWord(num)); +} + +void +Pl390::clearInt(uint32_t number) +{ + /* @todo assume edge triggered only at the moment. Nothing to do. */ +} + +void +Pl390::postInt(uint32_t cpu, Tick when) +{ + if (!(postIntEvent[cpu]->scheduled())) + eventq->schedule(postIntEvent[cpu], when); +} + +AddrRangeList +Pl390::getAddrRanges() const +{ + AddrRangeList ranges; + ranges.push_back(RangeSize(distAddr, DIST_SIZE)); + ranges.push_back(RangeSize(cpuAddr, CPU_SIZE)); + return ranges; +} + + +void +Pl390::serialize(std::ostream &os) +{ + DPRINTF(Checkpoint, "Serializing Arm GIC\n"); + + SERIALIZE_SCALAR(distAddr); + SERIALIZE_SCALAR(cpuAddr); + SERIALIZE_SCALAR(distPioDelay); + SERIALIZE_SCALAR(cpuPioDelay); + SERIALIZE_SCALAR(enabled); + SERIALIZE_SCALAR(itLines); + SERIALIZE_SCALAR(itLinesLog2); + 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, INT_BITS_MAX * 2); + 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_ARRAY(cpuPpiActive, CPU_MAX); + SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); + SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX)); + SERIALIZE_SCALAR(irqEnable); + Tick interrupt_time[CPU_MAX]; + for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) { + interrupt_time[cpu] = 0; + if (postIntEvent[cpu]->scheduled()) { + interrupt_time[cpu] = postIntEvent[cpu]->when(); + } + } + SERIALIZE_ARRAY(interrupt_time, CPU_MAX); + +} + +void +Pl390::unserialize(Checkpoint *cp, const std::string §ion) +{ + DPRINTF(Checkpoint, "Unserializing Arm GIC\n"); + + UNSERIALIZE_SCALAR(distAddr); + UNSERIALIZE_SCALAR(cpuAddr); + UNSERIALIZE_SCALAR(distPioDelay); + UNSERIALIZE_SCALAR(cpuPioDelay); + UNSERIALIZE_SCALAR(enabled); + UNSERIALIZE_SCALAR(itLines); + UNSERIALIZE_SCALAR(itLinesLog2); + 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_ARRAY(cpuPpiActive, CPU_MAX); + UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX); + UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX)); + UNSERIALIZE_SCALAR(irqEnable); + + Tick interrupt_time[CPU_MAX]; + UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX); + + for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) { + if (interrupt_time[cpu]) + schedule(postIntEvent[cpu], interrupt_time[cpu]); + } + +} + +Pl390 * +Pl390Params::create() +{ + return new Pl390(this); +} + +/* Functions for debugging and testing */ +void +Pl390::driveSPI(unsigned int spiVect) +{ + DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable); + pendingInt[1] |= spiVect; + if (irqEnable && enabled) { + updateIntState(-1); + } +} + +void +Pl390::driveIrqEn( bool state) +{ + irqEnable = state; + DPRINTF(GIC, " Enabling Irq\n"); + updateIntState(-1); +} + +void +Pl390::driveLegIRQ(bool state) +{ + if (irqEnable && !(!enabled && cpuEnabled[0])) { + if (state) { + DPRINTF(GIC, "Driving Legacy Irq\n"); + platform->intrctrl->post(0, ArmISA::INT_IRQ, 0); + } + else platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0); + } +} + +void +Pl390::driveLegFIQ(bool state) +{ + if (state) + platform->intrctrl->post(0, ArmISA::INT_FIQ, 0); + else platform->intrctrl->clear(0, ArmISA::INT_FIQ, 0); +} diff --git a/src/dev/arm/gic_pl390.hh b/src/dev/arm/gic_pl390.hh new file mode 100644 index 000000000..cc6e24d1c --- /dev/null +++ b/src/dev/arm/gic_pl390.hh @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2010 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + + +/** @file + * Implementiation of a PL390 GIC + */ + +#ifndef __DEV_ARM_GIC_PL390_H__ +#define __DEV_ARM_GIC_PL390_H__ + +#include "base/bitunion.hh" +#include "cpu/intr_control.hh" +#include "dev/arm/base_gic.hh" +#include "dev/io_device.hh" +#include "dev/platform.hh" +#include "params/Pl390.hh" + +/** @todo this code only assumes one processor for now. Low word + * of intEnabled and pendingInt need to be replicated per CPU. + * bottom 31 interrupts (7 words) need to be replicated for + * for interrupt priority register, processor target registers + * interrupt config registers */ + +class Pl390 : public BaseGic +{ + protected: + // distributor memory addresses + static const int ICDDCR = 0x000; // control register + static const int ICDICTR = 0x004; // controller type + static const int ICDIIDR = 0x008; // implementer id + static const int ICDISER_ST = 0x100; // interrupt set enable + static const int ICDISER_ED = 0x17c; + static const int ICDICER_ST = 0x180; // interrupt clear enable + static const int ICDICER_ED = 0x1fc; + static const int ICDISPR_ST = 0x200; // set pending interrupt + static const int ICDISPR_ED = 0x27c; + static const int ICDICPR_ST = 0x280; // clear pending interrupt + static const int ICDICPR_ED = 0x2fc; + static const int ICDABR_ST = 0x300; // active bit registers + static const int ICDABR_ED = 0x37c; + static const int ICDIPR_ST = 0x400; // interrupt priority registers + static const int ICDIPR_ED = 0x7f8; + static const int ICDIPTR_ST = 0x800; // processor target registers + static const int ICDIPTR_ED = 0xbf8; + static const int ICDICFR_ST = 0xc00; // interrupt config registers + static const int ICDICFR_ED = 0xcfc; + static const int ICDSGIR = 0xf00; // software generated interrupt + static const int DIST_SIZE = 0xfff; + + // cpu memory addressesa + static const int ICCICR = 0x00; // CPU control register + static const int ICCPMR = 0x04; // Interrupt priority mask + static const int ICCBPR = 0x08; // binary point register + static const int ICCIAR = 0x0C; // interrupt ack register + static const int ICCEOIR = 0x10; // end of interrupt + static const int ICCRPR = 0x14; // runing priority + static const int ICCHPIR = 0x18; // highest pending interrupt + static const int ICCABPR = 0x1c; // aliased binary point + 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 + static const int PPI_MAX = 16; // Number of Private Peripheral 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; + Bitfield<23,16> cpu_list; + 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; + + /** CPU address GIC listens at */ + /** @todo is this one per cpu? */ + Addr cpuAddr; + + /** Latency for a distributor operation */ + Tick distPioDelay; + + /** Latency for a cpu operation */ + Tick cpuPioDelay; + + /** Latency for a interrupt to get to CPU */ + Tick intLatency; + + /** Gic enabled */ + bool enabled; + + /** Number of itLines enabled */ + uint32_t itLines; + + uint32_t itLinesLog2; + + /** interrupt enable bits for all possible 1020 interupts. + * one bit per interrupt, 32 bit per word = 32 words */ + 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[INT_BITS_MAX]; + + /** interrupt active bits for all possible 1020 interupts. + * one bit per interrupt, 32 bit per word = 32 words */ + uint32_t activeInt[INT_BITS_MAX]; + + /** read only running priroity register, 1 per cpu*/ + uint32_t iccrpr[CPU_MAX]; + + /** an 8 bit priority (lower is higher priority) for each + * of the 1020 possible supported interrupts. + */ + 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[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[INT_BITS_MAX*2]; + + /** CPU enabled */ + bool cpuEnabled[CPU_MAX]; + + /** CPU priority */ + uint8_t cpuPriority[CPU_MAX]; + + /** Binary point registers */ + uint8_t cpuBpr[CPU_MAX]; + + /** highest interrupt that is interrupting CPU */ + 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]; + + /** 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]; + uint32_t cpuPpiActive[CPU_MAX]; + + /** Banked interrupt prioirty registers for SGIs and PPIs */ + uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX]; + + /** IRQ Enable Used for debug */ + bool irqEnable; + + /** software generated interrupt + * @param data data to decode that indicates which cpus to interrupt + */ + 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 + */ + void updateIntState(int hint); + + /** Update the register that records priority of the highest priority + * 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; } + + /** Post an interrupt to a CPU + */ + void postInt(uint32_t cpu, Tick when); + + /** Event definition to post interrupt to CPU after a delay + */ + class PostIntEvent : public Event + { + private: + uint32_t cpu; + Platform *platform; + public: + PostIntEvent( uint32_t c, Platform* p) + : cpu(c), platform(p) + { } + void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);} + const char *description() const { return "Post Interrupt to CPU"; } + }; + PostIntEvent *postIntEvent[CPU_MAX]; + + public: + typedef Pl390Params Params; + const Params * + params() const + { + return dynamic_cast(_params); + } + Pl390(const Params *p); + + /** Return the address ranges used by the Gic + * This is the distributor address + all cpu addresses + */ + virtual AddrRangeList getAddrRanges() const; + + /** A PIO read to the device, immediately split up into + * readDistributor() or readCpu() + */ + virtual Tick read(PacketPtr pkt); + + /** A PIO read to the device, immediately split up into + * writeDistributor() or writeCpu() + */ + virtual Tick write(PacketPtr pkt); + + /** Handle a read to the distributor poriton of the GIC + * @param pkt packet to respond to + */ + Tick readDistributor(PacketPtr pkt); + + /** Handle a read to the cpu poriton of the GIC + * @param pkt packet to respond to + */ + Tick readCpu(PacketPtr pkt); + + /** Handle a write to the distributor poriton of the GIC + * @param pkt packet to respond to + */ + Tick writeDistributor(PacketPtr pkt); + + /** Handle a write to the cpu poriton of the GIC + * @param pkt packet to respond to + */ + Tick writeCpu(PacketPtr pkt); + + /** Post an interrupt from a device that is connected to the Gic. + * Depending on the configuration, the gic will pass this interrupt + * on through to a CPU. + * @param number number of interrupt to send */ + void sendInt(uint32_t number); + + /** Interface call for private peripheral interrupts */ + void sendPPInt(uint32_t num, uint32_t cpu); + + /** Clear an interrupt from a device that is connected to the Gic + * Depending on the configuration, the gic may de-assert it's cpu line + * @param number number of interrupt to send */ + void clearInt(uint32_t number); + + /* Various functions fer testing and debugging */ + void driveSPI(uint32_t spi); + void driveLegIRQ(bool state); + void driveLegFIQ(bool state); + void driveIrqEn(bool state); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif //__DEV_ARM_GIC_H__ diff --git a/src/dev/arm/kmi.hh b/src/dev/arm/kmi.hh index e2e75cfef..f9dbfcf76 100644 --- a/src/dev/arm/kmi.hh +++ b/src/dev/arm/kmi.hh @@ -54,8 +54,6 @@ #include "dev/arm/amba_device.hh" #include "params/Pl050.hh" -class Gic; - class Pl050 : public AmbaIntDevice, public VncKeyboard, public VncMouse { protected: diff --git a/src/dev/arm/pl011.cc b/src/dev/arm/pl011.cc index 4be7a5d90..8593c4e54 100644 --- a/src/dev/arm/pl011.cc +++ b/src/dev/arm/pl011.cc @@ -44,7 +44,7 @@ #include "debug/Checkpoint.hh" #include "debug/Uart.hh" #include "dev/arm/amba_device.hh" -#include "dev/arm/gic.hh" +#include "dev/arm/base_gic.hh" #include "dev/arm/pl011.hh" #include "dev/terminal.hh" #include "mem/packet.hh" diff --git a/src/dev/arm/pl011.hh b/src/dev/arm/pl011.hh index e96d33d83..a13f635f0 100644 --- a/src/dev/arm/pl011.hh +++ b/src/dev/arm/pl011.hh @@ -54,7 +54,7 @@ #include "dev/uart.hh" #include "params/Pl011.hh" -class Gic; +class BaseGic; class Pl011 : public Uart { @@ -121,7 +121,7 @@ class Pl011 : public Uart int intNum; /** Gic to use for interrupting */ - Gic *gic; + BaseGic *gic; /** Should the simulation end on an EOT */ bool endOnEOT; diff --git a/src/dev/arm/pl111.cc b/src/dev/arm/pl111.cc index acb3b7dd8..2cf401ce4 100644 --- a/src/dev/arm/pl111.cc +++ b/src/dev/arm/pl111.cc @@ -45,10 +45,11 @@ #include "debug/PL111.hh" #include "debug/Uart.hh" #include "dev/arm/amba_device.hh" -#include "dev/arm/gic.hh" +#include "dev/arm/base_gic.hh" #include "dev/arm/pl111.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" +#include "sim/system.hh" // clang complains about std::set being overloaded with Packet::set if // we open up the entire namespace std diff --git a/src/dev/arm/pl111.hh b/src/dev/arm/pl111.hh index 855fb8bef..a99406715 100644 --- a/src/dev/arm/pl111.hh +++ b/src/dev/arm/pl111.hh @@ -52,7 +52,6 @@ #include "params/Pl111.hh" #include "sim/serialize.hh" -class Gic; class VncInput; class Bitmap; diff --git a/src/dev/arm/realview.cc b/src/dev/arm/realview.cc index b33624cc6..18208b402 100644 --- a/src/dev/arm/realview.cc +++ b/src/dev/arm/realview.cc @@ -50,7 +50,7 @@ #include "config/the_isa.hh" #include "cpu/intr_control.hh" -#include "dev/arm/gic.hh" +#include "dev/arm/base_gic.hh" #include "dev/arm/realview.hh" #include "dev/terminal.hh" #include "sim/system.hh" diff --git a/src/dev/arm/realview.hh b/src/dev/arm/realview.hh index f38aa69fc..38fa040d5 100644 --- a/src/dev/arm/realview.hh +++ b/src/dev/arm/realview.hh @@ -52,7 +52,7 @@ #include "dev/platform.hh" #include "params/RealView.hh" -class Gic; +class BaseGic; class IdeController; class System; @@ -62,7 +62,7 @@ class RealView : public Platform /** Pointer to the system */ System *system; - Gic *gic; + BaseGic *gic; public: typedef RealViewParams Params; @@ -80,7 +80,7 @@ class RealView : public Platform RealView(const Params *p); /** Give platform a pointer to interrupt controller */ - void setGic(Gic *_gic) { gic = _gic; } + void setGic(BaseGic *_gic) { gic = _gic; } /** * Cause the cpu to post a serial interrupt to the CPU. diff --git a/src/dev/arm/timer_cpulocal.cc b/src/dev/arm/timer_cpulocal.cc index 097c52186..84bc12aa9 100644 --- a/src/dev/arm/timer_cpulocal.cc +++ b/src/dev/arm/timer_cpulocal.cc @@ -42,7 +42,7 @@ #include "base/trace.hh" #include "debug/Checkpoint.hh" #include "debug/Timer.hh" -#include "dev/arm/gic.hh" +#include "dev/arm/base_gic.hh" #include "dev/arm/timer_cpulocal.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" diff --git a/src/dev/arm/timer_cpulocal.hh b/src/dev/arm/timer_cpulocal.hh index 9b60db4ec..086dc1c63 100644 --- a/src/dev/arm/timer_cpulocal.hh +++ b/src/dev/arm/timer_cpulocal.hh @@ -50,7 +50,7 @@ * Technical Reference Manual rev r2p2 (ARM DDI 0407F) */ -class Gic; +class BaseGic; class CpuLocalTimer : public BasicPioDevice { @@ -157,7 +157,7 @@ class CpuLocalTimer : public BasicPioDevice static const int CPU_MAX = 8; /** Pointer to the GIC for causing an interrupt */ - Gic *gic; + BaseGic *gic; /** Timers that do the actual work */ Timer localTimer[CPU_MAX]; diff --git a/src/dev/arm/timer_sp804.cc b/src/dev/arm/timer_sp804.cc index af0227ec4..18a22e108 100644 --- a/src/dev/arm/timer_sp804.cc +++ b/src/dev/arm/timer_sp804.cc @@ -41,7 +41,7 @@ #include "base/trace.hh" #include "debug/Checkpoint.hh" #include "debug/Timer.hh" -#include "dev/arm/gic.hh" +#include "dev/arm/base_gic.hh" #include "dev/arm/timer_sp804.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" diff --git a/src/dev/arm/timer_sp804.hh b/src/dev/arm/timer_sp804.hh index 745cb95e3..c000985bd 100644 --- a/src/dev/arm/timer_sp804.hh +++ b/src/dev/arm/timer_sp804.hh @@ -47,7 +47,7 @@ * This implements the dual Sp804 timer block */ -class Gic; +class BaseGic; class Sp804 : public AmbaDevice { @@ -127,7 +127,7 @@ class Sp804 : public AmbaDevice }; /** Pointer to the GIC for causing an interrupt */ - Gic *gic; + BaseGic *gic; /** Timers that do the actual work */ Timer timer0; -- cgit v1.2.3