ttm_pool_alloc() always allocates on the pool's default node, although the internal TTM helpers (__ttm_pool_alloc(), ttm_pool_alloc_page(), ttm_pool_type_take()) already take a nid. Add ttm_pool_alloc_node() to let a driver pass that nid for a specific tt.
ttm_pool_alloc() passes NUMA_NO_NODE, keeping current behaviour. An explicit node on a dma_alloc pool returns -EOPNOTSUPP, as dma_alloc_attrs() can't honor it. Signed-off-by: Himal Prasad Ghimiray <[email protected]> --- drivers/gpu/drm/ttm/ttm_pool.c | 59 +++++++++++++++++++++++++++++----- include/drm/ttm/ttm_pool.h | 2 ++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index 1bf37023fed6..54d2f6b5c229 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -158,9 +158,9 @@ static int ttm_pool_nid(struct ttm_pool *pool) return nid; } -/* Allocate pages of size 1 << order with the given gfp_flags */ +/* Allocate pages of size 1 << order with the given gfp_flags on node @nid */ static struct page *ttm_pool_alloc_page(struct ttm_pool *pool, gfp_t gfp_flags, - unsigned int order) + unsigned int order, int nid) { const unsigned int beneficial_order = ttm_pool_beneficial_order(pool); unsigned long attr = DMA_ATTR_FORCE_CONTIGUOUS; @@ -189,7 +189,7 @@ static struct page *ttm_pool_alloc_page(struct ttm_pool *pool, gfp_t gfp_flags, } if (!ttm_pool_uses_dma_alloc(pool)) { - p = alloc_pages_node(pool->nid, gfp_flags, order); + p = alloc_pages_node(nid, gfp_flags, order); if (p) { p->private = order; mod_lruvec_page_state(p, NR_GPU_ACTIVE, 1 << order); @@ -783,7 +783,8 @@ static unsigned int ttm_pool_alloc_find_order(unsigned int highest, static int __ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, const struct ttm_operation_ctx *ctx, struct ttm_pool_alloc_state *alloc, - struct ttm_pool_tt_restore *restore) + struct ttm_pool_tt_restore *restore, + int nid) { enum ttm_caching page_caching; gfp_t gfp_flags = GFP_USER; @@ -818,7 +819,7 @@ static int __ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, p = NULL; pt = ttm_pool_select_type(pool, page_caching, order); if (pt && allow_pools) - p = ttm_pool_type_take(pt, ttm_pool_nid(pool)); + p = ttm_pool_type_take(pt, nid); /* * If that fails or previously failed, allocate from system. @@ -829,7 +830,7 @@ static int __ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, if (!p) { page_caching = ttm_cached; allow_pools = false; - p = ttm_pool_alloc_page(pool, gfp_flags, order); + p = ttm_pool_alloc_page(pool, gfp_flags, order, nid); } /* If that fails, lower the order if possible and retry. */ if (!p) { @@ -900,10 +901,52 @@ int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, ttm_pool_alloc_state_init(tt, &alloc); - return __ttm_pool_alloc(pool, tt, ctx, &alloc, NULL); + return __ttm_pool_alloc(pool, tt, ctx, &alloc, NULL, ttm_pool_nid(pool)); } EXPORT_SYMBOL(ttm_pool_alloc); +/** + * ttm_pool_alloc_node - Fill a ttm_tt object, placing pages on a given node + * + * @pool: ttm_pool to use + * @tt: ttm_tt object to fill + * @ctx: operation context + * @nid: NUMA node id to allocate the backing system pages from, or + * NUMA_NO_NODE to use the pool's default node (@ttm_pool.nid) + * + * Like ttm_pool_alloc(), but allows the caller to override the NUMA node the + * backing system pages are allocated from. This only affects the + * non-coherent (non dma-alloc) allocation path; coherent/dma pools continue + * to use the device-local node. Intended for drivers that expose a + * user-selectable host memory NUMA placement. + * + * Returns: 0 on success, -EOPNOTSUPP if @nid is specified on a coherent/dma + * pool, negative error code otherwise. + */ +int ttm_pool_alloc_node(struct ttm_pool *pool, struct ttm_tt *tt, + struct ttm_operation_ctx *ctx, int nid) +{ + struct ttm_pool_alloc_state alloc; + + if (WARN_ON(ttm_tt_is_backed_up(tt))) + return -EINVAL; + + /* + * Coherent/dma pools allocate via dma_alloc_attrs(), which places pages + * per device DMA constraints and cannot honor a caller-requested node. + */ + if (nid != NUMA_NO_NODE && ttm_pool_uses_dma_alloc(pool)) + return -EOPNOTSUPP; + + if (nid == NUMA_NO_NODE) + nid = ttm_pool_nid(pool); + + ttm_pool_alloc_state_init(tt, &alloc); + + return __ttm_pool_alloc(pool, tt, ctx, &alloc, NULL, nid); +} +EXPORT_SYMBOL(ttm_pool_alloc_node); + /** * ttm_pool_restore_and_alloc - Fill a ttm_tt, restoring previously backed-up * content. @@ -964,7 +1007,7 @@ int ttm_pool_restore_and_alloc(struct ttm_pool *pool, struct ttm_tt *tt, } } - return __ttm_pool_alloc(pool, tt, ctx, &alloc, restore); + return __ttm_pool_alloc(pool, tt, ctx, &alloc, restore, ttm_pool_nid(pool)); } /** diff --git a/include/drm/ttm/ttm_pool.h b/include/drm/ttm/ttm_pool.h index 26ee592e1994..6a0b14aca092 100644 --- a/include/drm/ttm/ttm_pool.h +++ b/include/drm/ttm/ttm_pool.h @@ -79,6 +79,8 @@ struct ttm_pool { int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, struct ttm_operation_ctx *ctx); +int ttm_pool_alloc_node(struct ttm_pool *pool, struct ttm_tt *tt, + struct ttm_operation_ctx *ctx, int nid); void ttm_pool_free(struct ttm_pool *pool, struct ttm_tt *tt); void ttm_pool_init(struct ttm_pool *pool, struct device *dev, -- 2.43.0
