2 * Copyright (c) 2019 ARM Limited
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.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include "dev/arm/smmu_v3_slaveifc.hh"
40 #include "base/trace.hh"
41 #include "debug/SMMUv3.hh"
42 #include "dev/arm/smmu_v3.hh"
43 #include "dev/arm/smmu_v3_transl.hh"
45 SMMUv3SlaveInterface::SMMUv3SlaveInterface(
46 const SMMUv3SlaveInterfaceParams
*p
) :
49 microTLB(new SMMUTLB(p
->utlb_entries
,
52 mainTLB(new SMMUTLB(p
->tlb_entries
,
55 microTLBEnable(p
->utlb_enable
),
56 mainTLBEnable(p
->tlb_enable
),
58 microTLBSem(p
->utlb_slots
),
59 mainTLBSem(p
->tlb_slots
),
60 microTLBLat(p
->utlb_lat
),
61 mainTLBLat(p
->tlb_lat
),
62 slavePort(new SMMUSlavePort(csprintf("%s.slave", name()), *this)),
63 atsSlavePort(name() + ".atsSlave", *this),
64 atsMasterPort(name() + ".atsMaster", *this),
65 portWidth(p
->port_width
),
66 wrBufSlotsRemaining(p
->wrbuf_slots
),
67 xlateSlotsRemaining(p
->xlate_slots
),
68 pendingMemAccesses(0),
69 prefetchEnable(p
->prefetch_enable
),
70 prefetchReserveLastWay(
71 p
->prefetch_reserve_last_way
),
72 deviceNeedsRetry(false),
73 atsDeviceNeedsRetry(false),
74 sendDeviceRetryEvent(*this),
75 atsSendDeviceRetryEvent(this)
79 SMMUv3SlaveInterface::sendRange()
81 if (slavePort
->isConnected()) {
82 inform("Slave port is connected to %s\n", slavePort
->getPeer());
84 slavePort
->sendRangeChange();
86 fatal("Slave port is not connected.\n");
91 SMMUv3SlaveInterface::getPort(const std::string
&name
, PortID id
)
93 if (name
== "ats_master") {
95 } else if (name
== "slave") {
97 } else if (name
== "ats_slave") {
100 return ClockedObject::getPort(name
, id
);
105 SMMUv3SlaveInterface::schedTimingResp(PacketPtr pkt
)
107 slavePort
->schedTimingResp(pkt
, nextCycle());
111 SMMUv3SlaveInterface::schedAtsTimingResp(PacketPtr pkt
)
113 atsSlavePort
.schedTimingResp(pkt
, nextCycle());
115 if (atsDeviceNeedsRetry
) {
116 atsDeviceNeedsRetry
= false;
117 schedule(atsSendDeviceRetryEvent
, nextCycle());
122 SMMUv3SlaveInterface::recvAtomic(PacketPtr pkt
)
124 DPRINTF(SMMUv3
, "[a] req from %s addr=%#x size=%#x\n",
125 slavePort
->getPeer(), pkt
->getAddr(), pkt
->getSize());
127 std::string proc_name
= csprintf("%s.port", name());
128 SMMUTranslationProcess
proc(proc_name
, *smmu
, *this);
129 proc
.beginTransaction(SMMUTranslRequest::fromPacket(pkt
));
131 SMMUAction a
= smmu
->runProcessAtomic(&proc
, pkt
);
132 assert(a
.type
== ACTION_SEND_RESP
);
138 SMMUv3SlaveInterface::recvTimingReq(PacketPtr pkt
)
140 DPRINTF(SMMUv3
, "[t] req from %s addr=%#x size=%#x\n",
141 slavePort
->getPeer(), pkt
->getAddr(), pkt
->getSize());
143 // @todo: We need to pay for this and not just zero it out
144 pkt
->headerDelay
= pkt
->payloadDelay
= 0;
147 (pkt
->getSize() + (portWidth
-1)) / portWidth
;
149 if (xlateSlotsRemaining
==0 ||
150 (pkt
->isWrite() && wrBufSlotsRemaining
< nbeats
))
152 deviceNeedsRetry
= true;
157 wrBufSlotsRemaining
-= nbeats
;
159 std::string proc_name
= csprintf("%s.port", name());
160 SMMUTranslationProcess
*proc
=
161 new SMMUTranslationProcess(proc_name
, *smmu
, *this);
162 proc
->beginTransaction(SMMUTranslRequest::fromPacket(pkt
));
164 smmu
->runProcessTiming(proc
, pkt
);
170 SMMUv3SlaveInterface::atsSlaveRecvAtomic(PacketPtr pkt
)
172 DPRINTF(SMMUv3
, "[a] ATS slave req addr=%#x size=%#x\n",
173 pkt
->getAddr(), pkt
->getSize());
175 std::string proc_name
= csprintf("%s.atsport", name());
176 const bool ats_request
= true;
177 SMMUTranslationProcess
proc(
178 proc_name
, *smmu
, *this);
179 proc
.beginTransaction(SMMUTranslRequest::fromPacket(pkt
, ats_request
));
181 SMMUAction a
= smmu
->runProcessAtomic(&proc
, pkt
);
182 assert(a
.type
== ACTION_SEND_RESP_ATS
);
188 SMMUv3SlaveInterface::atsSlaveRecvTimingReq(PacketPtr pkt
)
190 DPRINTF(SMMUv3
, "[t] ATS slave req addr=%#x size=%#x\n",
191 pkt
->getAddr(), pkt
->getSize());
193 // @todo: We need to pay for this and not just zero it out
194 pkt
->headerDelay
= pkt
->payloadDelay
= 0;
196 if (xlateSlotsRemaining
== 0) {
197 deviceNeedsRetry
= true;
201 std::string proc_name
= csprintf("%s.atsport", name());
202 const bool ats_request
= true;
203 SMMUTranslationProcess
*proc
=
204 new SMMUTranslationProcess(proc_name
, *smmu
, *this);
205 proc
->beginTransaction(SMMUTranslRequest::fromPacket(pkt
, ats_request
));
207 smmu
->runProcessTiming(proc
, pkt
);
213 SMMUv3SlaveInterface::atsMasterRecvTimingResp(PacketPtr pkt
)
215 DPRINTF(SMMUv3
, "[t] ATS master resp addr=%#x size=%#x\n",
216 pkt
->getAddr(), pkt
->getSize());
218 // @todo: We need to pay for this and not just zero it out
219 pkt
->headerDelay
= pkt
->payloadDelay
= 0;
222 safe_cast
<SMMUProcess
*>(pkt
->popSenderState());
224 smmu
->runProcessTiming(proc
, pkt
);
230 SMMUv3SlaveInterface::sendDeviceRetry()
232 slavePort
->sendRetryReq();
236 SMMUv3SlaveInterface::atsSendDeviceRetry()
238 DPRINTF(SMMUv3
, "ATS retry\n");
239 atsSlavePort
.sendRetryReq();
243 SMMUv3SlaveInterface::scheduleDeviceRetry()
245 if (deviceNeedsRetry
&& !sendDeviceRetryEvent
.scheduled()) {
246 DPRINTF(SMMUv3
, "sched slave retry\n");
247 deviceNeedsRetry
= false;
248 schedule(sendDeviceRetryEvent
, nextCycle());
253 SMMUv3SlaveInterface::drain()
255 // Wait until all SMMU translations are completed
256 if (xlateSlotsRemaining
< params()->xlate_slots
) {
257 return DrainState::Draining
;
259 return DrainState::Drained
;
262 SMMUv3SlaveInterface
*
263 SMMUv3SlaveInterfaceParams::create()
265 return new SMMUv3SlaveInterface(this);