Skip to content

Commit

Permalink
use ring buffer to store DMA descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
adstraw committed Aug 22, 2022
1 parent 87b3115 commit 06b4ef8
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 25 deletions.
62 changes: 45 additions & 17 deletions src/runtime/hexagon/hexagon_user_dma.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,26 @@ int HexagonUserDMA::Copy(void* dst, void* src, uint32_t length) {
uint32_t src32 = static_cast<uint32_t>(src64);
uint32_t dst32 = static_cast<uint32_t>(dst64);

// allocate new descriptor
void* dma_desc = nullptr;
int ret = posix_memalign(&dma_desc, DMA_DESC_2D_SIZE, DMA_DESC_2D_SIZE);
if (ret || !dma_desc) {
return DMA_FAILURE;
// check if the next DMA descriptor will overwrite an in flight DMA descriptor
// if this is the first DMA there is nothting to check
if (!first_dma_) {
// update the ID of the oldest DMA descriptor in flight
DMAsInFlight();
// calcultate whether there are DMA descriptors in flight
bool dma_desc_in_flight = id_next_dma_desc_ != id_oldest_dma_desc_in_flight_;
// calculate whether the next DMA descriptor will overwrite the oldest DMA descriptor in flight
bool same_ring_buff_index = (id_next_dma_desc_ % dma_desc_ring_buff_size_) ==
(id_oldest_dma_desc_in_flight_ % dma_desc_ring_buff_size_);
// fail if there are DMA descriptors in flight
// and the next DMA descriptor overwrites the oldest DMA descriptor in flight
if (dma_desc_in_flight && same_ring_buff_index) {
return DMA_FAILURE;
}
}

// get pointer to next DMA descriptor
void* dma_desc = GetDescriptorAddr(id_next_dma_desc_);

// populate descriptor fields
dma_desc_set_state(dma_desc, DESC_STATE_READY);
dma_desc_set_next(dma_desc, DMA_NULL_PTR);
Expand All @@ -82,12 +95,13 @@ int HexagonUserDMA::Copy(void* dst, void* src, uint32_t length) {
dmstart(dma_desc);
first_dma_ = false;
} else {
// `dmlink` descriptor to tail
dmlink(dma_descriptors_.back(), dma_desc);
// `dmlink` descriptor to tail descriptor
void* tail = GetDescriptorAddr(id_next_dma_desc_ - 1);
dmlink(tail, dma_desc);
}

// set descriptor as new tail
dma_descriptors_.push_back(dma_desc);
// update the ID of the next DMA descriptor
id_next_dma_desc_++;

return DMA_SUCCESS;
}
Expand All @@ -104,28 +118,42 @@ uint32_t HexagonUserDMA::DMAsInFlight() {
// poll DMA engine to make sure DMA status is current
dmpoll();

// find the oldest DMA in flight
for (; oldest_dma_in_flight_ < dma_descriptors_.size(); ++oldest_dma_in_flight_) {
// find the oldest DMA descriptor in flight
// total number of DMA descriptors in flight == ID of the next DMA descriptor
for (; id_oldest_dma_desc_in_flight_ < id_next_dma_desc_; ++id_oldest_dma_desc_in_flight_) {
// read the `done` bit from the DMA descriptor and stop if incomplete
unsigned int done = dma_desc_get_done(dma_descriptors_[oldest_dma_in_flight_]);
unsigned int done = dma_desc_get_done(GetDescriptorAddr(id_oldest_dma_desc_in_flight_));
if (done == DESC_DONE_INCOMPLETE) {
break;
}
}
// total DMAs in flight = total DMAs - oldest DMA in flight
return dma_descriptors_.size() - oldest_dma_in_flight_;

// total DMA descriptors in flight = total number DMA desc - ID of the oldest DMA desc in flight
// note that these two IDs are equivalent when no DMA descriptors are in flight
return id_next_dma_desc_ - id_oldest_dma_desc_in_flight_;
}

void* HexagonUserDMA::GetDescriptorAddr(uint32_t dma_desc_id) {
return static_cast<char*>(dma_desc_ring_buff_) +
DMA_DESC_2D_SIZE * (dma_desc_id % dma_desc_ring_buff_size_);
}

HexagonUserDMA::HexagonUserDMA() {
// reset DMA engine
unsigned int status = Init();
CHECK_EQ(status, DM0_STATUS_IDLE);

// allocate memory for ring buffer storage for all DMA descriptors
int ret = posix_memalign(&dma_desc_ring_buff_, DMA_DESC_2D_SIZE,
DMA_DESC_2D_SIZE * dma_desc_ring_buff_size_);
CHECK_EQ(ret, 0);
CHECK_NE(dma_desc_ring_buff_, nullptr);
}

HexagonUserDMA::~HexagonUserDMA() {
for (auto dma_desc : dma_descriptors_) {
free(dma_desc);
}
// stop the DMA engine
Init();
free(dma_desc_ring_buff_);
}

int hexagon_user_dma_1d_sync(void* dst, void* src, uint32_t length) {
Expand Down
27 changes: 21 additions & 6 deletions src/runtime/hexagon/hexagon_user_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_USER_DMA_H_
#define TVM_RUNTIME_HEXAGON_HEXAGON_USER_DMA_H_

#include <vector>
#include <stdint.h>

namespace tvm {
namespace runtime {
Expand Down Expand Up @@ -70,14 +70,29 @@ class HexagonUserDMA {
//! \brief Initializes the Hexagon User DMA engine
unsigned int Init();

//! \brief Calculates the number of DMAs in flight
//! \brief Calculates and returns the number of DMAs in flight; updates the ID of the oldest
//! descriptor in flight
uint32_t DMAsInFlight();

//! \brief Stores descriptors for all DMAs
std::vector<void*> dma_descriptors_;
//! \brief Calculates and returns the address of a DMA descriptor in the ring buffer given a
//! descriptor ID
void* GetDescriptorAddr(uint32_t dma_desc_id);

//! \brief Index to the descriptor for the oldest DMA in flight
uint32_t oldest_dma_in_flight_{0};
//! \brief Pointer to ring buffer storage for all DMA descriptors
void* dma_desc_ring_buff_{nullptr};

//! \brief Size of ring buffer storage for all DMA descriptors
const uint32_t dma_desc_ring_buff_size_{100};

//! \brief Tracks both the total number of DMA descriptors and the ID of the next DMA descriptor
//! to be added to the ring buffer - modulo ring buffer size to find the ring buffer index for the
//! next DMA descriptor
uint32_t id_next_dma_desc_{0};

//! \brief Tracks the ID of the oldest DMA descriptor in flight OR the ID of the next DMA
//! descriptor if no DMA descriptors are in flight - modulo ring buffer size to find the ring
//! buffer index for the oldest DMA descriptor in flight
uint32_t id_oldest_dma_desc_in_flight_{0};

//! \brief Tracks whether (or not) we are executing the very first DMA
bool first_dma_{true};
Expand Down
4 changes: 2 additions & 2 deletions tests/cpp-runtime/hexagon/hexagon_user_dma_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ TEST_F(HexagonUserDMATest, wait) {
HexagonUserDMA::Get().Wait(10);
}

TEST_F(HexagonUserDMATest, just_poll) { ASSERT_EQ(HexagonUserDMA::Get().Poll(), 0); }
TEST_F(HexagonUserDMATest, poll) { ASSERT_EQ(HexagonUserDMA::Get().Poll(), 0); }

TEST_F(HexagonUserDMATest, copy) {
TEST_F(HexagonUserDMATest, bad_copy) {
uint64_t bigaddr = 0x100000000;
void* src64 = reinterpret_cast<void*>(bigaddr);
void* dst64 = reinterpret_cast<void*>(bigaddr);
Expand Down

0 comments on commit 06b4ef8

Please sign in to comment.