1/* 2 * Copyright (c) 2019 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2018 Metempsy Technology Consulting 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Jairo Balart 41 */ 42 43#include "dev/arm/gic_v3.hh" 44 45#include "cpu/intr_control.hh" 46#include "debug/GIC.hh" 47#include "debug/Interrupt.hh" 48#include "dev/arm/gic_v3_cpu_interface.hh" 49#include "dev/arm/gic_v3_distributor.hh" 50#include "dev/arm/gic_v3_its.hh" 51#include "dev/arm/gic_v3_redistributor.hh" 52#include "dev/platform.hh" 53#include "mem/packet.hh" 54#include "mem/packet_access.hh" 55 56Gicv3::Gicv3(const Params * p) 57 : BaseGic(p) 58{ 59} 60 61void 62Gicv3::init() 63{ 64 distributor = new Gicv3Distributor(this, params()->it_lines); 65 redistributors.resize(sys->numContexts(), nullptr); 66 cpuInterfaces.resize(sys->numContexts(), nullptr); 67 68 panic_if(sys->numContexts() > params()->cpu_max, 69 "Exceeding maximum number of PEs supported by GICv3: " 70 "using %u while maximum is %u\n", sys->numContexts(), 71 params()->cpu_max); 72 73 for (int i = 0; i < sys->numContexts(); i++) { 74 redistributors[i] = new Gicv3Redistributor(this, i); 75 cpuInterfaces[i] = new Gicv3CPUInterface(this, i); 76 } 77 78 distRange = RangeSize(params()->dist_addr, 79 Gicv3Distributor::ADDR_RANGE_SIZE - 1); 80 81 redistSize = redistributors[0]->addrRangeSize; 82 redistRange = RangeSize(params()->redist_addr, 83 redistSize * sys->numContexts() - 1); 84 85 addrRanges = {distRange, redistRange}; 86 87 distributor->init(); 88 89 for (int i = 0; i < sys->numContexts(); i++) { 90 redistributors[i]->init(); 91 cpuInterfaces[i]->init(); 92 } 93 94 params()->its->setGIC(this); 95 96 BaseGic::init(); 97} 98 99Tick 100Gicv3::read(PacketPtr pkt) 101{ 102 const Addr addr = pkt->getAddr(); 103 const size_t size = pkt->getSize(); 104 bool is_secure_access = pkt->isSecure(); 105 uint64_t resp = 0; 106 Tick delay = 0; 107 108 if (distRange.contains(addr)) { 109 const Addr daddr = addr - distRange.start(); 110 panic_if(!distributor, "Distributor is null!"); 111 resp = distributor->read(daddr, size, is_secure_access); 112 delay = params()->dist_pio_delay; 113 DPRINTF(GIC, "Gicv3::read(): (distributor) context_id %d register %#x " 114 "size %d is_secure_access %d (value %#x)\n", 115 pkt->req->contextId(), daddr, size, is_secure_access, resp); 116 } else if (redistRange.contains(addr)) { 117 Addr daddr = (addr - redistRange.start()) % redistSize; 118 119 Gicv3Redistributor *redist = getRedistributorByAddr(addr); 120 resp = redist->read(daddr, size, is_secure_access); 121 122 delay = params()->redist_pio_delay; 123 DPRINTF(GIC, "Gicv3::read(): (redistributor %d) context_id %d " 124 "register %#x size %d is_secure_access %d (value %#x)\n", 125 redist->processorNumber(), pkt->req->contextId(), daddr, size, 126 is_secure_access, resp); 127 } else { 128 panic("Gicv3::read(): unknown address %#x\n", addr); 129 } 130 131 pkt->setUintX(resp, LittleEndianByteOrder); 132 pkt->makeAtomicResponse(); 133 return delay; 134} 135 136Tick 137Gicv3::write(PacketPtr pkt) 138{ 139 const size_t size = pkt->getSize(); 140 uint64_t data = pkt->getUintX(LittleEndianByteOrder); 141 const Addr addr = pkt->getAddr(); 142 bool is_secure_access = pkt->isSecure(); 143 Tick delay = 0; 144 145 if (distRange.contains(addr)) { 146 const Addr daddr = addr - distRange.start(); 147 panic_if(!distributor, "Distributor is null!"); 148 DPRINTF(GIC, "Gicv3::write(): (distributor) context_id %d " 149 "register %#x size %d is_secure_access %d value %#x\n", 150 pkt->req->contextId(), daddr, size, is_secure_access, data); 151 distributor->write(daddr, data, size, is_secure_access); 152 delay = params()->dist_pio_delay; 153 } else if (redistRange.contains(addr)) { 154 Addr daddr = (addr - redistRange.start()) % redistSize; 155 156 Gicv3Redistributor *redist = getRedistributorByAddr(addr); 157 DPRINTF(GIC, "Gicv3::write(): (redistributor %d) context_id %d " 158 "register %#x size %d is_secure_access %d value %#x\n", 159 redist->processorNumber(), pkt->req->contextId(), daddr, size, 160 is_secure_access, data); 161 162 redist->write(daddr, data, size, is_secure_access); 163 164 delay = params()->redist_pio_delay; 165 } else { 166 panic("Gicv3::write(): unknown address %#x\n", addr); 167 } 168 169 pkt->makeAtomicResponse(); 170 return delay; 171} 172 173void 174Gicv3::sendInt(uint32_t int_id) 175{ 176 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!"); 177 panic_if(int_id >= Gicv3::INTID_SECURE, "Invalid SPI!"); 178 DPRINTF(Interrupt, "Gicv3::sendInt(): received SPI %d\n", int_id); 179 distributor->sendInt(int_id); 180} 181 182void 183Gicv3::clearInt(uint32_t number) 184{ 185 distributor->deassertSPI(number); 186} 187 188void 189Gicv3::sendPPInt(uint32_t int_id, uint32_t cpu) 190{ 191 panic_if(cpu >= redistributors.size(), "Invalid cpuID sending PPI!"); 192 panic_if(int_id < Gicv3::SGI_MAX, "Invalid PPI!"); 193 panic_if(int_id >= Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid PPI!"); 194 DPRINTF(Interrupt, "Gicv3::sendPPInt(): received PPI %d cpuTarget %#x\n", 195 int_id, cpu); 196 redistributors[cpu]->sendPPInt(int_id); 197} 198 199void 200Gicv3::clearPPInt(uint32_t num, uint32_t cpu) 201{ 202} 203 204void 205Gicv3::postInt(uint32_t cpu, ArmISA::InterruptTypes int_type) 206{ 207 platform->intrctrl->post(cpu, int_type, 0); 208} 209 210void 211Gicv3::deassertInt(uint32_t cpu, ArmISA::InterruptTypes int_type) 212{ 213 platform->intrctrl->clear(cpu, int_type, 0); 214} 215 216Gicv3Redistributor * 217Gicv3::getRedistributorByAffinity(uint32_t affinity) const 218{ 219 for (auto & redistributor : redistributors) { 220 if (redistributor->getAffinity() == affinity) { 221 return redistributor; 222 } 223 } 224 225 return nullptr; 226} 227 228Gicv3Redistributor * 229Gicv3::getRedistributorByAddr(Addr addr) const 230{ 231 panic_if(!redistRange.contains(addr), 232 "Address not pointing to a valid redistributor\n"); 233 234 const Addr daddr = addr - redistRange.start(); 235 const uint32_t redistributor_id = daddr / redistSize; 236 237 panic_if(redistributor_id >= redistributors.size(), 238 "Invalid redistributor_id!"); 239 panic_if(!redistributors[redistributor_id], "Redistributor is null!"); 240 241 return redistributors[redistributor_id]; 242} 243 244void 245Gicv3::serialize(CheckpointOut & cp) const 246{ 247 distributor->serializeSection(cp, "distributor"); 248 249 for (uint32_t redistributor_id = 0; 250 redistributor_id < redistributors.size(); redistributor_id++) 251 redistributors[redistributor_id]->serializeSection(cp, 252 csprintf("redistributors.%i", redistributor_id)); 253 254 for (uint32_t cpu_interface_id = 0; 255 cpu_interface_id < cpuInterfaces.size(); cpu_interface_id++) 256 cpuInterfaces[cpu_interface_id]->serializeSection(cp, 257 csprintf("cpuInterface.%i", cpu_interface_id)); 258} 259 260void 261Gicv3::unserialize(CheckpointIn & cp) 262{ 263 getSystem()->setGIC(this); 264 265 distributor->unserializeSection(cp, "distributor"); 266 267 for (uint32_t redistributor_id = 0; 268 redistributor_id < redistributors.size(); redistributor_id++) 269 redistributors[redistributor_id]->unserializeSection(cp, 270 csprintf("redistributors.%i", redistributor_id)); 271 272 for (uint32_t cpu_interface_id = 0; 273 cpu_interface_id < cpuInterfaces.size(); cpu_interface_id++) 274 cpuInterfaces[cpu_interface_id]->unserializeSection(cp, 275 csprintf("cpuInterface.%i", cpu_interface_id)); 276} 277 278Gicv3 * 279Gicv3Params::create() 280{ 281 return new Gicv3(this); 282} 283