dev-amdgpu: Check privledge bit for SDMA RLC queues (#792)

By default all SDMA queues are privileged queues, meaning the addresses
in SDMA packets use the privileged translation tables. RLC queues
(sometimes called user queues) are not necessarily privileged and might
use user translation tables. RLC queues are used more often in ROCm 6.0
exposing an issue with invalid translations with RLC queues.

This changeset checks the priv bit in the SDMA MQD when an RLC queue is
mapped. Each packet type which uses an address then checks the bit
before performing translation. Tested with daily/weekly tests with a
ROCm 6.0 disk image and tests are passing.

Change-Id: I6122fbc194e8d6f5d38e81f1b0e11646d90e0ea0
This commit is contained in:
Matthew Poremba
2024-01-24 07:25:43 -08:00
committed by GitHub
parent dfafc5792a
commit 0ac110ac95
2 changed files with 22 additions and 7 deletions

View File

@@ -184,6 +184,7 @@ SDMAEngine::registerRLCQueue(Addr doorbell, Addr mqdAddr, SDMAQueueDesc *mqd)
Addr rptr_wb_addr = mqd->sdmax_rlcx_rb_rptr_addr_hi;
rptr_wb_addr <<= 32;
rptr_wb_addr |= mqd->sdmax_rlcx_rb_rptr_addr_lo;
bool priv = bits(mqd->sdmax_rlcx_rb_cntl, 23, 23);
// Get first free RLC
if (!rlc0.valid()) {
@@ -199,6 +200,7 @@ SDMAEngine::registerRLCQueue(Addr doorbell, Addr mqdAddr, SDMAQueueDesc *mqd)
rlc0.processing(false);
rlc0.setMQD(mqd);
rlc0.setMQDAddr(mqdAddr);
rlc0.setPriv(priv);
} else if (!rlc1.valid()) {
DPRINTF(SDMAEngine, "Doorbell %lx mapped to RLC1\n", doorbell);
rlcInfo[1] = doorbell;
@@ -212,6 +214,7 @@ SDMAEngine::registerRLCQueue(Addr doorbell, Addr mqdAddr, SDMAQueueDesc *mqd)
rlc1.processing(false);
rlc1.setMQD(mqd);
rlc1.setMQDAddr(mqdAddr);
rlc1.setPriv(priv);
} else {
panic("No free RLCs. Check they are properly unmapped.");
}
@@ -622,8 +625,9 @@ SDMAEngine::writeReadData(SDMAQueue *q, sdmaWrite *pkt, uint32_t *dmaBuffer)
gpuDevice->getMemMgr()->writeRequest(mmhubAddr, (uint8_t *)dmaBuffer,
bufferSize, 0, cb);
} else {
// TODO: getGARTAddr?
pkt->dest = getGARTAddr(pkt->dest);
if (q->priv()) {
pkt->dest = getGARTAddr(pkt->dest);
}
auto cb = new DmaVirtCallback<uint32_t>(
[ = ] (const uint64_t &) { writeDone(q, pkt, dmaBuffer); });
dmaWriteVirt(pkt->dest, bufferSize, cb, (void *)dmaBuffer);
@@ -650,9 +654,11 @@ SDMAEngine::copy(SDMAQueue *q, sdmaCopy *pkt)
q->incRptr(sizeof(sdmaCopy));
// count represents the number of bytes - 1 to be copied
pkt->count++;
DPRINTF(SDMAEngine, "Getting GART addr for %lx\n", pkt->source);
pkt->source = getGARTAddr(pkt->source);
DPRINTF(SDMAEngine, "GART addr %lx\n", pkt->source);
if (q->priv()) {
DPRINTF(SDMAEngine, "Getting GART addr for %lx\n", pkt->source);
pkt->source = getGARTAddr(pkt->source);
DPRINTF(SDMAEngine, "GART addr %lx\n", pkt->source);
}
// Read data from the source first, then call the copyReadData method
uint8_t *dmaBuffer = new uint8_t[pkt->count];
@@ -745,7 +751,11 @@ SDMAEngine::copyDone(SDMAQueue *q, sdmaCopy *pkt, uint8_t *dmaBuffer)
void
SDMAEngine::indirectBuffer(SDMAQueue *q, sdmaIndirectBuffer *pkt)
{
q->ib()->base(getGARTAddr(pkt->base));
if (q->priv()) {
q->ib()->base(getGARTAddr(pkt->base));
} else {
q->ib()->base(pkt->base);
}
q->ib()->rptr(0);
q->ib()->size(pkt->size * sizeof(uint32_t) + 1);
q->ib()->setWptr(pkt->size * sizeof(uint32_t));
@@ -761,7 +771,9 @@ void
SDMAEngine::fence(SDMAQueue *q, sdmaFence *pkt)
{
q->incRptr(sizeof(sdmaFence));
pkt->dest = getGARTAddr(pkt->dest);
if (q->priv()) {
pkt->dest = getGARTAddr(pkt->dest);
}
// Writing the data from the fence packet to the destination address.
auto cb = new DmaVirtCallback<uint32_t>(

View File

@@ -68,6 +68,7 @@ class SDMAEngine : public DmaVirtDevice
SDMAType _type;
SDMAQueueDesc *_mqd;
Addr _mqd_addr = 0;
bool _priv = true; // Only used for RLC queues. True otherwise.
public:
SDMAQueue() : _rptr(0), _wptr(0), _valid(false), _processing(false),
_parent(nullptr), _ib(nullptr), _type(SDMAGfx), _mqd(nullptr) {}
@@ -87,6 +88,7 @@ class SDMAEngine : public DmaVirtDevice
SDMAType queueType() { return _type; }
SDMAQueueDesc* getMQD() { return _mqd; }
Addr getMQDAddr() { return _mqd_addr; }
bool priv() { return _priv; }
void base(Addr value) { _base = value; }
@@ -121,6 +123,7 @@ class SDMAEngine : public DmaVirtDevice
void queueType(SDMAType type) { _type = type; }
void setMQD(SDMAQueueDesc *mqd) { _mqd = mqd; }
void setMQDAddr(Addr mqdAddr) { _mqd_addr = mqdAddr; }
void setPriv(bool priv) { _priv = priv; }
};
/* SDMA Engine ID */