blob: b00c0a000332df99815a1b870fe082b8cb8b6a4f [file] [log] [blame]
/*
* Copyright (c) 2021 Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*/
#ifndef __DEV_AMDGPU_PAGETABLE_WALKER_HH__
#define __DEV_AMDGPU_PAGETABLE_WALKER_HH__
#include <vector>
#include "arch/amdgpu/vega/pagetable.hh"
#include "arch/amdgpu/vega/tlb.hh"
#include "base/types.hh"
#include "debug/GPUPTWalker.hh"
#include "mem/packet.hh"
#include "params/VegaPagetableWalker.hh"
#include "sim/clocked_object.hh"
#include "sim/system.hh"
namespace gem5
{
class ThreadContext;
namespace VegaISA
{
class Walker : public ClockedObject
{
protected:
// Port for accessing memory
class WalkerPort : public RequestPort
{
public:
WalkerPort(const std::string &_name, Walker * _walker) :
RequestPort(_name, _walker), walker(_walker)
{}
protected:
Walker *walker;
bool recvTimingResp(PacketPtr pkt);
void recvReqRetry();
};
friend class WalkerPort;
WalkerPort port;
// State to track each walk of the page table
class WalkerState
{
friend class Walker;
private:
enum State
{
Ready,
Waiting,
PDE2, PDE1, PDE0, PTE
};
protected:
Walker *walker;
State state;
State nextState;
int dataSize;
bool enableNX;
VegaTlbEntry entry;
PacketPtr read;
Fault timingFault;
BaseMMU::Mode mode;
bool retrying;
bool started;
bool timing;
PacketPtr tlbPkt;
public:
WalkerState(Walker *_walker, PacketPtr pkt, bool is_functional = false)
: walker(_walker), state(Ready), nextState(Ready), dataSize(8),
enableNX(true), retrying(false), started(false), tlbPkt(pkt)
{
DPRINTF(GPUPTWalker, "Walker::WalkerState %p %p %d\n",
this, walker, state);
}
void initState(BaseMMU::Mode _mode, Addr baseAddr, Addr vaddr,
bool is_functional = false);
void startWalk();
Fault startFunctional(Addr base, Addr vaddr, PageTableEntry &pte,
unsigned &logBytes);
bool isRetrying();
void retry();
std::string name() const { return walker->name(); }
Walker* getWalker() const { return walker; }
private:
Fault stepWalk();
void stepTimingWalk();
void walkStateMachine(PageTableEntry &pte, Addr &nextRead,
bool &doEndWalk, Fault &fault);
void sendPackets();
void endWalk();
Fault pageFault(bool present);
uint64_t offsetFunc(Addr logicalAddr, int top, int lsb);
};
friend class WalkerState;
// State for timing and atomic accesses (need multiple per walker in
// the case of multiple outstanding requests in timing mode)
std::list<WalkerState *> currStates;
// State for functional accesses (only need one of these per walker)
WalkerState funcState;
struct WalkerSenderState : public Packet::SenderState
{
WalkerState * senderWalk;
WalkerSenderState(WalkerState * _senderWalk) :
senderWalk(_senderWalk) {}
};
public:
// Kick off the state machine.
void startTiming(PacketPtr pkt, Addr base, Addr vaddr, BaseMMU::Mode mode);
Fault startFunctional(Addr base, Addr vaddr, PageTableEntry &pte,
unsigned &logBytes, BaseMMU::Mode mode);
Fault startFunctional(Addr base, Addr &addr, unsigned &logBytes,
BaseMMU::Mode mode, bool &isSystem);
Port &getPort(const std::string &if_name,
PortID idx=InvalidPortID) override;
Addr getBaseAddr() const { return baseAddr; }
void setBaseAddr(Addr ta) { baseAddr = ta; }
void setDevRequestor(RequestorID mid) { deviceRequestorId = mid; }
RequestorID getDevRequestor() const { return deviceRequestorId; }
protected:
// The TLB we're supposed to load.
GpuTLB *tlb;
RequestorID requestorId;
// Base address set by MAP_PROCESS packet
Addr baseAddr;
RequestorID deviceRequestorId;
// Functions for dealing with packets.
void recvTimingResp(PacketPtr pkt);
void recvReqRetry();
bool sendTiming(WalkerState * sendingState, PacketPtr pkt);
void walkerResponse(WalkerState *state, VegaTlbEntry& entry,
PacketPtr pkt);
// System pointer for functional accesses
System *system;
public:
void setTLB(GpuTLB * _tlb)
{
assert(tlb == nullptr); // only set it once
tlb = _tlb;
}
Walker(const VegaPagetableWalkerParams &p)
: ClockedObject(p),
port(name() + ".port", this),
funcState(this, nullptr, true), tlb(nullptr),
requestorId(p.system->getRequestorId(this)),
deviceRequestorId(999), system(p.system)
{
DPRINTF(GPUPTWalker, "Walker::Walker %p\n", this);
}
};
} // namespace VegaISA
} // namespace gem5
#endif // __DEV_AMDGPU_PAGETABLE_WALKER_HH__