Re: [RFC PATCH 6/7] drm/ttm: Introduce a huge page aligning TTM range manager.

From: Thomas HellstrÃm (VMware)
Date: Wed Nov 27 2019 - 07:30:30 EST


On 11/27/19 11:05 AM, Christian KÃnig wrote:
I don't see the advantage over just increasing the alignment requirements in the driver side?

The advantage is that we don't fail space allocation if we can't match the alignment. We instead fall back to a lower alignment if it's compatible with the GPU required alignment.

Thanks,
/Thomas



That would be a one liner if I'm not completely mistaken.

Regards,
Christian.

Am 27.11.19 um 09:31 schrieb Thomas HellstrÃm (VMware):
From: Thomas Hellstrom <thellstrom@xxxxxxxxxx>

Using huge page-table entries require that the start of a buffer object
is huge page size aligned. So introduce a ttm_bo_man_get_node_huge()
function that attempts to accomplish this for allocations that are larger
than the huge page size, and provide a new range-manager instance that
uses that function.

Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Cc: Michal Hocko <mhocko@xxxxxxxx>
Cc: "Matthew Wilcox (Oracle)" <willy@xxxxxxxxxxxxx>
Cc: "Kirill A. Shutemov" <kirill.shutemov@xxxxxxxxxxxxxxx>
Cc: Ralph Campbell <rcampbell@xxxxxxxxxx>
Cc: "JÃrÃme Glisse" <jglisse@xxxxxxxxxx>
Cc: "Christian KÃnig" <christian.koenig@xxxxxxx>
Signed-off-by: Thomas Hellstrom <thellstrom@xxxxxxxxxx>
---
 drivers/gpu/drm/ttm/ttm_bo_manager.c | 92 ++++++++++++++++++++++++++++
 include/drm/ttm/ttm_bo_driver.h | 1 +
 2 files changed, 93 insertions(+)

diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c
index 18d3debcc949..26aa1a2ae7f1 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c
@@ -89,6 +89,89 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
ÂÂÂÂÂ return 0;
 }
 +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static int ttm_bo_insert_aligned(struct drm_mm *mm, struct drm_mm_node *node,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned long align_pages,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ const struct ttm_place *place,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct ttm_mem_reg *mem,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned long lpfn,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ enum drm_mm_insert_mode mode)
+{
+ÂÂÂ if (align_pages >= mem->page_alignment &&
+ÂÂÂÂÂÂÂ (!mem->page_alignment || align_pages % mem->page_alignment == 0)) {
+ÂÂÂÂÂÂÂ return drm_mm_insert_node_in_range(mm, node,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ mem->num_pages,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ align_pages, 0,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ place->fpfn, lpfn, mode);
+ÂÂÂ }
+
+ÂÂÂ return -ENOSPC;
+}
+
+static int ttm_bo_man_get_node_huge(struct ttm_mem_type_manager *man,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct ttm_buffer_object *bo,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ const struct ttm_place *place,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct ttm_mem_reg *mem)
+{
+ÂÂÂ struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+ÂÂÂ struct drm_mm *mm = &rman->mm;
+ÂÂÂ struct drm_mm_node *node;
+ÂÂÂ unsigned long align_pages;
+ÂÂÂ unsigned long lpfn;
+ÂÂÂ enum drm_mm_insert_mode mode = DRM_MM_INSERT_BEST;
+ÂÂÂ int ret;
+
+ÂÂÂ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ÂÂÂ if (!node)
+ÂÂÂÂÂÂÂ return -ENOMEM;
+
+ÂÂÂ lpfn = place->lpfn;
+ÂÂÂ if (!lpfn)
+ÂÂÂÂÂÂÂ lpfn = man->size;
+
+ÂÂÂ mode = DRM_MM_INSERT_BEST;
+ÂÂÂ if (place->flags & TTM_PL_FLAG_TOPDOWN)
+ÂÂÂÂÂÂÂ mode = DRM_MM_INSERT_HIGH;
+
+ÂÂÂ spin_lock(&rman->lock);
+ÂÂÂ if (IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)) {
+ÂÂÂÂÂÂÂ align_pages = (HPAGE_PUD_SIZE >> PAGE_SHIFT);
+ÂÂÂÂÂÂÂ if (mem->num_pages >= align_pages) {
+ÂÂÂÂÂÂÂÂÂÂÂ ret = ttm_bo_insert_aligned(mm, node, align_pages,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ place, mem, lpfn, mode);
+ÂÂÂÂÂÂÂÂÂÂÂ if (!ret)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ goto found_unlock;
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
+
+ÂÂÂ align_pages = (HPAGE_PMD_SIZE >> PAGE_SHIFT);
+ÂÂÂ if (mem->num_pages >= align_pages) {
+ÂÂÂÂÂÂÂ ret = ttm_bo_insert_aligned(mm, node, align_pages, place, mem,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ lpfn, mode);
+ÂÂÂÂÂÂÂ if (!ret)
+ÂÂÂÂÂÂÂÂÂÂÂ goto found_unlock;
+ÂÂÂ }
+
+ÂÂÂ ret = drm_mm_insert_node_in_range(mm, node, mem->num_pages,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ mem->page_alignment, 0,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ place->fpfn, lpfn, mode);
+found_unlock:
+ÂÂÂ spin_unlock(&rman->lock);
+
+ÂÂÂ if (unlikely(ret)) {
+ÂÂÂÂÂÂÂ kfree(node);
+ÂÂÂ } else {
+ÂÂÂÂÂÂÂ mem->mm_node = node;
+ÂÂÂÂÂÂÂ mem->start = node->start;
+ÂÂÂ }
+
+ÂÂÂ return 0;
+}
+#else
+#define ttm_bo_man_get_node_huge ttm_bo_man_get_node
+#endif
+
+
 static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct ttm_mem_reg *mem)
 {
@@ -154,3 +237,12 @@ const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
ÂÂÂÂÂ .debug = ttm_bo_man_debug
 };
 EXPORT_SYMBOL(ttm_bo_manager_func);
+
+const struct ttm_mem_type_manager_func ttm_bo_manager_huge_func = {
+ÂÂÂ .init = ttm_bo_man_init,
+ÂÂÂ .takedown = ttm_bo_man_takedown,
+ÂÂÂ .get_node = ttm_bo_man_get_node_huge,
+ÂÂÂ .put_node = ttm_bo_man_put_node,
+ÂÂÂ .debug = ttm_bo_man_debug
+};
+EXPORT_SYMBOL(ttm_bo_manager_huge_func);
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index cac7a8a0825a..868bd0d4be6a 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -888,5 +888,6 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo);
 pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp);
  extern const struct ttm_mem_type_manager_func ttm_bo_manager_func;
+extern const struct ttm_mem_type_manager_func ttm_bo_manager_huge_func;
  #endif