gic_v3.cc revision 13877:a4ac726b549d
14826Ssaidi@eecs.umich.edu/*
24826Ssaidi@eecs.umich.edu * Copyright (c) 2018 Metempsy Technology Consulting
34826Ssaidi@eecs.umich.edu * All rights reserved.
44826Ssaidi@eecs.umich.edu *
54826Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
64826Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are
74826Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright
84826Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
94826Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
104826Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
114826Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution;
124826Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its
134826Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from
144826Ssaidi@eecs.umich.edu * this software without specific prior written permission.
154826Ssaidi@eecs.umich.edu *
164826Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174826Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184826Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194826Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204826Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214826Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224826Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234826Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244826Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254826Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264826Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274826Ssaidi@eecs.umich.edu *
284826Ssaidi@eecs.umich.edu * Authors: Jairo Balart
294826Ssaidi@eecs.umich.edu */
304826Ssaidi@eecs.umich.edu
314826Ssaidi@eecs.umich.edu#include "dev/arm/gic_v3.hh"
324826Ssaidi@eecs.umich.edu
3311793Sbrandon.potter@amd.com#include "cpu/intr_control.hh"
344826Ssaidi@eecs.umich.edu#include "debug/GIC.hh"
358706Sandreas.hansson@arm.com#include "debug/Interrupt.hh"
368780Sgblack@eecs.umich.edu#include "dev/arm/gic_v3_cpu_interface.hh"
374826Ssaidi@eecs.umich.edu#include "dev/arm/gic_v3_distributor.hh"
385569Snate@binkert.org#include "dev/arm/gic_v3_redistributor.hh"
394826Ssaidi@eecs.umich.edu#include "dev/platform.hh"
405569Snate@binkert.org#include "mem/packet.hh"
417707Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
424826Ssaidi@eecs.umich.edu
438806Sgblack@eecs.umich.eduGicv3::Gicv3(const Params * p)
448780Sgblack@eecs.umich.edu    : BaseGic(p)
458780Sgblack@eecs.umich.edu{
464826Ssaidi@eecs.umich.edu}
478806Sgblack@eecs.umich.edu
488806Sgblack@eecs.umich.eduvoid
498806Sgblack@eecs.umich.eduGicv3::init()
508806Sgblack@eecs.umich.edu{
5113611Sgabeblack@google.com    distRange = RangeSize(params()->dist_addr,
528806Sgblack@eecs.umich.edu                          Gicv3Distributor::ADDR_RANGE_SIZE - 1);
538806Sgblack@eecs.umich.edu    redistRange = RangeSize(params()->redist_addr,
548806Sgblack@eecs.umich.edu        Gicv3Redistributor::ADDR_RANGE_SIZE * sys->numContexts() - 1);
558806Sgblack@eecs.umich.edu    addrRanges = {distRange, redistRange};
5614020Sgabeblack@google.com    BaseGic::init();
578852Sandreas.hansson@arm.com    distributor = new Gicv3Distributor(this, params()->it_lines);
588852Sandreas.hansson@arm.com    redistributors.resize(sys->numContexts(), nullptr);
598852Sandreas.hansson@arm.com    cpuInterfaces.resize(sys->numContexts(), nullptr);
608806Sgblack@eecs.umich.edu
618806Sgblack@eecs.umich.edu    panic_if(sys->numContexts() > params()->cpu_max,
624826Ssaidi@eecs.umich.edu        "Exceeding maximum number of PEs supported by GICv3: "
634826Ssaidi@eecs.umich.edu        "using %u while maximum is %u\n", sys->numContexts(),
646329Sgblack@eecs.umich.edu        params()->cpu_max);
656329Sgblack@eecs.umich.edu
666329Sgblack@eecs.umich.edu    for (int i = 0; i < sys->numContexts(); i++) {
676329Sgblack@eecs.umich.edu        redistributors[i] = new Gicv3Redistributor(this, i);
686329Sgblack@eecs.umich.edu        cpuInterfaces[i] = new Gicv3CPUInterface(this, i);
696329Sgblack@eecs.umich.edu    }
706329Sgblack@eecs.umich.edu
716329Sgblack@eecs.umich.edu    distributor->init();
726329Sgblack@eecs.umich.edu
7313611Sgabeblack@google.com    for (int i = 0; i < sys->numContexts(); i++) {
746329Sgblack@eecs.umich.edu        redistributors[i]->init();
759920Syasuko.eckert@amd.com        cpuInterfaces[i]->init();
769920Syasuko.eckert@amd.com    }
779920Syasuko.eckert@amd.com}
786329Sgblack@eecs.umich.edu
796329Sgblack@eecs.umich.eduvoid
806329Sgblack@eecs.umich.eduGicv3::initState()
816329Sgblack@eecs.umich.edu{
827720Sgblack@eecs.umich.edu    distributor->initState();
836329Sgblack@eecs.umich.edu
846329Sgblack@eecs.umich.edu    for (int i = 0; i < sys->numContexts(); i++) {
856329Sgblack@eecs.umich.edu        redistributors[i]->initState();
866329Sgblack@eecs.umich.edu        cpuInterfaces[i]->initState();
876329Sgblack@eecs.umich.edu    }
886329Sgblack@eecs.umich.edu}
896329Sgblack@eecs.umich.edu
906329Sgblack@eecs.umich.eduTick
916329Sgblack@eecs.umich.eduGicv3::read(PacketPtr pkt)
926329Sgblack@eecs.umich.edu{
936329Sgblack@eecs.umich.edu    const Addr addr = pkt->getAddr();
946329Sgblack@eecs.umich.edu    const size_t size = pkt->getSize();
956329Sgblack@eecs.umich.edu    bool is_secure_access = pkt->isSecure();
966329Sgblack@eecs.umich.edu    uint64_t resp = 0;
976329Sgblack@eecs.umich.edu    Tick delay = 0;
986329Sgblack@eecs.umich.edu
996329Sgblack@eecs.umich.edu    if (distRange.contains(addr)) {
1007693SAli.Saidi@ARM.com        const Addr daddr = addr - distRange.start();
1017693SAli.Saidi@ARM.com        panic_if(!distributor, "Distributor is null!");
1027693SAli.Saidi@ARM.com        resp = distributor->read(daddr, size, is_secure_access);
10313915Sgabeblack@google.com        delay = params()->dist_pio_delay;
1047720Sgblack@eecs.umich.edu        DPRINTF(GIC, "Gicv3::read(): (distributor) context_id %d register %#x "
1057720Sgblack@eecs.umich.edu                "size %d is_secure_access %d (value %#x)\n",
1067693SAli.Saidi@ARM.com                pkt->req->contextId(), daddr, size, is_secure_access, resp);
1077693SAli.Saidi@ARM.com    } else if (redistRange.contains(addr)) {
1087693SAli.Saidi@ARM.com        Addr daddr = addr - redistRange.start();
1094826Ssaidi@eecs.umich.edu        uint32_t redistributor_id =
1104826Ssaidi@eecs.umich.edu            daddr / Gicv3Redistributor::ADDR_RANGE_SIZE;
111        daddr = daddr % Gicv3Redistributor::ADDR_RANGE_SIZE;
112        panic_if(redistributor_id >= redistributors.size(),
113                 "Invalid redistributor_id!");
114        panic_if(!redistributors[redistributor_id], "Redistributor is null!");
115        resp = redistributors[redistributor_id]->read(daddr, size,
116                                                      is_secure_access);
117        delay = params()->redist_pio_delay;
118        DPRINTF(GIC, "Gicv3::read(): (redistributor %d) context_id %d "
119                "register %#x size %d is_secure_access %d (value %#x)\n",
120                redistributor_id, pkt->req->contextId(), daddr, size,
121                is_secure_access, resp);
122    } else {
123        panic("Gicv3::read(): unknown address %#x\n", addr);
124    }
125
126    pkt->setUintX(resp, LittleEndianByteOrder);
127    pkt->makeAtomicResponse();
128    return delay;
129}
130
131Tick
132Gicv3::write(PacketPtr pkt)
133{
134    const size_t size = pkt->getSize();
135    uint64_t data = pkt->getUintX(LittleEndianByteOrder);
136    const Addr addr = pkt->getAddr();
137    bool is_secure_access = pkt->isSecure();
138    Tick delay = 0;
139
140    if (distRange.contains(addr)) {
141        const Addr daddr = addr - distRange.start();
142        panic_if(!distributor, "Distributor is null!");
143        DPRINTF(GIC, "Gicv3::write(): (distributor) context_id %d "
144                "register %#x size %d is_secure_access %d value %#x\n",
145                pkt->req->contextId(), daddr, size, is_secure_access, data);
146        distributor->write(daddr, data, size, is_secure_access);
147        delay = params()->dist_pio_delay;
148    } else if (redistRange.contains(addr)) {
149        Addr daddr = addr - redistRange.start();
150        uint32_t redistributor_id =
151            daddr / Gicv3Redistributor::ADDR_RANGE_SIZE;
152        daddr = daddr % Gicv3Redistributor::ADDR_RANGE_SIZE;
153        panic_if(redistributor_id >= redistributors.size(),
154                 "Invalid redistributor_id!");
155        panic_if(!redistributors[redistributor_id], "Redistributor is null!");
156        DPRINTF(GIC, "Gicv3::write(): (redistributor %d) context_id %d "
157                "register %#x size %d is_secure_access %d value %#x\n",
158                redistributor_id, pkt->req->contextId(), daddr, size,
159                is_secure_access, data);
160        redistributors[redistributor_id]->write(daddr, data, size,
161                                                is_secure_access);
162        delay = params()->redist_pio_delay;
163    } else {
164        panic("Gicv3::write(): unknown address %#x\n", addr);
165    }
166
167    pkt->makeAtomicResponse();
168    return delay;
169}
170
171void
172Gicv3::sendInt(uint32_t int_id)
173{
174    panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
175    panic_if(int_id >= Gicv3::INTID_SECURE, "Invalid SPI!");
176    DPRINTF(Interrupt, "Gicv3::sendInt(): received SPI %d\n", int_id);
177    distributor->sendInt(int_id);
178}
179
180void
181Gicv3::clearInt(uint32_t number)
182{
183    distributor->deassertSPI(number);
184}
185
186void
187Gicv3::sendPPInt(uint32_t int_id, uint32_t cpu)
188{
189    panic_if(cpu >= redistributors.size(), "Invalid cpuID sending PPI!");
190    panic_if(int_id < Gicv3::SGI_MAX, "Invalid PPI!");
191    panic_if(int_id >= Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid PPI!");
192    DPRINTF(Interrupt, "Gicv3::sendPPInt(): received PPI %d cpuTarget %#x\n",
193            int_id, cpu);
194    redistributors[cpu]->sendPPInt(int_id);
195}
196
197void
198Gicv3::clearPPInt(uint32_t num, uint32_t cpu)
199{
200}
201
202void
203Gicv3::postInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
204{
205    platform->intrctrl->post(cpu, int_type, 0);
206}
207
208void
209Gicv3::deassertInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
210{
211    platform->intrctrl->clear(cpu, int_type, 0);
212}
213
214Gicv3Redistributor *
215Gicv3::getRedistributorByAffinity(uint32_t affinity) const
216{
217    for (auto & redistributor : redistributors) {
218        if (redistributor->getAffinity() == affinity) {
219            return redistributor;
220        }
221    }
222
223    return nullptr;
224}
225
226void
227Gicv3::serialize(CheckpointOut & cp) const
228{
229    distributor->serializeSection(cp, "distributor");
230
231    for (uint32_t redistributor_id = 0;
232         redistributor_id < redistributors.size(); redistributor_id++)
233        redistributors[redistributor_id]->serializeSection(cp,
234            csprintf("redistributors.%i", redistributor_id));
235
236    for (uint32_t cpu_interface_id = 0;
237         cpu_interface_id < cpuInterfaces.size(); cpu_interface_id++)
238        cpuInterfaces[cpu_interface_id]->serializeSection(cp,
239            csprintf("cpuInterface.%i", cpu_interface_id));
240}
241
242void
243Gicv3::unserialize(CheckpointIn & cp)
244{
245    getSystem()->setGIC(this);
246
247    distributor->unserializeSection(cp, "distributor");
248
249    for (uint32_t redistributor_id = 0;
250         redistributor_id < redistributors.size(); redistributor_id++)
251        redistributors[redistributor_id]->unserializeSection(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]->unserializeSection(cp,
257            csprintf("cpuInterface.%i", cpu_interface_id));
258}
259
260Gicv3 *
261Gicv3Params::create()
262{
263    return new Gicv3(this);
264}
265