@@ -331,10 +331,10 @@ static struct page *alloc_largest_available(unsigned long size,
return NULL;
}
-static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
- unsigned long len,
- u32 fd_flags,
- u64 heap_flags)
+static struct dma_buf *__system_heap_allocate(struct dma_heap *heap,
+ struct dma_heap_file *heap_file,
+ unsigned long len, u32 fd_flags,
+ u64 heap_flags)
{
struct system_heap_buffer *buffer;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
@@ -346,6 +346,7 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
struct list_head pages;
struct page *page, *tmp_page;
int i, ret = -ENOMEM;
+ struct dma_heap_file_task *heap_ftask;
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
@@ -357,6 +358,15 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
buffer->len = len;
INIT_LIST_HEAD(&pages);
+
+ if (heap_file) {
+ heap_ftask = dma_heap_declare_file_read(heap_file);
+ if (!heap_ftask) {
+ kfree(buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
i = 0;
while (size_remaining > 0) {
/*
@@ -372,6 +382,13 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
if (!page)
goto free_buffer;
+ /**
+ * If alloc and read, gather each page to read task.
+ * If got error, free buffer and return error.
+ */
+ if (heap_file && dma_heap_gather_file_page(heap_ftask, page))
+ goto free_buffer;
+
list_add_tail(&page->lru, &pages);
size_remaining -= page_size(page);
max_order = compound_order(page);
@@ -400,9 +417,29 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
ret = PTR_ERR(dmabuf);
goto free_pages;
}
+
+ /**
+ * End of alloc, dma-buf export and anything we need, but maybe
+ * file read is still work, so, wait it. if done, destroy all file
+ * task.
+ * But maybe something wrong when read file, if so, abandon dma-buf
+ * return error.
+ */
+ if (heap_file && dma_heap_end_file_read(heap_ftask)) {
+ dma_buf_put(dmabuf);
+ dmabuf = ERR_PTR(-EIO);
+ }
+
return dmabuf;
free_pages:
+ /**
+ * maybe we already trigger file read, so, before release pages,
+ * wait for all running file read task done.
+ */
+ if (heap_file)
+ dma_heap_wait_for_file_read(heap_ftask);
+
for_each_sgtable_sg(table, sg, i) {
struct page *p = sg_page(sg);
@@ -410,6 +447,13 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
}
sg_free_table(table);
free_buffer:
+ /**
+ * maybe we already trigger file read, so, before release pages and
+ * return, destroy file task, include running task.
+ */
+ if (heap_file)
+ dma_heap_end_file_read(heap_ftask);
+
list_for_each_entry_safe(page, tmp_page, &pages, lru)
__free_pages(page, compound_order(page));
kfree(buffer);
@@ -417,8 +461,26 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
return ERR_PTR(ret);
}
+static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
+ unsigned long len, u32 fd_flags,
+ u64 heap_flags)
+{
+ return __system_heap_allocate(heap, NULL, len, fd_flags, heap_flags);
+}
+
+static struct dma_buf *
+system_heap_allocate_async_read_file(struct dma_heap *heap,
+ struct dma_heap_file *heap_file,
+ u32 fd_flags, u64 heap_flags)
+{
+ return __system_heap_allocate(heap, heap_file,
+ PAGE_ALIGN(dma_heap_file_size(heap_file)),
+ fd_flags, heap_flags);
+}
+
static const struct dma_heap_ops system_heap_ops = {
.allocate = system_heap_allocate,
+ .allocate_async_read = system_heap_allocate_async_read_file,
};
static int system_heap_create(void)
The system heap cyclically allocates pages and then places these pages into a scatter_list, which is then managed by the dma-buf. This process can parallelize memory allocation and I/O read operations: Gather each allocated page and trigger a submit once the limit is reached. Once the memory allocation is complete, there is no need to wait immediately for the file read to finish. Instead, continue preparing the dma-buf until it is necessary to return the dma-buf, at which point waiting for the file content to be fully read is required. Note that the content of the page cannot be modified after it is allocated in the heap, as it may cause conflicts with accessing the page when reading from the file. There are currently no conflicts in the system_heap for this part. The formula for the time taken for system_heap buffer allocation and file reading through async_read is as follows: T(total) = T(first gather page) + Max(T(remain alloc), T(I/O)) Compared to the synchronous read: T(total) = T(alloc) + T(I/O) If the allocation time or I/O time is long, the time difference will be covered by the maximum value between the allocation and I/O. The other party will be concealed. Therefore, the larger the size of the file that needs to be read, the greater the corresponding benefits will be. Signed-off-by: Huan Yang <link@vivo.com> --- drivers/dma-buf/heaps/system_heap.c | 70 +++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 4 deletions(-)