From fc0ed906f1eaf189eff76f586bb898eaa4193ba9 Mon Sep 17 00:00:00 2001 From: Ionut Nechita Date: Mon, 23 Mar 2026 23:13:43 +0200 Subject: drm/amd/display: Wire up dcn10_dio_construct() for all pre-DCN401 generations Description: - Commit b82f0759346617b2 ("drm/amd/display: Migrate DIO registers access from hwseq to dio component") moved DIO_MEM_PWR_CTRL register access behind the new dio abstraction layer but only created the dio object for DCN 4.01. On all other generations (DCN 10/20/21/201/30/301/302/303/ 31/314/315/316/32/321/35/351/36), the dio pointer is NULL, causing the register write to be silently skipped. This results in AFMT HDMI memory not being powered on during init_hw, which can cause HDMI audio failures and display issues on affected hardware including Renoir/Cezanne (DCN 2.1) APUs that use dcn10_init_hw. Call dcn10_dio_construct() in each older DCN generation's resource.c to create the dio object, following the same pattern as DCN 4.01. This ensures the dio pointer is non-NULL and the mem_pwr_ctrl callback works through the dio abstraction for all DCN generations. Fixes: b82f07593466 ("drm/amd/display: Migrate DIO registers access from hwseq to dio component.") Reviewed-by: Ivan Lipski Signed-off-by: Ionut Nechita Signed-off-by: Alex Deucher (cherry picked from commit a4983968fa5b3179ab090407d325a71cdc96874e) --- .../amd/display/dc/resource/dcn10/dcn10_resource.c | 41 +++++++++++++++++++++ .../amd/display/dc/resource/dcn20/dcn20_resource.c | 42 +++++++++++++++++++++ .../display/dc/resource/dcn201/dcn201_resource.c | 41 +++++++++++++++++++++ .../amd/display/dc/resource/dcn21/dcn21_resource.c | 34 +++++++++++++++++ .../amd/display/dc/resource/dcn30/dcn30_resource.c | 42 +++++++++++++++++++++ .../display/dc/resource/dcn301/dcn301_resource.c | 42 +++++++++++++++++++++ .../display/dc/resource/dcn302/dcn302_resource.c | 41 +++++++++++++++++++++ .../display/dc/resource/dcn303/dcn303_resource.c | 41 +++++++++++++++++++++ .../amd/display/dc/resource/dcn31/dcn31_resource.c | 40 ++++++++++++++++++++ .../display/dc/resource/dcn314/dcn314_resource.c | 40 ++++++++++++++++++++ .../display/dc/resource/dcn315/dcn315_resource.c | 40 ++++++++++++++++++++ .../display/dc/resource/dcn316/dcn316_resource.c | 40 ++++++++++++++++++++ .../amd/display/dc/resource/dcn32/dcn32_resource.c | 43 ++++++++++++++++++++++ .../display/dc/resource/dcn321/dcn321_resource.c | 43 ++++++++++++++++++++++ .../amd/display/dc/resource/dcn35/dcn35_resource.c | 43 ++++++++++++++++++++++ .../display/dc/resource/dcn351/dcn351_resource.c | 43 ++++++++++++++++++++++ .../amd/display/dc/resource/dcn36/dcn36_resource.c | 43 ++++++++++++++++++++++ 17 files changed, 699 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c index 250c3975b9e9..0fdebe63d355 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c @@ -71,6 +71,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f @@ -444,6 +445,33 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN10(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn10_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static int map_transmitter_id_to_phy_instance( enum transmitter transmitter) { @@ -918,6 +946,11 @@ static void dcn10_resource_destruct(struct dcn10_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.opps[i] != NULL) pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); @@ -1663,6 +1696,14 @@ static bool dcn10_resource_construct( goto fail; } + /* DIO */ + pool->base.dio = dcn10_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto fail; + } + if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) goto fail; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c index bd5c18ee35e7..a99829f23965 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c @@ -82,6 +82,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #include "vm_helper.h" #include "link_enc_cfg.h" @@ -550,6 +551,33 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN20(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn20_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + #define vmid_regs(id)\ [id] = {\ DCN20_VMID_REG_LIST(id)\ @@ -1105,6 +1133,12 @@ static void dcn20_resource_destruct(struct dcn20_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn20_dpp_destroy(&pool->base.dpps[i]); @@ -2709,6 +2743,14 @@ static bool dcn20_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn20_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn20_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c index 491d8d3b1b68..02b7dc07ad53 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c @@ -56,6 +56,7 @@ #include "dce/dce_aux.h" #include "dce/dce_i2c.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "cyan_skillfish_ip_offset.h" @@ -755,6 +756,33 @@ static struct hubbub *dcn201_hubbub_create(struct dc_context *ctx) return &hubbub->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn201_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn201_timing_generator_create( struct dc_context *ctx, uint32_t instance) @@ -930,6 +958,11 @@ static void dcn201_resource_destruct(struct dcn201_resource_pool *pool) pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn201_dpp_destroy(&pool->base.dpps[i]); @@ -1277,6 +1310,14 @@ static bool dcn201_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn201_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) goto create_fail; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c index bd19168a3f77..54ebf8cf607f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -84,6 +84,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #include "dcn21_resource.h" #include "vm_helper.h" #include "dcn20/dcn20_vmid.h" @@ -329,6 +330,25 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN21(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +static const struct dcn_dio_shift dio_shift = { 0 }; + +static const struct dcn_dio_mask dio_mask = { 0 }; + +static struct dio *dcn21_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} #define vmid_regs(id)\ [id] = {\ @@ -677,6 +697,12 @@ static void dcn21_resource_destruct(struct dcn21_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn20_dpp_destroy(&pool->base.dpps[i]); @@ -1662,6 +1688,14 @@ static bool dcn21_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn21_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn21_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 5742effef7ae..4a864689c44f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -60,6 +60,7 @@ #include "dml/display_mode_vba.h" #include "dcn30/dcn30_dccg.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" #include "dce/dce_panel_cntl.h" @@ -886,6 +887,33 @@ static struct hubbub *dcn30_hubbub_create(struct dc_context *ctx) return &hubbub3->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn30_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn30_timing_generator_create( struct dc_context *ctx, uint32_t instance) @@ -1096,6 +1124,12 @@ static void dcn30_resource_destruct(struct dcn30_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn30_dpp_destroy(&pool->base.dpps[i]); @@ -2468,6 +2502,14 @@ static bool dcn30_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn30_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn30_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c index 9773896e0801..a74b150cbe9c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c @@ -59,6 +59,7 @@ #include "dml/display_mode_vba.h" #include "dcn301/dcn301_dccg.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "dcn30/dcn30_dio_stream_encoder.h" #include "dcn301/dcn301_dio_link_encoder.h" #include "dcn301/dcn301_panel_cntl.h" @@ -843,6 +844,33 @@ static struct hubbub *dcn301_hubbub_create(struct dc_context *ctx) return &hubbub3->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn301_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn301_timing_generator_create( struct dc_context *ctx, uint32_t instance) { @@ -1067,6 +1095,12 @@ static void dcn301_destruct(struct dcn301_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn301_dpp_destroy(&pool->base.dpps[i]); @@ -1584,6 +1618,14 @@ static bool dcn301_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn301_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + j = 0; /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c index d9f12a6f225f..539c5aa6bffa 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c @@ -46,6 +46,7 @@ #include "dml/dcn30/dcn30_fpu.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" @@ -253,6 +254,33 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn302_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn302_hubbub_create(struct dc_context *ctx) { int i; @@ -1023,6 +1051,11 @@ static void dcn302_resource_destruct(struct resource_pool *pool) pool->hubbub = NULL; } + if (pool->dio != NULL) { + kfree(TO_DCN10_DIO(pool->dio)); + pool->dio = NULL; + } + for (i = 0; i < pool->pipe_count; i++) { if (pool->dpps[i] != NULL) { kfree(TO_DCN20_DPP(pool->dpps[i])); @@ -1374,6 +1407,14 @@ static bool dcn302_resource_construct( goto create_fail; } + /* DIO */ + pool->dio = dcn302_dio_create(ctx); + if (pool->dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->pipe_count; i++) { pool->hubps[i] = dcn302_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c index f0c75db81b2c..529eccb4ed3b 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c @@ -46,6 +46,7 @@ #include "dml/dcn30/dcn30_fpu.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" @@ -249,6 +250,33 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn303_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn303_hubbub_create(struct dc_context *ctx) { int i; @@ -967,6 +995,11 @@ static void dcn303_resource_destruct(struct resource_pool *pool) pool->hubbub = NULL; } + if (pool->dio != NULL) { + kfree(TO_DCN10_DIO(pool->dio)); + pool->dio = NULL; + } + for (i = 0; i < pool->pipe_count; i++) { if (pool->dpps[i] != NULL) { kfree(TO_DCN20_DPP(pool->dpps[i])); @@ -1306,6 +1339,14 @@ static bool dcn303_resource_construct( goto create_fail; } + /* DIO */ + pool->dio = dcn303_dio_create(ctx); + if (pool->dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->pipe_count; i++) { pool->hubps[i] = dcn303_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index afcc4dff6abc..ee4bc2c2e73a 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -64,6 +64,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -810,6 +811,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1021,6 +1037,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn31_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1397,6 +1425,10 @@ static void dcn31_resource_destruct(struct dcn31_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -2065,6 +2097,14 @@ static bool dcn31_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn31_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c index 654b4e97807e..5acc545bbe7f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c @@ -66,6 +66,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -822,6 +823,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn314 = { .num_timing_generator = 4, .num_opp = 4, @@ -1079,6 +1095,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn314_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1456,6 +1484,10 @@ static void dcn314_resource_destruct(struct dcn314_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1992,6 +2024,14 @@ static bool dcn314_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn314_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index f424fd4d5a45..2ca673114841 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -63,6 +63,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -809,6 +810,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1020,6 +1036,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn315_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1398,6 +1426,10 @@ static void dcn315_resource_destruct(struct dcn315_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -2015,6 +2047,14 @@ static bool dcn315_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn315_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c index e0dc8aaaaaa1..2242df112a3f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c @@ -63,6 +63,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -804,6 +805,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1013,6 +1029,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn316_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1393,6 +1421,10 @@ static void dcn316_resource_destruct(struct dcn316_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1891,6 +1923,14 @@ static bool dcn316_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn316_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index 3c0d046ab747..82f81b586986 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -66,6 +66,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" @@ -643,6 +644,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn32 = { .num_timing_generator = 4, .num_opp = 4, @@ -833,6 +847,22 @@ static struct clock_source *dcn32_clock_source_create( return NULL; } +static struct dio *dcn32_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn32_hubbub_create(struct dc_context *ctx) { int i; @@ -1494,6 +1524,11 @@ static void dcn32_resource_destruct(struct dcn32_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + if (pool->base.oem_device != NULL) { struct dc *dc = pool->base.oem_device->ctx->dc; @@ -2374,6 +2409,14 @@ static bool dcn32_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn32_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs, TGs, ABMs */ for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index b8ae6e8397ef..c8c81870d50e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -69,6 +69,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" @@ -639,6 +640,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn321 = { .num_timing_generator = 4, .num_opp = 4, @@ -827,6 +841,22 @@ static struct clock_source *dcn321_clock_source_create( return NULL; } +static struct dio *dcn321_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn321_hubbub_create(struct dc_context *ctx) { int i; @@ -1474,6 +1504,11 @@ static void dcn321_resource_destruct(struct dcn321_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + if (pool->base.oem_device != NULL) { struct dc *dc = pool->base.oem_device->ctx->dc; @@ -1873,6 +1908,14 @@ static bool dcn321_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn321_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs, TGs, ABMs */ for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 825ecaf9c580..2a1b0b152501 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -71,6 +71,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -664,6 +665,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn35 = { .num_timing_generator = 4, .num_opp = 4, @@ -973,6 +987,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn35_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1563,6 +1593,11 @@ static void dcn35_resource_destruct(struct dcn35_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -2045,6 +2080,14 @@ static bool dcn35_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn35_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c index 00286cba5742..bfd1016aa780 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c @@ -50,6 +50,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -644,6 +645,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn351 = { .num_timing_generator = 4, .num_opp = 4, @@ -953,6 +967,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn351_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1543,6 +1573,11 @@ static void dcn351_resource_destruct(struct dcn351_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -2017,6 +2052,14 @@ static bool dcn351_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn351_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c index 7c4519d57e4d..07a6675a7329 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c @@ -50,6 +50,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -651,6 +652,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn36 = { .num_timing_generator = 4, .num_opp = 4, @@ -960,6 +974,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn36_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1550,6 +1580,11 @@ static void dcn36_resource_destruct(struct dcn36_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -2015,6 +2050,14 @@ static bool dcn36_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn36_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); -- cgit v1.2.3 From 57ce498faa1e4d358bf44b5df575874c22922786 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Mon, 30 Mar 2026 08:26:03 +0530 Subject: drm/amd/display: Fix dc_is_fp_enabled name mismatch Fix incorrect function name in comment to match dc_is_fp_enabled. This function checks if FPU is currently active by reading a counter. The FPU helpers manage safe usage of FPU in the kernel by tracking when it starts and stops, avoiding misuse or crashes. Fixes: 3539437f354b ("drm/amd/display: Move FPU Guards From DML To DC - Part 1") Cc: Roman Li Cc: Alex Hung Cc: Tom Chung Cc: Dillon Varone Cc: Rafal Ostrowski Cc: Aurabindo Pillai Signed-off-by: Srinivasan Shanmugam Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index 8ba9b4f56f87..172999cc84e5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -59,7 +59,7 @@ inline void dc_assert_fp_enabled(void) } /** - * dc_assert_fp_enabled - Check if FPU protection is enabled + * dc_is_fp_enabled - Check if FPU protection is enabled * * This function tells if the code is already under FPU protection or not. A * function that works as an API for a set of FPU operations can use this -- cgit v1.2.3 From 118362a96286367b04b31cebb25c6ca3601644a4 Mon Sep 17 00:00:00 2001 From: Chenyu Chen Date: Tue, 31 Mar 2026 11:14:26 +0800 Subject: drm/edid: Parse AMD Vendor-Specific Data Block Parse the AMD VSDB v3 from CTA extension blocks and store the result in struct drm_amd_vsdb_info, a new field of drm_display_info. This includes replay mode, panel type, and luminance ranges. Signed-off-by: Chenyu Chen Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher --- drivers/gpu/drm/drm_edid.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5f9fcd7d9ce4..404208bf23a6 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -99,6 +99,29 @@ enum drm_edid_internal_quirk { }; #define MICROSOFT_IEEE_OUI 0xca125c +#define AMD_IEEE_OUI 0x00001A + +#define AMD_VSDB_V3_PAYLOAD_MIN_LEN 15 +#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 20 + +struct amd_vsdb_v3_payload { + u8 oui[3]; + u8 version; + u8 feature_caps; + u8 rsvd0[3]; + u8 cs_eotf_support; + u8 lum1_max; + u8 lum1_min; + u8 lum2_max; + u8 lum2_min; + u8 rsvd1[2]; + /* + * Bytes beyond AMD_VSDB_V3_PAYLOAD_MIN_LEN are optional; a + * monitor may provide a payload as short as 15 bytes. Always + * check cea_db_payload_len() before accessing extra[]. + */ + u8 extra[AMD_VSDB_V3_PAYLOAD_MAX_LEN - AMD_VSDB_V3_PAYLOAD_MIN_LEN]; +} __packed; struct detailed_mode_closure { struct drm_connector *connector; @@ -5205,6 +5228,13 @@ static bool cea_db_is_microsoft_vsdb(const struct cea_db *db) cea_db_payload_len(db) == 21; } +static bool cea_db_is_amd_vsdb(const struct cea_db *db) +{ + return cea_db_is_vendor(db, AMD_IEEE_OUI) && + cea_db_payload_len(db) >= AMD_VSDB_V3_PAYLOAD_MIN_LEN && + cea_db_payload_len(db) <= AMD_VSDB_V3_PAYLOAD_MAX_LEN; +} + static bool cea_db_is_vcdb(const struct cea_db *db) { return cea_db_is_extended_tag(db, CTA_EXT_DB_VIDEO_CAP) && @@ -6401,6 +6431,45 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector, connector->base.id, connector->name, version, db[5]); } +static void drm_parse_amd_vsdb(struct drm_connector *connector, + const struct cea_db *db) +{ + struct drm_display_info *info = &connector->display_info; + const u8 *data = cea_db_data(db); + const struct amd_vsdb_v3_payload *p; + + p = (const struct amd_vsdb_v3_payload *)data; + + if (p->version != 0x03) { + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Unsupported AMD VSDB version %u\n", + connector->base.id, connector->name, p->version); + return; + } + + info->amd_vsdb.version = p->version; + info->amd_vsdb.replay_mode = p->feature_caps & 0x40; + info->amd_vsdb.panel_type = (p->cs_eotf_support & 0xC0) >> 6; + info->amd_vsdb.luminance_range1.max_luminance = p->lum1_max; + info->amd_vsdb.luminance_range1.min_luminance = p->lum1_min; + info->amd_vsdb.luminance_range2.max_luminance = p->lum2_max; + info->amd_vsdb.luminance_range2.min_luminance = p->lum2_min; + + /* + * The AMD VSDB v3 payload length is variable (15..20 bytes). + * All fields through p->rsvd1 (byte 14) are always present, + * but p->extra[] (bytes 15+) may not be. Any future access to + * extra[] must be guarded with a runtime length check to avoid + * out-of-bounds reads on shorter (but spec-valid) payloads. + * For example: + * + * int len = cea_db_payload_len(db); + * + * if (len > AMD_VSDB_V3_PAYLOAD_MIN_LEN) + * info->amd_vsdb.foo = p->extra[0]; + */ +} + static void drm_parse_cea_ext(struct drm_connector *connector, const struct drm_edid *drm_edid) { @@ -6449,6 +6518,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, drm_parse_hdmi_forum_scds(connector, data); else if (cea_db_is_microsoft_vsdb(db)) drm_parse_microsoft_vsdb(connector, data); + else if (cea_db_is_amd_vsdb(db)) + drm_parse_amd_vsdb(connector, db); else if (cea_db_is_y420cmdb(db)) parse_cta_y420cmdb(connector, db, &y420cmdb_map); else if (cea_db_is_y420vdb(db)) @@ -6641,6 +6712,7 @@ static void drm_reset_display_info(struct drm_connector *connector) info->quirks = 0; info->source_physical_address = CEC_PHYS_ADDR_INVALID; + memset(&info->amd_vsdb, 0, sizeof(info->amd_vsdb)); } static void update_displayid_info(struct drm_connector *connector, -- cgit v1.2.3 From bf3fc94cd72abe6fc6cd88691fa98f817f4cd6db Mon Sep 17 00:00:00 2001 From: Chenyu Chen Date: Tue, 31 Mar 2026 11:15:02 +0800 Subject: drm/amd/display: Use drm_display_info for AMD VSDB data Replace the raw EDID byte-walking in parse_amd_vsdb() with a read from connector->display_info.amd_vsdb, now populated by drm_edid. Factor out panel type determination into dm_set_panel_type(), which checks VSDB panel_type, DPCD ext caps, and a luminance heuristic as fallbacks. Signed-off-by: Chenyu Chen Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 120 ++++++++++++---------- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 14 --- 2 files changed, 68 insertions(+), 66 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 21635e80349a..824ee93c9911 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3833,6 +3833,66 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = { .atomic_commit_setup = amdgpu_dm_atomic_setup_commit, }; +#define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C + +static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector) +{ + struct drm_connector *connector = &aconnector->base; + struct drm_display_info *display_info = &connector->display_info; + struct dc_link *link = aconnector->dc_link; + struct amdgpu_device *adev; + + adev = drm_to_adev(connector->dev); + + link->panel_type = PANEL_TYPE_NONE; + + switch (display_info->amd_vsdb.panel_type) { + case AMD_VSDB_PANEL_TYPE_OLED: + link->panel_type = PANEL_TYPE_OLED; + break; + case AMD_VSDB_PANEL_TYPE_MINILED: + link->panel_type = PANEL_TYPE_MINILED; + break; + } + + /* If VSDB didn't determine panel type, check DPCD ext caps */ + if (link->panel_type == PANEL_TYPE_NONE) { + if (link->dpcd_sink_ext_caps.bits.miniled == 1) + link->panel_type = PANEL_TYPE_MINILED; + if (link->dpcd_sink_ext_caps.bits.oled == 1) + link->panel_type = PANEL_TYPE_OLED; + } + + /* + * TODO: get panel type from DID2 that has device technology field + * to specify if it's OLED or not. But we need to wait for DID2 + * support in DC and EDID parser to be able to use it here. + */ + + if (link->panel_type == PANEL_TYPE_NONE) { + struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb; + u32 lum1_max = vsdb->luminance_range1.max_luminance; + u32 lum2_max = vsdb->luminance_range2.max_luminance; + + if (vsdb->version && link->local_sink && + link->local_sink->edid_caps.manufacturer_id == + DDC_MANUFACTURERNAME_SAMSUNG && + lum1_max >= ((lum2_max * 3) / 2)) + link->panel_type = PANEL_TYPE_MINILED; + } + + if (link->panel_type == PANEL_TYPE_OLED) + drm_object_property_set_value(&connector->base, + adev_to_drm(adev)->mode_config.panel_type_property, + DRM_MODE_PANEL_TYPE_OLED); + else + drm_object_property_set_value(&connector->base, + adev_to_drm(adev)->mode_config.panel_type_property, + DRM_MODE_PANEL_TYPE_UNKNOWN); + + drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type); +} + static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) { const struct drm_panel_backlight_quirk *panel_backlight_quirk; @@ -3854,10 +3914,6 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; caps->aux_support = false; - drm_object_property_set_value(&conn_base->base, - adev_to_drm(adev)->mode_config.panel_type_property, - caps->ext_caps->bits.oled ? DRM_MODE_PANEL_TYPE_OLED : DRM_MODE_PANEL_TYPE_UNKNOWN); - if (caps->ext_caps->bits.oled == 1 /* * || @@ -4031,6 +4087,7 @@ void amdgpu_dm_update_connector_after_detect( amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid); update_connector_ext_caps(aconnector); + dm_set_panel_type(aconnector); } else { hdmi_cec_unset_edid(aconnector); drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); @@ -13155,56 +13212,15 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector, } } -static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, - const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) +static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector, + struct amdgpu_hdmi_vsdb_info *vsdb_info) { - u8 *edid_ext = NULL; - int i; - int j = 0; - int total_ext_block_len; - - if (edid == NULL || edid->extensions == 0) - return -ENODEV; - - /* Find DisplayID extension */ - for (i = 0; i < edid->extensions; i++) { - edid_ext = (void *)(edid + (i + 1)); - if (edid_ext[0] == DISPLAYID_EXT) - break; - } - - total_ext_block_len = EDID_LENGTH * edid->extensions; - while (j < total_ext_block_len - sizeof(struct amd_vsdb_block)) { - struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j]; - unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]); - - if (ieeeId == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID && - amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) { - u8 panel_type; - vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false; - vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3; - drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); - panel_type = (amd_vsdb->color_space_eotf_support & AMD_VDSB_VERSION_3_PANEL_TYPE_MASK) >> AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT; - switch (panel_type) { - case AMD_VSDB_PANEL_TYPE_OLED: - aconnector->dc_link->panel_type = PANEL_TYPE_OLED; - break; - case AMD_VSDB_PANEL_TYPE_MINILED: - aconnector->dc_link->panel_type = PANEL_TYPE_MINILED; - break; - default: - aconnector->dc_link->panel_type = PANEL_TYPE_NONE; - break; - } - drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", - aconnector->dc_link->panel_type); + struct drm_connector *connector = &aconnector->base; - return true; - } - j++; - } + vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode; + vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version; - return false; + return connector->display_info.amd_vsdb.version != 0; } static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, @@ -13307,7 +13323,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, freesync_capable = true; } - parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); + get_amd_vsdb(amdgpu_dm_connector, &vsdb_info); if (vsdb_info.replay_mode) { amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index d1a14e0c12bd..63ce1f52b697 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -53,12 +53,6 @@ #define AMDGPU_DMUB_NOTIFICATION_MAX 8 -#define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x00001A -#define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40 -#define AMD_VDSB_VERSION_3_PANEL_TYPE_MASK 0xC0 -#define AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT 6 -#define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3 - enum amd_vsdb_panel_type { AMD_VSDB_PANEL_TYPE_DEFAULT = 0, AMD_VSDB_PANEL_TYPE_MINILED, @@ -97,14 +91,6 @@ struct dc_plane_state; struct dmub_notification; struct dmub_cmd_fused_request; -struct amd_vsdb_block { - unsigned char ieee_id[3]; - unsigned char version; - unsigned char feature_caps; - unsigned char reserved[3]; - unsigned char color_space_eotf_support; -}; - struct common_irq_params { struct amdgpu_device *adev; enum dc_irq_source irq_src; -- cgit v1.2.3 From f2483b3f39c8e20d2de0cc16e512a1b2aa14baf9 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Mon, 30 Mar 2026 08:42:29 +0530 Subject: drm/amd/display: Fix parameter mismatch in panel self-refresh helper Align parameter names with function arguments. The function controls panel self-refresh enable/disable based on vblank and VRR state. Fixes the below with gcc W=1: ../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'dm' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' ../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'acrtc' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' ../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'stream' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' ../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'dm' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' ../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'acrtc' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' ../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'stream' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' Fixes: 754003486c3c ("drm/amd/display: Add Idle state manager(ISM)") Cc: Ray Wu Cc: Leo Li Cc: Roman Li Cc: Alex Hung Cc: Tom Chung Cc: Aurabindo Pillai Cc: Mario Limonciello (AMD) Signed-off-by: Srinivasan Shanmugam Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index c3c588294665..5d2715f78314 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -101,23 +101,22 @@ bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state) /** * amdgpu_dm_crtc_set_panel_sr_feature() - Manage panel self-refresh features. - * - * @vblank_work: is a pointer to a struct vblank_control_work object. - * @vblank_enabled: indicates whether the DRM vblank counter is currently - * enabled (true) or disabled (false). - * @allow_sr_entry: represents whether entry into the self-refresh mode is - * allowed (true) or not allowed (false). + * @dm: amdgpu display manager instance. + * @acrtc: CRTC whose panel self-refresh state is being updated. + * @stream: DC stream associated with @acrtc. + * @vblank_enabled: Whether the DRM vblank counter is currently enabled. + * @allow_sr_entry: Whether entry into self-refresh mode is allowed. * * The DRM vblank counter enable/disable action is used as the trigger to enable * or disable various panel self-refresh features: * * Panel Replay and PSR SU * - Enable when: - * - VRR is disabled - * - vblank counter is disabled - * - entry is allowed: usermode demonstrates an adequate number of fast - * commits) - * - CRC capture window isn't active + * - VRR is disabled + * - vblank counter is disabled + * - entry is allowed: usermode demonstrates an adequate number of fast + * commits + * - CRC capture window isn't active * - Keep enabled even when vblank counter gets enabled * * PSR1 -- cgit v1.2.3 From 4e8197426f8f10a9afc9a50fc2970b733ed22d85 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Sun, 29 Mar 2026 15:26:42 +0530 Subject: drm/amd/display: Fix missing parameter details in amdgpu_dm_ism Update comments in dm_ism_get_idle_allow_delay() and dm_ism_insert_record() to better reflect their behavior and inputs. dm_ism_get_idle_allow_delay() computes the delay before allowing idle optimizations based on history and stream timing. dm_ism_insert_record() stores idle duration records in the circular history buffer. These functions explain what they do, but they do not explain what their inputs mean. Fixes the below with gcc W=1: ../display/amdgpu_dm/amdgpu_dm_ism.c:44 function parameter 'current_state' not described in 'dm_ism_next_state' ../display/amdgpu_dm/amdgpu_dm_ism.c:44 function parameter 'event' not described in 'dm_ism_next_state' ../display/amdgpu_dm/amdgpu_dm_ism.c:44 function parameter 'next_state' not described in 'dm_ism_next_state' ../display/amdgpu_dm/amdgpu_dm_ism.c:153 function parameter 'ism' not described in 'dm_ism_get_idle_allow_delay' ../display/amdgpu_dm/amdgpu_dm_ism.c:153 function parameter 'stream' not described in 'dm_ism_get_idle_allow_delay' ../display/amdgpu_dm/amdgpu_dm_ism.c:216 function parameter 'ism' not described in 'dm_ism_insert_record' ../display/amdgpu_dm/amdgpu_dm_ism.c:44 function parameter 'current_state' not described in 'dm_ism_next_state' ../display/amdgpu_dm/amdgpu_dm_ism.c:44 function parameter 'event' not described in 'dm_ism_next_state' ../display/amdgpu_dm/amdgpu_dm_ism.c:44 function parameter 'next_state' not described in 'dm_ism_next_state' ../display/amdgpu_dm/amdgpu_dm_ism.c:153 function parameter 'ism' not described in 'dm_ism_get_idle_allow_delay' ../display/amdgpu_dm/amdgpu_dm_ism.c:153 function parameter 'stream' not described in 'dm_ism_get_idle_allow_delay' ../display/amdgpu_dm/amdgpu_dm_ism.c:216 function parameter 'ism' not described in 'dm_ism_insert_record' Fixes: 754003486c3c ("drm/amd/display: Add Idle state manager(ISM)") Cc: Ray Wu Cc: Leo Li Cc: Roman Li Cc: Alex Hung Cc: Tom Chung Cc: Aurabindo Pillai Cc: Mario Limonciello (AMD) Signed-off-by: Srinivasan Shanmugam Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c index 65a5cfe1e106..a3ccb6fdc372 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c @@ -35,6 +35,9 @@ /** * dm_ism_next_state - Get next state based on current state and event + * @current_state: current ISM state + * @event: event being processed + * @next_state: place to store the next state * * This function defines the idle state management FSM. Invalid transitions * are ignored and will not progress the FSM. @@ -148,6 +151,11 @@ static uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism, /** * dm_ism_get_idle_allow_delay - Calculate hysteresis-based idle allow delay + * @ism: ISM instance containing configuration, history, and current state + * @stream: display stream used to derive frame timing values for delay + * + * Calculates the delay before allowing idle optimizations based on recent + * idle history and the current stream timing. */ static uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism, const struct dc_stream_state *stream) @@ -212,6 +220,7 @@ static uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism, /** * dm_ism_insert_record - Insert a record into the circular history buffer + * @ism: ISM instance */ static void dm_ism_insert_record(struct amdgpu_dm_ism *ism) { -- cgit v1.2.3 From 66085e206431ef88ce36f53c1f53d570790ccc9e Mon Sep 17 00:00:00 2001 From: Benjamin Cheng Date: Wed, 25 Mar 2026 08:39:19 -0400 Subject: drm/amdgpu: Add bounds checking to ib_{get,set}_value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uvd/vce/vcn code accesses the IB at predefined offsets without checking that the IB is large enough. Check the bounds here. The caller is responsible for making sure it can handle arbitrary return values. Also make the idx a uint32_t to prevent overflows causing the condition to fail. Signed-off-by: Benjamin Cheng Reviewed-by: Christian König Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index ce5af137ee40..715c9e43e13a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -559,15 +559,18 @@ void amdgpu_debugfs_ring_init(struct amdgpu_device *adev, int amdgpu_ring_init_mqd(struct amdgpu_ring *ring); -static inline u32 amdgpu_ib_get_value(struct amdgpu_ib *ib, int idx) +static inline u32 amdgpu_ib_get_value(struct amdgpu_ib *ib, uint32_t idx) { - return ib->ptr[idx]; + if (idx < ib->length_dw) + return ib->ptr[idx]; + return 0; } -static inline void amdgpu_ib_set_value(struct amdgpu_ib *ib, int idx, +static inline void amdgpu_ib_set_value(struct amdgpu_ib *ib, uint32_t idx, uint32_t value) { - ib->ptr[idx] = value; + if (idx < ib->length_dw) + ib->ptr[idx] = value; } int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm, -- cgit v1.2.3 From de2a02cc28d6d5d37db07d00a9a684c754a5fd74 Mon Sep 17 00:00:00 2001 From: Benjamin Cheng Date: Mon, 30 Mar 2026 15:01:27 -0400 Subject: drm/amdgpu/vce: Prevent partial address patches In the case that only one of lo/hi is valid, the patching could result in a bad address written to in FW. Signed-off-by: Benjamin Cheng Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index eb4a15db2ef2..efdebd9c0a1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -680,6 +680,9 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib, uint64_t addr; int r; + if (lo >= ib->length_dw || hi >= ib->length_dw) + return -EINVAL; + if (index == 0xffffffff) index = 0; -- cgit v1.2.3 From b193019860d61e92da395eae2011f2f6716b182f Mon Sep 17 00:00:00 2001 From: Benjamin Cheng Date: Tue, 24 Mar 2026 16:25:56 -0400 Subject: drm/amdgpu/vcn3: Prevent OOB reads when parsing dec msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check bounds against the end of the BO whenever we access the msg. Signed-off-by: Benjamin Cheng Reviewed-by: Christian König Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 02d5c5af65f2..6fb4fcdbba4f 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -1909,7 +1909,7 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, struct ttm_operation_ctx ctx = { false, false }; struct amdgpu_device *adev = p->adev; struct amdgpu_bo_va_mapping *map; - uint32_t *msg, num_buffers; + uint32_t *msg, num_buffers, len_dw; struct amdgpu_bo *bo; uint64_t start, end; unsigned int i; @@ -1930,6 +1930,11 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, return -EINVAL; } + if (end - addr < 16) { + DRM_ERROR("VCN messages must be at least 4 DWORDs!\n"); + return -EINVAL; + } + bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; amdgpu_bo_placement_from_domain(bo, bo->allowed_domains); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); @@ -1946,8 +1951,8 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, msg = ptr + addr - start; - /* Check length */ if (msg[1] > end - addr) { + DRM_ERROR("VCN message header does not fit in BO!\n"); r = -EINVAL; goto out; } @@ -1955,7 +1960,16 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, if (msg[3] != RDECODE_MSG_CREATE) goto out; + len_dw = msg[1] / 4; num_buffers = msg[2]; + + /* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */ + if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) { + DRM_ERROR("VCN message has too many buffers!\n"); + r = -EINVAL; + goto out; + } + for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { uint32_t offset, size, *create; @@ -1965,14 +1979,15 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, offset = msg[1]; size = msg[2]; - if (offset + size > end) { + if (size < 4 || offset + size > end - addr) { + DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); r = -EINVAL; goto out; } create = ptr + addr + offset - start; - /* H246, HEVC and VP9 can run on any instance */ + /* H264, HEVC and VP9 can run on any instance */ if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11) continue; -- cgit v1.2.3 From 0a78f2bac1424deb7c9d5e09c6b8e849d8e8b648 Mon Sep 17 00:00:00 2001 From: Benjamin Cheng Date: Wed, 25 Mar 2026 09:09:27 -0400 Subject: drm/amdgpu/vcn4: Prevent OOB reads when parsing dec msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check bounds against the end of the BO whenever we access the msg. Signed-off-by: Benjamin Cheng Reviewed-by: Christian König Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index d17219be50f3..1a1cdc14841a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -1826,7 +1826,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, struct ttm_operation_ctx ctx = { false, false }; struct amdgpu_device *adev = p->adev; struct amdgpu_bo_va_mapping *map; - uint32_t *msg, num_buffers; + uint32_t *msg, num_buffers, len_dw; struct amdgpu_bo *bo; uint64_t start, end; unsigned int i; @@ -1847,6 +1847,11 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, return -EINVAL; } + if (end - addr < 16) { + DRM_ERROR("VCN messages must be at least 4 DWORDs!\n"); + return -EINVAL; + } + bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; amdgpu_bo_placement_from_domain(bo, bo->allowed_domains); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); @@ -1863,8 +1868,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, msg = ptr + addr - start; - /* Check length */ if (msg[1] > end - addr) { + DRM_ERROR("VCN message header does not fit in BO!\n"); r = -EINVAL; goto out; } @@ -1872,7 +1877,16 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, if (msg[3] != RDECODE_MSG_CREATE) goto out; + len_dw = msg[1] / 4; num_buffers = msg[2]; + + /* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */ + if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) { + DRM_ERROR("VCN message has too many buffers!\n"); + r = -EINVAL; + goto out; + } + for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { uint32_t offset, size, *create; @@ -1882,7 +1896,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, offset = msg[1]; size = msg[2]; - if (offset + size > end) { + if (size < 4 || offset + size > end - addr) { + DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); r = -EINVAL; goto out; } -- cgit v1.2.3 From 2444eb0ec8283f4a3845eb7febad378476e1ba3c Mon Sep 17 00:00:00 2001 From: Benjamin Cheng Date: Tue, 24 Mar 2026 16:42:05 -0400 Subject: drm/amdgpu/vcn4: Prevent OOB reads when parsing IB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite the IB parsing to use amdgpu_ib_get_value() which handles the bounds checks. Signed-off-by: Benjamin Cheng Acked-by: Christian König Reviewed-by: Ruijing Dong Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 1a1cdc14841a..5dec92691f73 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -1928,9 +1928,10 @@ out: static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start) { int i; + uint32_t len; - for (i = start; i < ib->length_dw && ib->ptr[i] >= 8; i += ib->ptr[i] / 4) { - if (ib->ptr[i + 1] == id) + for (i = start; (len = amdgpu_ib_get_value(ib, i)) >= 8; i += len / 4) { + if (amdgpu_ib_get_value(ib, i + 1) == id) return i; } return -1; @@ -1941,8 +1942,6 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib) { struct amdgpu_ring *ring = amdgpu_job_ring(job); - struct amdgpu_vcn_decode_buffer *decode_buffer; - uint64_t addr; uint32_t val; int idx = 0, sidx; @@ -1953,20 +1952,22 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) { val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */ if (val == RADEON_VCN_ENGINE_TYPE_DECODE) { - decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6]; + uint32_t valid_buf_flag = amdgpu_ib_get_value(ib, idx + 6); + uint64_t msg_buffer_addr; - if (!(decode_buffer->valid_buf_flag & 0x1)) + if (!(valid_buf_flag & 0x1)) return 0; - addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 | - decode_buffer->msg_buffer_address_lo; - return vcn_v4_0_dec_msg(p, job, addr); + msg_buffer_addr = ((u64)amdgpu_ib_get_value(ib, idx + 7)) << 32 | + amdgpu_ib_get_value(ib, idx + 8); + return vcn_v4_0_dec_msg(p, job, msg_buffer_addr); } else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) { sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx); - if (sidx >= 0 && ib->ptr[sidx + 2] == RENCODE_ENCODE_STANDARD_AV1) + if (sidx >= 0 && + amdgpu_ib_get_value(ib, sidx + 2) == RENCODE_ENCODE_STANDARD_AV1) return vcn_v4_0_limit_sched(p, job); } - idx += ib->ptr[idx] / 4; + idx += amdgpu_ib_get_value(ib, idx) / 4; } return 0; } -- cgit v1.2.3 From 8d45d88e0b3d17c9f847cef8171c95c19d2cbdf5 Mon Sep 17 00:00:00 2001 From: Ce Sun Date: Mon, 30 Mar 2026 14:22:03 +0800 Subject: drm/amd/ras: enable uniras via IP version check enable uniras via IP version check Signed-off-by: Ce Sun Reviewed-by: YiPeng Chai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c index d213eea71cff..ad8862d43263 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c @@ -290,13 +290,10 @@ static int amdgpu_ras_mgr_sw_init(struct amdgpu_ip_block *ip_block) /* Disabled by default */ con->uniras_enabled = false; - /* Enabled only in debug mode */ - if (adev->debug_enable_ras_aca) { + if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) || + adev->debug_enable_ras_aca) con->uniras_enabled = true; - RAS_DEV_INFO(adev, "Debug amdgpu uniras!"); - } - - if (!con->uniras_enabled) + else return 0; ras_mgr = kzalloc_obj(*ras_mgr); -- cgit v1.2.3 From c9042a4dd6ac311281fc2d95d0d9f8e3278608c5 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 16:36:16 +0530 Subject: drm/amdgpu: Add reserved region ids Add reserved regions and helper functions to memory manager. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 58 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 31 ++++++++++++++++++ 2 files changed, 89 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index afaaab6496de..8f0b13a39b61 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1671,6 +1671,64 @@ static struct ttm_device_funcs amdgpu_bo_driver = { .access_memory = &amdgpu_ttm_access_memory, }; +void amdgpu_ttm_init_vram_resv(struct amdgpu_device *adev, + enum amdgpu_resv_region_id id, + uint64_t offset, uint64_t size, + bool needs_cpu_map) +{ + struct amdgpu_vram_resv *resv; + + if (id >= AMDGPU_RESV_MAX) + return; + + resv = &adev->mman.resv_region[id]; + resv->offset = offset; + resv->size = size; + resv->needs_cpu_map = needs_cpu_map; +} + +int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, + enum amdgpu_resv_region_id id) +{ + struct amdgpu_vram_resv *resv; + int ret; + + if (id >= AMDGPU_RESV_MAX) + return -EINVAL; + + resv = &adev->mman.resv_region[id]; + if (!resv->size) + return 0; + + ret = amdgpu_bo_create_kernel_at(adev, resv->offset, resv->size, + &resv->bo, + resv->needs_cpu_map ? &resv->cpu_ptr : NULL); + if (ret) { + dev_dbg(adev->dev, "reserve vram failed: id=%d offset=0x%llx size=0x%llx ret=%d\n", + id, resv->offset, resv->size, ret); + memset(resv, 0, sizeof(*resv)); + } + + return ret; +} + +void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev, + enum amdgpu_resv_region_id id) +{ + struct amdgpu_vram_resv *resv; + + if (id >= AMDGPU_RESV_MAX) + return; + + resv = &adev->mman.resv_region[id]; + if (!resv->bo) + return; + + amdgpu_bo_free_kernel(&resv->bo, NULL, + resv->needs_cpu_map ? &resv->cpu_ptr : NULL); + memset(resv, 0, sizeof(*resv)); +} + /* * Firmware Reservation functions */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 3b1973611446..7c49fe56a1df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -59,6 +59,26 @@ struct amdgpu_ttm_buffer_entity { u64 gart_window_offs[2]; }; +enum amdgpu_resv_region_id { + AMDGPU_RESV_STOLEN_VGA, + AMDGPU_RESV_STOLEN_EXTENDED, + AMDGPU_RESV_STOLEN_RESERVED, + AMDGPU_RESV_FW, + AMDGPU_RESV_FW_EXTEND, + AMDGPU_RESV_FW_VRAM_USAGE, + AMDGPU_RESV_DRV_VRAM_USAGE, + AMDGPU_RESV_MEM_TRAIN, + AMDGPU_RESV_MAX +}; + +struct amdgpu_vram_resv { + uint64_t offset; + uint64_t size; + struct amdgpu_bo *bo; + void *cpu_ptr; + bool needs_cpu_map; +}; + struct amdgpu_mman { struct ttm_device bdev; struct ttm_pool *ttm_pools; @@ -109,6 +129,8 @@ struct amdgpu_mman { struct amdgpu_bo *drv_vram_usage_reserved_bo; void *drv_vram_usage_va; + struct amdgpu_vram_resv resv_region[AMDGPU_RESV_MAX]; + /* PAGE_SIZE'd BO for process memory r/w over SDMA. */ struct amdgpu_bo *sdma_access_bo; void *sdma_access_ptr; @@ -175,6 +197,15 @@ void amdgpu_vram_mgr_clear_reset_blocks(struct amdgpu_device *adev); bool amdgpu_res_cpu_visible(struct amdgpu_device *adev, struct ttm_resource *res); +void amdgpu_ttm_init_vram_resv(struct amdgpu_device *adev, + enum amdgpu_resv_region_id id, + uint64_t offset, uint64_t size, + bool needs_cpu_map); +int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, + enum amdgpu_resv_region_id id); +void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev, + enum amdgpu_resv_region_id id); + int amdgpu_ttm_init(struct amdgpu_device *adev); void amdgpu_ttm_fini(struct amdgpu_device *adev); void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, -- cgit v1.2.3 From 9bb16dabb09116d3308772569e850477f2d803b5 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 17:00:31 +0530 Subject: drm/amdgpu: Add stolen vga reserve-region Use reserve region helpers for initializing/reserving stolen vga region. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 8 +++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 10 ++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 2 -- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index ec74f3971732..2d7e5c137902 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -1099,10 +1099,12 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev) size = 0; if (size > AMDGPU_VBIOS_VGA_ALLOCATION) { - adev->mman.stolen_vga_size = AMDGPU_VBIOS_VGA_ALLOCATION; - adev->mman.stolen_extended_size = size - adev->mman.stolen_vga_size; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_VGA, + 0, AMDGPU_VBIOS_VGA_ALLOCATION, false); + adev->mman.stolen_extended_size = size - AMDGPU_VBIOS_VGA_ALLOCATION; } else { - adev->mman.stolen_vga_size = size; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_VGA, + 0, size, false); adev->mman.stolen_extended_size = 0; } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8f0b13a39b61..57804625702f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2206,14 +2206,12 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) * and driver. */ if (!adev->gmc.is_app_apu) { - r = amdgpu_bo_create_kernel_at(adev, 0, - adev->mman.stolen_vga_size, - &adev->mman.stolen_vga_memory, - NULL); + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); if (r) return r; - r = amdgpu_bo_create_kernel_at(adev, adev->mman.stolen_vga_size, + r = amdgpu_bo_create_kernel_at(adev, + adev->mman.resv_region[AMDGPU_RESV_STOLEN_VGA].size, adev->mman.stolen_extended_size, &adev->mman.stolen_extended_memory, NULL); @@ -2342,7 +2340,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_ttm_training_reserve_vram_fini(adev); /* return the stolen vga memory back to VRAM */ if (!adev->gmc.is_app_apu) { - amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL); /* return the FW reserved memory back to VRAM */ amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 7c49fe56a1df..826db85d133e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -103,8 +103,6 @@ struct amdgpu_mman { struct amdgpu_gtt_mgr gtt_mgr; struct ttm_resource_manager preempt_mgr; - uint64_t stolen_vga_size; - struct amdgpu_bo *stolen_vga_memory; uint64_t stolen_extended_size; struct amdgpu_bo *stolen_extended_memory; bool keep_stolen_vga_memory; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 824ee93c9911..19d8a5fc5def 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -11199,7 +11199,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) if (!adev->in_suspend) { /* return the stolen vga memory back to VRAM */ if (!adev->mman.keep_stolen_vga_memory) - amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL); } -- cgit v1.2.3 From 941c50330ec4ab07b67abd37749da0687aadab1e Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 17:04:36 +0530 Subject: drm/amdgpu: Add extended stolen vga reserve-region Use reserve region helpers for initializing/reserving extended stolen vga region. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 +++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 9 ++------- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 2 -- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 2d7e5c137902..4d066955be85 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -1101,11 +1101,12 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev) if (size > AMDGPU_VBIOS_VGA_ALLOCATION) { amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_VGA, 0, AMDGPU_VBIOS_VGA_ALLOCATION, false); - adev->mman.stolen_extended_size = size - AMDGPU_VBIOS_VGA_ALLOCATION; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_EXTENDED, + AMDGPU_VBIOS_VGA_ALLOCATION, + size - AMDGPU_VBIOS_VGA_ALLOCATION, false); } else { amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_VGA, 0, size, false); - adev->mman.stolen_extended_size = 0; } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 57804625702f..256bf490ee15 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2210,12 +2210,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) if (r) return r; - r = amdgpu_bo_create_kernel_at(adev, - adev->mman.resv_region[AMDGPU_RESV_STOLEN_VGA].size, - adev->mman.stolen_extended_size, - &adev->mman.stolen_extended_memory, - NULL); - + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); if (r) return r; @@ -2341,7 +2336,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) /* return the stolen vga memory back to VRAM */ if (!adev->gmc.is_app_apu) { amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); - amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); /* return the FW reserved memory back to VRAM */ amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, NULL); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 826db85d133e..b62f9208eb9a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -103,8 +103,6 @@ struct amdgpu_mman { struct amdgpu_gtt_mgr gtt_mgr; struct ttm_resource_manager preempt_mgr; - uint64_t stolen_extended_size; - struct amdgpu_bo *stolen_extended_memory; bool keep_stolen_vga_memory; struct amdgpu_bo *stolen_reserved_memory; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 19d8a5fc5def..1816007f1040 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -11200,7 +11200,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) /* return the stolen vga memory back to VRAM */ if (!adev->mman.keep_stolen_vga_memory) amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); - amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); } /* -- cgit v1.2.3 From 272a9c8f6f711c283f18aa954e54ede7ed32bdd8 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 17:08:45 +0530 Subject: drm/amdgpu: Add stolen_reserved reserve-region Use reserve region helpers for initializing/reserving stolen_reserved region. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 7 ++----- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 10 ++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 4 ---- 3 files changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 4d066955be85..c3b83d9f110e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -1041,9 +1041,6 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev) * Some ASICs need to reserve a region of video memory to avoid access * from driver */ - adev->mman.stolen_reserved_offset = 0; - adev->mman.stolen_reserved_size = 0; - /* * TODO: * Currently there is a bug where some memory client outside @@ -1060,8 +1057,8 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev) */ #ifdef CONFIG_X86 if (amdgpu_sriov_vf(adev) && hypervisor_is_type(X86_HYPER_MS_HYPERV)) { - adev->mman.stolen_reserved_offset = 0x500000; - adev->mman.stolen_reserved_size = 0x200000; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_RESERVED, + 0x500000, 0x200000, false); } #endif break; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 256bf490ee15..30e2478cf474 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2214,11 +2214,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) if (r) return r; - r = amdgpu_bo_create_kernel_at(adev, - adev->mman.stolen_reserved_offset, - adev->mman.stolen_reserved_size, - &adev->mman.stolen_reserved_memory, - NULL); + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED); if (r) return r; } else { @@ -2342,9 +2338,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) NULL); amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL, NULL); - if (adev->mman.stolen_reserved_size) - amdgpu_bo_free_kernel(&adev->mman.stolen_reserved_memory, - NULL, NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED); } amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL, &adev->mman.sdma_access_ptr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index b62f9208eb9a..63e8a7fe441d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -105,10 +105,6 @@ struct amdgpu_mman { bool keep_stolen_vga_memory; - struct amdgpu_bo *stolen_reserved_memory; - uint64_t stolen_reserved_offset; - uint64_t stolen_reserved_size; - /* fw reserved memory */ struct amdgpu_bo *fw_reserved_memory; struct amdgpu_bo *fw_reserved_memory_extend; -- cgit v1.2.3 From b2155aaef0eae56ff1a3583dff38e7b92e99f8ed Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 17:17:10 +0530 Subject: drm/amdgpu: Add fw_reserved reserve-region Use reserve region helpers for initializing/reserving fw_reserved region. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 7 ++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 12 +++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 1 - 4 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index d39b695cd925..ee6c4b724146 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1076,14 +1076,15 @@ int psp_update_fw_reservation(struct psp_context *psp) return 0; } - amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW); reserv_size = roundup(reserv_size, SZ_1M); - ret = amdgpu_bo_create_kernel_at(adev, reserv_addr, reserv_size, &adev->mman.fw_reserved_memory, NULL); + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW, + reserv_addr, reserv_size, false); + ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW); if (ret) { dev_err(adev->dev, "reserve fw region failed(%d)!\n", ret); - amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, NULL); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 6edcb7713299..6c644cfe6695 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -5726,7 +5726,7 @@ out: static void amdgpu_ras_critical_region_init(struct amdgpu_device *adev) { - amdgpu_ras_add_critical_region(adev, adev->mman.fw_reserved_memory); + amdgpu_ras_add_critical_region(adev, adev->mman.resv_region[AMDGPU_RESV_FW].bo); } static void amdgpu_ras_critical_region_fini(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 30e2478cf474..8758ec6f7809 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1913,13 +1913,12 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS; } - ret = amdgpu_bo_create_kernel_at( - adev, adev->gmc.real_vram_size - reserve_size, reserve_size, - &adev->mman.fw_reserved_memory, NULL); + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW, + adev->gmc.real_vram_size - reserve_size, + reserve_size, false); + ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW); if (ret) { dev_err(adev->dev, "alloc tmr failed(%d)!\n", ret); - amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, - NULL); return ret; } @@ -2334,8 +2333,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); /* return the FW reserved memory back to VRAM */ - amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, - NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW); amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL, NULL); amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 63e8a7fe441d..a03620d50838 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -106,7 +106,6 @@ struct amdgpu_mman { bool keep_stolen_vga_memory; /* fw reserved memory */ - struct amdgpu_bo *fw_reserved_memory; struct amdgpu_bo *fw_reserved_memory_extend; /* firmware VRAM reservation */ -- cgit v1.2.3 From 14a517e37a575da79681c9b5e3b39d3755cbd94d Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 17:20:11 +0530 Subject: drm/amdgpu: Add firmware extended reserve-region Use reserve region helpers for initializing/reserving extended firmware reservation area. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 6 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 3 --- 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index ee6c4b724146..f0e4d020f4c7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1090,11 +1090,11 @@ int psp_update_fw_reservation(struct psp_context *psp) reserv_size_ext = roundup(reserv_size_ext, SZ_1M); - ret = amdgpu_bo_create_kernel_at(adev, reserv_addr_ext, reserv_size_ext, - &adev->mman.fw_reserved_memory_extend, NULL); + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_EXTEND, + reserv_addr_ext, reserv_size_ext, false); + ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW_EXTEND); if (ret) { dev_err(adev->dev, "reserve extend fw region failed(%d)!\n", ret); - amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL, NULL); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8758ec6f7809..f0284846b2d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2334,8 +2334,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); /* return the FW reserved memory back to VRAM */ amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW); - amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL, - NULL); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_EXTEND); amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED); } amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index a03620d50838..29aae20abdc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -105,9 +105,6 @@ struct amdgpu_mman { bool keep_stolen_vga_memory; - /* fw reserved memory */ - struct amdgpu_bo *fw_reserved_memory_extend; - /* firmware VRAM reservation */ u64 fw_vram_usage_start_offset; u64 fw_vram_usage_size; -- cgit v1.2.3 From daaf24d1fc538fc713ffc4a84949af0d92f06fb4 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 18:32:25 +0530 Subject: drm/amdgpu: Add fw vram usage reserve-region Use reserve region helpers for initializing/reserving firmware usage region in virtualized environments. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 6 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c | 12 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 54 ++++------------------ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 6 --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 39 ++++++++-------- .../gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c | 8 ++-- 6 files changed, 41 insertions(+), 84 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 9f38b7dd1011..3698dd0330ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -1685,9 +1685,9 @@ static int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev) (uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION << ATOM_VRAM_OPERATION_FLAGS_SHIFT)) { /* Firmware request VRAM reservation for SR-IOV */ - adev->mman.fw_vram_usage_start_offset = (start_addr & - (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10; - adev->mman.fw_vram_usage_size = size << 10; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE, + (start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10, + size << 10, true); /* Use the default scratch size */ usage_bytes = 0; } else { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index cd9aa5b45e94..51e692712d3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -120,9 +120,9 @@ static int amdgpu_atomfirmware_allocate_fb_v2_1(struct amdgpu_device *adev, (u32)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION << ATOM_VRAM_OPERATION_FLAGS_SHIFT)) { /* Firmware request VRAM reservation for SR-IOV */ - adev->mman.fw_vram_usage_start_offset = (start_addr & - (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10; - adev->mman.fw_vram_usage_size = fw_size << 10; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE, + (start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10, + fw_size << 10, true); /* Use the default scratch size */ *usage_bytes = 0; } else { @@ -152,9 +152,9 @@ static int amdgpu_atomfirmware_allocate_fb_v2_2(struct amdgpu_device *adev, ((fw_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION << ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) { /* Firmware request VRAM reservation for SR-IOV */ - adev->mman.fw_vram_usage_start_offset = (fw_start_addr & - (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10; - adev->mman.fw_vram_usage_size = fw_size << 10; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE, + (fw_start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10, + fw_size << 10, true); } if (amdgpu_sriov_vf(adev) && diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index f0284846b2d3..b82ab4794a6b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1729,22 +1729,6 @@ void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev, memset(resv, 0, sizeof(*resv)); } -/* - * Firmware Reservation functions - */ -/** - * amdgpu_ttm_fw_reserve_vram_fini - free fw reserved vram - * - * @adev: amdgpu_device pointer - * - * free fw reserved vram if it has been reserved. - */ -static void amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device *adev) -{ - amdgpu_bo_free_kernel(&adev->mman.fw_vram_usage_reserved_bo, - NULL, &adev->mman.fw_vram_usage_va); -} - /* * Driver Reservation functions */ @@ -1762,31 +1746,6 @@ static void amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device *adev) &adev->mman.drv_vram_usage_va); } -/** - * amdgpu_ttm_fw_reserve_vram_init - create bo vram reservation from fw - * - * @adev: amdgpu_device pointer - * - * create bo vram reservation from fw. - */ -static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev) -{ - uint64_t vram_size = adev->gmc.visible_vram_size; - - adev->mman.fw_vram_usage_va = NULL; - adev->mman.fw_vram_usage_reserved_bo = NULL; - - if (adev->mman.fw_vram_usage_size == 0 || - adev->mman.fw_vram_usage_size > vram_size) - return 0; - - return amdgpu_bo_create_kernel_at(adev, - adev->mman.fw_vram_usage_start_offset, - adev->mman.fw_vram_usage_size, - &adev->mman.fw_vram_usage_reserved_bo, - &adev->mman.fw_vram_usage_va); -} - /** * amdgpu_ttm_drv_reserve_vram_init - create bo vram reservation from driver * @@ -2176,9 +2135,14 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) *The reserved vram for firmware must be pinned to the specified *place on the VRAM, so reserve it early. */ - r = amdgpu_ttm_fw_reserve_vram_init(adev); - if (r) - return r; + if (adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size > + adev->gmc.visible_vram_size) { + adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size = 0; + } else { + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE); + if (r) + return r; + } /* * The reserved VRAM for the driver must be pinned to a specific @@ -2341,7 +2305,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) &adev->mman.sdma_access_ptr); amdgpu_ttm_free_mmio_remap_bo(adev); - amdgpu_ttm_fw_reserve_vram_fini(adev); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE); amdgpu_ttm_drv_reserve_vram_fini(adev); if (drm_dev_enter(adev_to_drm(adev), &idx)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 29aae20abdc1..98387984e448 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -105,12 +105,6 @@ struct amdgpu_mman { bool keep_stolen_vga_memory; - /* firmware VRAM reservation */ - u64 fw_vram_usage_start_offset; - u64 fw_vram_usage_size; - struct amdgpu_bo *fw_vram_usage_reserved_bo; - void *fw_vram_usage_va; - /* driver VRAM reservation */ u64 drv_vram_usage_start_offset; u64 drv_vram_usage_size; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index dba7ea16a10d..882d8524f4dc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -437,12 +437,8 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev, struct eeprom_table_record bp; uint64_t retired_page; uint32_t bp_idx, bp_cnt; - void *vram_usage_va = NULL; - - if (adev->mman.fw_vram_usage_va) - vram_usage_va = adev->mman.fw_vram_usage_va; - else - vram_usage_va = adev->mman.drv_vram_usage_va; + void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; + void *vram_usage_va = fw_va ? fw_va : adev->mman.drv_vram_usage_va; memset(&bp, 0, sizeof(bp)); @@ -710,15 +706,16 @@ void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev) void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) { uint32_t *pfvf_data = NULL; + void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; adev->virt.fw_reserve.p_pf2vf = NULL; adev->virt.fw_reserve.p_vf2pf = NULL; adev->virt.vf2pf_update_interval_ms = 0; adev->virt.vf2pf_update_retry_cnt = 0; - if (adev->mman.fw_vram_usage_va && adev->mman.drv_vram_usage_va) { + if (fw_va && adev->mman.drv_vram_usage_va) { dev_warn(adev->dev, "Currently fw_vram and drv_vram should not have values at the same time!"); - } else if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) { + } else if (fw_va || adev->mman.drv_vram_usage_va) { /* go through this logic in ip_init and reset to init workqueue*/ amdgpu_virt_exchange_data(adev); @@ -763,31 +760,32 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev) uint64_t bp_block_offset = 0; uint32_t bp_block_size = 0; struct amd_sriov_msg_pf2vf_info *pf2vf_v2 = NULL; + void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; - if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) { - if (adev->mman.fw_vram_usage_va) { + if (fw_va || adev->mman.drv_vram_usage_va) { + if (fw_va) { if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) - (adev->mman.fw_vram_usage_va + + (fw_va + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset); adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) - (adev->mman.fw_vram_usage_va + + (fw_va + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset + (AMD_SRIOV_MSG_SIZE_KB << 10)); adev->virt.fw_reserve.ras_telemetry = - (adev->mman.fw_vram_usage_va + + (fw_va + adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].offset); } else { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); + (fw_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); + (fw_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.ras_telemetry = - (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); + (fw_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); } } else if (adev->mman.drv_vram_usage_va) { adev->virt.fw_reserve.p_pf2vf = @@ -1081,13 +1079,14 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) } /* reserved memory starts from crit region base offset with the size of 5MB */ - adev->mman.fw_vram_usage_start_offset = adev->virt.crit_regn.offset; - adev->mman.fw_vram_usage_size = adev->virt.crit_regn.size_kb << 10; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE, + adev->virt.crit_regn.offset, + adev->virt.crit_regn.size_kb << 10, true); dev_info(adev->dev, "critical region v%d requested to reserve memory start at %08llx with %llu KB.\n", init_data_hdr->version, - adev->mman.fw_vram_usage_start_offset, - adev->mman.fw_vram_usage_size >> 10); + adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].offset, + adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size >> 10); adev->virt.is_dynamic_crit_regn_enabled = true; diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c index c83357307c55..5648e4c7afa4 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c @@ -36,17 +36,17 @@ static int amdgpu_virt_ras_get_cmd_shared_mem(struct ras_core_context *ras_core, struct amdgpu_device *adev = ras_core->dev; struct amdsriov_ras_telemetry *ras_telemetry_cpu; struct amdsriov_ras_telemetry *ras_telemetry_gpu; + void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; uint64_t fw_vram_usage_start_offset = 0; uint64_t ras_telemetry_offset = 0; if (!adev->virt.fw_reserve.ras_telemetry) return -EINVAL; - if (adev->mman.fw_vram_usage_va && - adev->mman.fw_vram_usage_va <= adev->virt.fw_reserve.ras_telemetry) { - fw_vram_usage_start_offset = adev->mman.fw_vram_usage_start_offset; + if (fw_va && fw_va <= adev->virt.fw_reserve.ras_telemetry) { + fw_vram_usage_start_offset = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].offset; ras_telemetry_offset = (uintptr_t)adev->virt.fw_reserve.ras_telemetry - - (uintptr_t)adev->mman.fw_vram_usage_va; + (uintptr_t)fw_va; } else if (adev->mman.drv_vram_usage_va && adev->mman.drv_vram_usage_va <= adev->virt.fw_reserve.ras_telemetry) { fw_vram_usage_start_offset = adev->mman.drv_vram_usage_start_offset; -- cgit v1.2.3 From 4c616e8446b916d8888415c76a91b36a00f94f79 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 18:40:24 +0530 Subject: drm/amdgpu: Add host driver reserved-region Use reserve region helpers for initializing/reserving host driver reserved region in virtualization environment. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c | 6 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 55 ++++------------------ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 6 --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 19 ++++---- .../gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c | 8 ++-- 5 files changed, 27 insertions(+), 67 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index 51e692712d3b..6860a3a4d466 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -161,9 +161,9 @@ static int amdgpu_atomfirmware_allocate_fb_v2_2(struct amdgpu_device *adev, ((drv_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION << ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) { /* driver request VRAM reservation for SR-IOV */ - adev->mman.drv_vram_usage_start_offset = (drv_start_addr & - (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10; - adev->mman.drv_vram_usage_size = drv_size << 10; + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_DRV_VRAM_USAGE, + (drv_start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10, + drv_size << 10, true); } *usage_bytes = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index b82ab4794a6b..feea4bbe5c95 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1729,48 +1729,6 @@ void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev, memset(resv, 0, sizeof(*resv)); } -/* - * Driver Reservation functions - */ -/** - * amdgpu_ttm_drv_reserve_vram_fini - free drv reserved vram - * - * @adev: amdgpu_device pointer - * - * free drv reserved vram if it has been reserved. - */ -static void amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device *adev) -{ - amdgpu_bo_free_kernel(&adev->mman.drv_vram_usage_reserved_bo, - NULL, - &adev->mman.drv_vram_usage_va); -} - -/** - * amdgpu_ttm_drv_reserve_vram_init - create bo vram reservation from driver - * - * @adev: amdgpu_device pointer - * - * create bo vram reservation from drv. - */ -static int amdgpu_ttm_drv_reserve_vram_init(struct amdgpu_device *adev) -{ - u64 vram_size = adev->gmc.visible_vram_size; - - adev->mman.drv_vram_usage_va = NULL; - adev->mman.drv_vram_usage_reserved_bo = NULL; - - if (adev->mman.drv_vram_usage_size == 0 || - adev->mman.drv_vram_usage_size > vram_size) - return 0; - - return amdgpu_bo_create_kernel_at(adev, - adev->mman.drv_vram_usage_start_offset, - adev->mman.drv_vram_usage_size, - &adev->mman.drv_vram_usage_reserved_bo, - &adev->mman.drv_vram_usage_va); -} - /* * Memoy training reservation functions */ @@ -2148,9 +2106,14 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) * The reserved VRAM for the driver must be pinned to a specific * location in VRAM, so reserve it early. */ - r = amdgpu_ttm_drv_reserve_vram_init(adev); - if (r) - return r; + if (adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size > + adev->gmc.visible_vram_size) { + adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size = 0; + } else { + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE); + if (r) + return r; + } /* * only NAVI10 and later ASICs support IP discovery. @@ -2306,7 +2269,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_ttm_free_mmio_remap_bo(adev); amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE); - amdgpu_ttm_drv_reserve_vram_fini(adev); + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE); if (drm_dev_enter(adev_to_drm(adev), &idx)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 98387984e448..f2f23a42b3cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -105,12 +105,6 @@ struct amdgpu_mman { bool keep_stolen_vga_memory; - /* driver VRAM reservation */ - u64 drv_vram_usage_start_offset; - u64 drv_vram_usage_size; - struct amdgpu_bo *drv_vram_usage_reserved_bo; - void *drv_vram_usage_va; - struct amdgpu_vram_resv resv_region[AMDGPU_RESV_MAX]; /* PAGE_SIZE'd BO for process memory r/w over SDMA. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 882d8524f4dc..e8d180a412d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -438,7 +438,8 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev, uint64_t retired_page; uint32_t bp_idx, bp_cnt; void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; - void *vram_usage_va = fw_va ? fw_va : adev->mman.drv_vram_usage_va; + void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr; + void *vram_usage_va = fw_va ? fw_va : drv_va; memset(&bp, 0, sizeof(bp)); @@ -707,15 +708,16 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) { uint32_t *pfvf_data = NULL; void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; + void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr; adev->virt.fw_reserve.p_pf2vf = NULL; adev->virt.fw_reserve.p_vf2pf = NULL; adev->virt.vf2pf_update_interval_ms = 0; adev->virt.vf2pf_update_retry_cnt = 0; - if (fw_va && adev->mman.drv_vram_usage_va) { + if (fw_va && drv_va) { dev_warn(adev->dev, "Currently fw_vram and drv_vram should not have values at the same time!"); - } else if (fw_va || adev->mman.drv_vram_usage_va) { + } else if (fw_va || drv_va) { /* go through this logic in ip_init and reset to init workqueue*/ amdgpu_virt_exchange_data(adev); @@ -761,8 +763,9 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev) uint32_t bp_block_size = 0; struct amd_sriov_msg_pf2vf_info *pf2vf_v2 = NULL; void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; + void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr; - if (fw_va || adev->mman.drv_vram_usage_va) { + if (fw_va || drv_va) { if (fw_va) { if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) { adev->virt.fw_reserve.p_pf2vf = @@ -787,15 +790,15 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev) adev->virt.fw_reserve.ras_telemetry = (fw_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); } - } else if (adev->mman.drv_vram_usage_va) { + } else if (drv_va) { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) - (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); + (drv_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) - (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); + (drv_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10)); adev->virt.fw_reserve.ras_telemetry = - (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); + (drv_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10)); } amdgpu_virt_read_pf2vf_data(adev); diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c index 5648e4c7afa4..eb552d0cce4a 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c @@ -37,6 +37,7 @@ static int amdgpu_virt_ras_get_cmd_shared_mem(struct ras_core_context *ras_core, struct amdsriov_ras_telemetry *ras_telemetry_cpu; struct amdsriov_ras_telemetry *ras_telemetry_gpu; void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr; + void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr; uint64_t fw_vram_usage_start_offset = 0; uint64_t ras_telemetry_offset = 0; @@ -47,11 +48,10 @@ static int amdgpu_virt_ras_get_cmd_shared_mem(struct ras_core_context *ras_core, fw_vram_usage_start_offset = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].offset; ras_telemetry_offset = (uintptr_t)adev->virt.fw_reserve.ras_telemetry - (uintptr_t)fw_va; - } else if (adev->mman.drv_vram_usage_va && - adev->mman.drv_vram_usage_va <= adev->virt.fw_reserve.ras_telemetry) { - fw_vram_usage_start_offset = adev->mman.drv_vram_usage_start_offset; + } else if (drv_va && drv_va <= adev->virt.fw_reserve.ras_telemetry) { + fw_vram_usage_start_offset = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].offset; ras_telemetry_offset = (uintptr_t)adev->virt.fw_reserve.ras_telemetry - - (uintptr_t)adev->mman.drv_vram_usage_va; + (uintptr_t)drv_va; } else { return -EINVAL; } -- cgit v1.2.3 From bb92be605290d11b5bab307f76ab85013beba847 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 25 Mar 2026 19:10:16 +0530 Subject: drm/amdgpu: Add memory training reserve-region Use reserve region helpers for initializing/reserving memory training region. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 15 ++++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 79a49cba8d40..7e94ec11c57e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -277,7 +277,6 @@ struct psp_memory_training_context { /*vram offset of the c2p training data*/ u64 c2p_train_data_offset; - struct amdgpu_bo *c2p_bo; enum psp_memory_training_init_flag init; u32 training_cnt; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index feea4bbe5c95..9f02b9e3eea1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1745,8 +1745,7 @@ static int amdgpu_ttm_training_reserve_vram_fini(struct amdgpu_device *adev) struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx; ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT; - amdgpu_bo_free_kernel(&ctx->c2p_bo, NULL, NULL); - ctx->c2p_bo = NULL; + amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_MEM_TRAIN); return 0; } @@ -1817,14 +1816,12 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) if (mem_train_support) { /* reserve vram for mem train according to TMR location */ amdgpu_ttm_training_data_block_init(adev, reserve_size); - ret = amdgpu_bo_create_kernel_at(adev, - ctx->c2p_train_data_offset, - ctx->train_data_size, - &ctx->c2p_bo, - NULL); + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_MEM_TRAIN, + ctx->c2p_train_data_offset, + ctx->train_data_size, false); + ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_MEM_TRAIN); if (ret) { - dev_err(adev->dev, "alloc c2p_bo failed(%d)!\n", ret); - amdgpu_ttm_training_reserve_vram_fini(adev); + dev_err(adev->dev, "memory training region reservation failed(%d)!\n", ret); return ret; } ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS; -- cgit v1.2.3 From 5dad4394229953cae4e040107a4fd1886dc01f30 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 26 Mar 2026 10:39:16 +0530 Subject: drm/amdgpu: Group filling reserve region details Add a function which groups filling of reserve region information. It may not cover all as info on some regions are still filled outside like those from atomfirmware tables. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 ++++- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 39 ++++++++++++++++++--------------- drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 2 -- 10 files changed, 26 insertions(+), 34 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index c3b83d9f110e..285e217fba04 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -1033,10 +1033,13 @@ void amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, } } -void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev) +void amdgpu_gmc_init_vga_resv_regions(struct amdgpu_device *adev) { unsigned size; + if (adev->gmc.is_app_apu) + return; + /* * Some ASICs need to reserve a region of video memory to avoid access * from driver diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index 32e73e8ba778..6ab4c1e297fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -456,7 +456,7 @@ extern void amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, bool enable); -void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev); +void amdgpu_gmc_init_vga_resv_regions(struct amdgpu_device *adev); void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev); uint64_t amdgpu_gmc_vram_mc2pa(struct amdgpu_device *adev, uint64_t mc_addr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 9f02b9e3eea1..a6364a50a2eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1687,6 +1687,16 @@ void amdgpu_ttm_init_vram_resv(struct amdgpu_device *adev, resv->needs_cpu_map = needs_cpu_map; } +static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev) +{ + /* Initialize memory reservations as required for VGA. + * This is used for VGA emulation and pre-OS scanout buffers to + * avoid display artifacts while transitioning between pre-OS + * and driver. + */ + amdgpu_gmc_init_vga_resv_regions(adev); +} + int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, enum amdgpu_resv_region_id id) { @@ -2086,6 +2096,8 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) adev->gmc.visible_vram_size); #endif + amdgpu_ttm_init_vram_resv_regions(adev); + /* *The reserved vram for firmware must be pinned to the specified *place on the VRAM, so reserve it early. @@ -2123,26 +2135,17 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; } - /* allocate memory as required for VGA - * This is used for VGA emulation and pre-OS scanout buffers to - * avoid display artifacts while transitioning between pre-OS - * and driver. - */ - if (!adev->gmc.is_app_apu) { - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); - if (r) - return r; + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); + if (r) + return r; - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); - if (r) - return r; + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); + if (r) + return r; - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED); - if (r) - return r; - } else { - DRM_DEBUG_DRIVER("Skipped stolen memory reservation\n"); - } + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED); + if (r) + return r; dev_info(adev->dev, " %uM of VRAM memory ready\n", (unsigned int)(adev->gmc.real_vram_size / (1024 * 1024))); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index fd691b2a6e21..e1ace7d44ffd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -860,8 +860,6 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - amdgpu_gmc_get_vbios_allocations(adev); - /* Memory manager */ r = amdgpu_bo_init(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index e6db87b94eb1..94d6631ce0bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -834,8 +834,6 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - amdgpu_gmc_get_vbios_allocations(adev); - /* Memory manager */ r = amdgpu_bo_init(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c index 6e184ea069ef..e10ac9788d13 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c @@ -924,8 +924,6 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - amdgpu_gmc_get_vbios_allocations(adev); - #ifdef HAVE_ACPI_DEV_GET_FIRST_MATCH_DEV if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) { r = amdgpu_gmc_init_mem_ranges(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 886bf77309a5..cc272a96fcef 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -854,8 +854,6 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - amdgpu_gmc_get_vbios_allocations(adev); - r = amdgpu_bo_init(adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index d25fdedb0d9f..bb16ba2ef6fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -1034,8 +1034,6 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - amdgpu_gmc_get_vbios_allocations(adev); - /* Memory manager */ r = amdgpu_bo_init(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 4910e5557a67..a59174f6bcc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -1149,8 +1149,6 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - amdgpu_gmc_get_vbios_allocations(adev); - /* Memory manager */ r = amdgpu_bo_init(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index d865059e884a..e7b78027002b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -2010,8 +2010,6 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; - amdgpu_gmc_get_vbios_allocations(adev); - if (amdgpu_is_multi_aid(adev)) { r = amdgpu_gmc_init_mem_ranges(adev); if (r) -- cgit v1.2.3 From 2c7b0e37835cc4522debba57b31b491025e9728c Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 26 Mar 2026 10:54:38 +0530 Subject: drm/amdgpu: Add function to fill fw reserve region Add a function to fill in details for firmware reserve region. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 70 +++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 29 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index a6364a50a2eb..4a54b5bad552 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1687,6 +1687,43 @@ void amdgpu_ttm_init_vram_resv(struct amdgpu_device *adev, resv->needs_cpu_map = needs_cpu_map; } +static void amdgpu_ttm_init_fw_resv_region(struct amdgpu_device *adev) +{ + uint32_t reserve_size = 0; + + if (!adev->discovery.reserve_tmr) + return; + + /* + * Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all + * the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc) + * + * Otherwise, fallback to legacy approach to check and reserve tmr block for ip + * discovery data and G6 memory training data respectively + */ + if (adev->bios) + reserve_size = + amdgpu_atomfirmware_get_fw_reserved_fb_size(adev); + + if (!adev->bios && + (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) || + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) || + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0))) + reserve_size = max(reserve_size, (uint32_t)280 << 20); + else if (!adev->bios && + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) { + if (hweight32(adev->aid_mask) == 1) + reserve_size = max(reserve_size, (uint32_t)128 << 20); + else + reserve_size = max(reserve_size, (uint32_t)144 << 20); + } else if (!reserve_size) + reserve_size = DISCOVERY_TMR_OFFSET; + + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW, + adev->gmc.real_vram_size - reserve_size, + reserve_size, false); +} + static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev) { /* Initialize memory reservations as required for VGA. @@ -1695,6 +1732,7 @@ static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev) * and driver. */ amdgpu_gmc_init_vga_resv_regions(adev); + amdgpu_ttm_init_fw_resv_region(adev); } int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, @@ -1788,9 +1826,11 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) { struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx; bool mem_train_support = false; - uint32_t reserve_size = 0; + uint32_t reserve_size; int ret; + reserve_size = adev->mman.resv_region[AMDGPU_RESV_FW].size; + if (adev->bios && !amdgpu_sriov_vf(adev)) { if (amdgpu_atomfirmware_mem_training_supported(adev)) mem_train_support = true; @@ -1798,31 +1838,6 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) DRM_DEBUG("memory training does not support!\n"); } - /* - * Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all - * the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc) - * - * Otherwise, fallback to legacy approach to check and reserve tmr block for ip - * discovery data and G6 memory training data respectively - */ - if (adev->bios) - reserve_size = - amdgpu_atomfirmware_get_fw_reserved_fb_size(adev); - - if (!adev->bios && - (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) || - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) || - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0))) - reserve_size = max(reserve_size, (uint32_t)280 << 20); - else if (!adev->bios && - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) { - if (hweight32(adev->aid_mask) == 1) - reserve_size = max(reserve_size, (uint32_t)128 << 20); - else - reserve_size = max(reserve_size, (uint32_t)144 << 20); - } else if (!reserve_size) - reserve_size = DISCOVERY_TMR_OFFSET; - if (mem_train_support) { /* reserve vram for mem train according to TMR location */ amdgpu_ttm_training_data_block_init(adev, reserve_size); @@ -1837,9 +1852,6 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS; } - amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW, - adev->gmc.real_vram_size - reserve_size, - reserve_size, false); ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW); if (ret) { dev_err(adev->dev, "alloc tmr failed(%d)!\n", ret); -- cgit v1.2.3 From 7b0af16044b7669685f923d2c83c20d3aba72e18 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 26 Mar 2026 11:06:10 +0530 Subject: drm/amdgpu: Add function to fill training region Add a function to fill in memory training reservation region. Only if the reservation for the region is successful, memory training context will be initialized. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 62 +++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 4a54b5bad552..8d072eb4af78 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1724,6 +1724,28 @@ static void amdgpu_ttm_init_fw_resv_region(struct amdgpu_device *adev) reserve_size, false); } +static void amdgpu_ttm_init_mem_train_resv_region(struct amdgpu_device *adev) +{ + uint64_t reserve_size; + uint64_t offset; + + if (!adev->discovery.reserve_tmr) + return; + + if (!adev->bios || amdgpu_sriov_vf(adev)) + return; + + if (!amdgpu_atomfirmware_mem_training_supported(adev)) + return; + + reserve_size = adev->mman.resv_region[AMDGPU_RESV_FW].size; + offset = ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M); + amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_MEM_TRAIN, + offset, + GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES, + false); +} + static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev) { /* Initialize memory reservations as required for VGA. @@ -1733,6 +1755,7 @@ static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev) */ amdgpu_gmc_init_vga_resv_regions(adev); amdgpu_ttm_init_fw_resv_region(adev); + amdgpu_ttm_init_mem_train_resv_region(adev); } int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, @@ -1798,19 +1821,18 @@ static int amdgpu_ttm_training_reserve_vram_fini(struct amdgpu_device *adev) return 0; } -static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev, - uint32_t reserve_size) +static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev) { struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx; + struct amdgpu_vram_resv *resv = + &adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN]; memset(ctx, 0, sizeof(*ctx)); - ctx->c2p_train_data_offset = - ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M); + ctx->c2p_train_data_offset = resv->offset; ctx->p2c_train_data_offset = (adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET); - ctx->train_data_size = - GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES; + ctx->train_data_size = resv->size; DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n", ctx->train_data_size, @@ -1825,30 +1847,16 @@ static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev, static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) { struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx; - bool mem_train_support = false; - uint32_t reserve_size; int ret; - reserve_size = adev->mman.resv_region[AMDGPU_RESV_FW].size; + ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_MEM_TRAIN); + if (ret) { + dev_err(adev->dev, "memory training region reservation failed(%d)!\n", ret); + return ret; + } - if (adev->bios && !amdgpu_sriov_vf(adev)) { - if (amdgpu_atomfirmware_mem_training_supported(adev)) - mem_train_support = true; - else - DRM_DEBUG("memory training does not support!\n"); - } - - if (mem_train_support) { - /* reserve vram for mem train according to TMR location */ - amdgpu_ttm_training_data_block_init(adev, reserve_size); - amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_MEM_TRAIN, - ctx->c2p_train_data_offset, - ctx->train_data_size, false); - ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_MEM_TRAIN); - if (ret) { - dev_err(adev->dev, "memory training region reservation failed(%d)!\n", ret); - return ret; - } + if (adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN].size) { + amdgpu_ttm_training_data_block_init(adev); ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS; } -- cgit v1.2.3 From 6845355a08c2dc7e5af3c37b7d8f61afbfec1939 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 26 Mar 2026 11:11:39 +0530 Subject: drm/amdgpu: Move validation of reserve region info Keep validation of reserved regions also as part of filling details. If the information is invalid, size is kept as 0 so that it's not considered for reservation. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8d072eb4af78..212b489845a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1748,6 +1748,8 @@ static void amdgpu_ttm_init_mem_train_resv_region(struct amdgpu_device *adev) static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev) { + uint64_t vram_size = adev->gmc.visible_vram_size; + /* Initialize memory reservations as required for VGA. * This is used for VGA emulation and pre-OS scanout buffers to * avoid display artifacts while transitioning between pre-OS @@ -1756,6 +1758,12 @@ static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev) amdgpu_gmc_init_vga_resv_regions(adev); amdgpu_ttm_init_fw_resv_region(adev); amdgpu_ttm_init_mem_train_resv_region(adev); + + if (adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size > vram_size) + adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size = 0; + + if (adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size > vram_size) + adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size = 0; } int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, @@ -2122,27 +2130,17 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) *The reserved vram for firmware must be pinned to the specified *place on the VRAM, so reserve it early. */ - if (adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size > - adev->gmc.visible_vram_size) { - adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size = 0; - } else { - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE); - if (r) - return r; - } + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE); + if (r) + return r; /* * The reserved VRAM for the driver must be pinned to a specific * location in VRAM, so reserve it early. */ - if (adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size > - adev->gmc.visible_vram_size) { - adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size = 0; - } else { - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE); - if (r) - return r; - } + r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE); + if (r) + return r; /* * only NAVI10 and later ASICs support IP discovery. -- cgit v1.2.3 From f315099fd26ae8e9ab7718fbc8f66b157828313a Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 26 Mar 2026 11:21:15 +0530 Subject: drm/amdgpu: Consolidate reserve region allocations Move marking reserve regions to a single function. It loops through all the reserve region ids. The ones with non-zero size are reserved. There are still some reservations which could happen later during runtime like firmware extended reservation region. Signed-off-by: Lijo Lazar Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 89 ++++++++++----------------------- 1 file changed, 26 insertions(+), 63 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 212b489845a9..0dc68fb9d88e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1783,7 +1783,8 @@ int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, &resv->bo, resv->needs_cpu_map ? &resv->cpu_ptr : NULL); if (ret) { - dev_dbg(adev->dev, "reserve vram failed: id=%d offset=0x%llx size=0x%llx ret=%d\n", + dev_err(adev->dev, + "reserve vram failed: id=%d offset=0x%llx size=0x%llx ret=%d\n", id, resv->offset, resv->size, ret); memset(resv, 0, sizeof(*resv)); } @@ -1808,6 +1809,24 @@ void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev, memset(resv, 0, sizeof(*resv)); } +/* + * Reserve all regions with non-zero size. Regions whose info is not + * yet available (e.g., fw extended region) may still be reserved + * during runtime. + */ +static int amdgpu_ttm_alloc_vram_resv_regions(struct amdgpu_device *adev) +{ + int i, r; + + for (i = 0; i < AMDGPU_RESV_MAX; i++) { + r = amdgpu_ttm_mark_vram_reserved(adev, i); + if (r) + return r; + } + + return 0; +} + /* * Memoy training reservation functions */ @@ -1848,35 +1867,6 @@ static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev) ctx->c2p_train_data_offset); } -/* - * reserve TMR memory at the top of VRAM which holds - * IP Discovery data and is protected by PSP. - */ -static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev) -{ - struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx; - int ret; - - ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_MEM_TRAIN); - if (ret) { - dev_err(adev->dev, "memory training region reservation failed(%d)!\n", ret); - return ret; - } - - if (adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN].size) { - amdgpu_ttm_training_data_block_init(adev); - ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS; - } - - ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW); - if (ret) { - dev_err(adev->dev, "alloc tmr failed(%d)!\n", ret); - return ret; - } - - return 0; -} - static int amdgpu_ttm_pools_init(struct amdgpu_device *adev) { int i; @@ -2126,45 +2116,18 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) amdgpu_ttm_init_vram_resv_regions(adev); - /* - *The reserved vram for firmware must be pinned to the specified - *place on the VRAM, so reserve it early. - */ - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE); + r = amdgpu_ttm_alloc_vram_resv_regions(adev); if (r) return r; - /* - * The reserved VRAM for the driver must be pinned to a specific - * location in VRAM, so reserve it early. - */ - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE); - if (r) - return r; + if (adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN].size) { + struct psp_memory_training_context *ctx = + &adev->psp.mem_train_ctx; - /* - * only NAVI10 and later ASICs support IP discovery. - * If IP discovery is enabled, a block of memory should be - * reserved for it. - */ - if (adev->discovery.reserve_tmr) { - r = amdgpu_ttm_reserve_tmr(adev); - if (r) - return r; + amdgpu_ttm_training_data_block_init(adev); + ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS; } - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA); - if (r) - return r; - - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED); - if (r) - return r; - - r = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED); - if (r) - return r; - dev_info(adev->dev, " %uM of VRAM memory ready\n", (unsigned int)(adev->gmc.real_vram_size / (1024 * 1024))); -- cgit v1.2.3 From e0e9792ea2d4bc72634c0ba77472c3d4ef01fc8e Mon Sep 17 00:00:00 2001 From: Xiaogang Chen Date: Tue, 31 Mar 2026 13:24:17 -0500 Subject: drm/amdgpu: add an option to allow gpu partition allocate all available memory Current driver reports and limits memory allocation for each partition equally among partitions using same memory partition. Application may not be able to use all available memory when run on a partitioned gpu though system still has enough free memory. Add an option that app can use to have gpu partition allocate all available memory. Signed-off-by: Xiaogang Chen Reviewed-by: Philip Yang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 5 +++- drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 39 ++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h | 17 +++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h | 2 ++ 5 files changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 4f27c75abedb..d9e283f3b57d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -805,7 +805,10 @@ u64 amdgpu_amdkfd_xcp_memory_size(struct amdgpu_device *adev, int xcp_id) } else { tmp = adev->gmc.mem_partitions[mem_id].size; } - do_div(tmp, adev->xcp_mgr->num_xcp_per_mem_partition); + + if (adev->xcp_mgr->mem_alloc_mode == AMDGPU_PARTITION_MEM_CAPPING_EVEN) + do_div(tmp, adev->xcp_mgr->num_xcp_per_mem_partition); + return ALIGN_DOWN(tmp, PAGE_SIZE); } else if (adev->apu_prefer_gtt) { return (ttm_tt_pages_limit() << PAGE_SHIFT); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index cab3196a87fb..2956e45c9254 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -1580,6 +1580,36 @@ static ssize_t amdgpu_gfx_set_compute_partition(struct device *dev, return count; } +static ssize_t compute_partition_mem_alloc_mode_show(struct device *dev, + struct device_attribute *addr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + int mode = adev->xcp_mgr->mem_alloc_mode; + + return sysfs_emit(buf, "%s\n", + amdgpu_gfx_compute_mem_alloc_mode_desc(mode)); +} + + +static ssize_t compute_partition_mem_alloc_mode_store(struct device *dev, + struct device_attribute *addr, + const char *buf, size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (!strncasecmp("CAPPING", buf, strlen("CAPPING"))) + adev->xcp_mgr->mem_alloc_mode = AMDGPU_PARTITION_MEM_CAPPING_EVEN; + else if (!strncasecmp("ALL", buf, strlen("ALL"))) + adev->xcp_mgr->mem_alloc_mode = AMDGPU_PARTITION_MEM_ALLOC_ALL; + else + return -EINVAL; + + return count; +} + static const char *xcp_desc[] = { [AMDGPU_SPX_PARTITION_MODE] = "SPX", [AMDGPU_DPX_PARTITION_MODE] = "DPX", @@ -1935,6 +1965,10 @@ static DEVICE_ATTR(gfx_reset_mask, 0444, static DEVICE_ATTR(compute_reset_mask, 0444, amdgpu_gfx_get_compute_reset_mask, NULL); +static DEVICE_ATTR(compute_partition_mem_alloc_mode, 0644, + compute_partition_mem_alloc_mode_show, + compute_partition_mem_alloc_mode_store); + static int amdgpu_gfx_sysfs_xcp_init(struct amdgpu_device *adev) { struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr; @@ -1955,6 +1989,11 @@ static int amdgpu_gfx_sysfs_xcp_init(struct amdgpu_device *adev) if (r) return r; + r = device_create_file(adev->dev, + &dev_attr_compute_partition_mem_alloc_mode); + if (r) + return r; + if (xcp_switch_supported) r = device_create_file(adev->dev, &dev_attr_available_compute_partition); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 2785eda6fea5..a0cf0a3b41da 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -71,6 +71,11 @@ enum amdgpu_gfx_partition { AMDGPU_AUTO_COMPUTE_PARTITION_MODE = -2, }; +enum amdgpu_gfx_partition_mem_alloc_mode { + AMDGPU_PARTITION_MEM_CAPPING_EVEN = 0, + AMDGPU_PARTITION_MEM_ALLOC_ALL = 1, +}; + #define NUM_XCC(x) hweight16(x) enum amdgpu_gfx_ras_mem_id_type { @@ -677,4 +682,16 @@ static inline const char *amdgpu_gfx_compute_mode_desc(int mode) } } +static inline const char *amdgpu_gfx_compute_mem_alloc_mode_desc(int mode) +{ + switch (mode) { + case AMDGPU_PARTITION_MEM_CAPPING_EVEN: + return "CAPPING"; + case AMDGPU_PARTITION_MEM_ALLOC_ALL: + return "ALL"; + default: + return "UNKNOWN"; + } +} + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c index cc5f4e01e38f..42be8ee155dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c @@ -181,6 +181,7 @@ int amdgpu_xcp_init(struct amdgpu_xcp_mgr *xcp_mgr, int num_xcps, int mode) } xcp_mgr->num_xcps = num_xcps; + xcp_mgr->mem_alloc_mode = AMDGPU_PARTITION_MEM_CAPPING_EVEN; amdgpu_xcp_update_partition_sched_list(adev); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h index 8058e8f35d41..878c1c422893 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h @@ -132,6 +132,8 @@ struct amdgpu_xcp_mgr { struct amdgpu_xcp_cfg *xcp_cfg; uint32_t supp_xcp_modes; uint32_t avail_xcp_modes; + /* used to determin KFD memory alloc mode for each partition */ + uint32_t mem_alloc_mode; }; struct amdgpu_xcp_mgr_funcs { -- cgit v1.2.3 From d290d6ee90b48b346978e8549b0bc0ba28c047fc Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Fri, 13 Mar 2026 15:47:15 +0100 Subject: drm/amd/display: Replace use of system_wq with system_percpu_wq This patch continues the effort to refactor workqueue APIs, which has begun with the changes introducing new workqueues and a new alloc_workqueue flag: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The point of the refactoring is to eventually alter the default behavior of workqueues to become unbound by default so that their workload placement is optimized by the scheduler. Before that to happen, workqueue users must be converted to the better named new workqueues with no intended behaviour changes: system_wq -> system_percpu_wq system_unbound_wq -> system_dfl_wq This way the old obsolete workqueues (system_wq, system_unbound_wq) can be removed in the future. Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/ Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 1816007f1040..1d9ceb432ec3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -572,7 +572,7 @@ static void schedule_dc_vmin_vmax(struct amdgpu_device *adev, offload_work->stream = stream; offload_work->adjust = adjust_copy; - queue_work(system_wq, &offload_work->work); + queue_work(system_percpu_wq, &offload_work->work); } static void dm_vupdate_high_irq(void *interrupt_params) @@ -4268,7 +4268,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector) dc_sink_retain(aconnector->hdmi_prev_sink); /* Schedule delayed detection. */ - if (mod_delayed_work(system_wq, + if (mod_delayed_work(system_percpu_wq, &aconnector->hdmi_hpd_debounce_work, msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms))) drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n"); -- cgit v1.2.3 From 1d0a26cf37c1b2e9928d2b61af6f282232b5daea Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Tue, 24 Mar 2026 19:53:59 -0400 Subject: drm/amdgpu: add CONFIG_GCOV_PROFILE_AMDGPU Kconfig option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a Kconfig option to enable GCOV code coverage profiling for the amdgpu driver, following the established upstream pattern used by CONFIG_GCOV_PROFILE_FTRACE (kernel/trace), CONFIG_GCOV_PROFILE_RDS (net/rds), and CONFIG_GCOV_PROFILE_URING (io_uring). This allows CI systems to enable amdgpu code coverage entirely via .config (e.g., scripts/config --enable GCOV_PROFILE_AMDGPU) without manually editing the amdgpu Makefile. The option depends on both DRM_AMDGPU and GCOV_KERNEL, defaults to n, and is therefore never enabled in production or distro builds. Cc: Christian König Cc: Alex Deucher Signed-off-by: Vitaly Prosyak Acked-by: Christian König Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/Kconfig | 17 +++++++++++++++++ drivers/gpu/drm/amd/amdgpu/Makefile | 4 ++++ 2 files changed, 21 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 7f515be5185d..7fb0b93bc1ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -103,6 +103,23 @@ config DRM_AMDGPU_WERROR Add -Werror to the build flags for amdgpu.ko. Only enable this if you are warning code for amdgpu.ko. + +config GCOV_PROFILE_AMDGPU + bool "Enable GCOV profiling on amdgpu" + depends on DRM_AMDGPU + depends on GCOV_KERNEL + default n + help + Enable GCOV profiling on the amdgpu driver for checking which + functions/lines are executed during testing. This adds compiler + instrumentation flags to all amdgpu source files, producing + .gcda/.gcno coverage data accessible via debugfs. + + This increases the amdgpu module size by ~50% and adds ~2-5% + runtime overhead on GPU submission paths. + + If unsure, say N. + source "drivers/gpu/drm/amd/acp/Kconfig" source "drivers/gpu/drm/amd/display/Kconfig" source "drivers/gpu/drm/amd/amdkfd/Kconfig" diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 6a7e9bfec59e..db66c6372199 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -27,6 +27,10 @@ FULL_AMD_PATH=$(src)/.. DISPLAY_FOLDER_NAME=display FULL_AMD_DISPLAY_PATH = $(FULL_AMD_PATH)/$(DISPLAY_FOLDER_NAME) +ifdef CONFIG_GCOV_PROFILE_AMDGPU +GCOV_PROFILE := y +endif + ccflags-y := -I$(FULL_AMD_PATH)/include/asic_reg \ -I$(FULL_AMD_PATH)/include \ -I$(FULL_AMD_PATH)/amdgpu \ -- cgit v1.2.3 From f2275ea90be581f599e7c88a9dbfc5dd4383087d Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 27 Mar 2026 13:13:00 +0530 Subject: drm/amd/pm: Add smu vram copy function Add a wrapper function for copying data/to from vram. This additionally checks for any RAS fatal error. Copy cannot be trusted if any RAS fatal error happened as VRAM becomes inaccessible. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 12 ++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 3 +++ 2 files changed, 15 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 7bd8c435466a..006ef585a377 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -1104,6 +1104,18 @@ int smu_cmn_update_table(struct smu_context *smu, return 0; } +int smu_cmn_vram_cpy(struct smu_context *smu, void *dst, const void *src, + size_t len) +{ + memcpy(dst, src, len); + + /* Don't trust the copy operation if RAS fatal error happened. */ + if (amdgpu_ras_get_fed_status(smu->adev)) + return -EHWPOISON; + + return 0; +} + int smu_cmn_write_watermarks_table(struct smu_context *smu) { void *watermarks_table = smu->smu_table.watermarks_table; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index b76e86df5da7..d129907535bd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -174,6 +174,9 @@ int smu_cmn_update_table(struct smu_context *smu, void *table_data, bool drv2smu); +int smu_cmn_vram_cpy(struct smu_context *smu, void *dst, + const void *src, size_t len); + int smu_cmn_write_watermarks_table(struct smu_context *smu); int smu_cmn_write_pptable(struct smu_context *smu); -- cgit v1.2.3 From 3bec582562a17ff16c4e3b8ac5cac8a6713976f2 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 27 Mar 2026 13:16:33 +0530 Subject: drm/amd/pm: Use smu vram copy in SMUv13 Use smu vram copy wrapper function for vram copy operations in SMUv13.0.6 and SMUv13.0.12. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 9 +++++++-- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 19 ++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 54a86eb77cd5..fe929bd89058 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -479,9 +479,14 @@ static int smu_v13_0_12_get_system_metrics_table(struct smu_context *smu) } amdgpu_hdp_invalidate(smu->adev, NULL); + + ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer, + table->cpu_addr, + smu_v13_0_12_get_system_metrics_size()); + if (ret) + return ret; + smu_table_cache_update_time(sys_table, jiffies); - memcpy(sys_table->cache.buffer, table->cpu_addr, - smu_v13_0_12_get_system_metrics_size()); return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 475541189782..cd0a23f432ff 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -778,7 +778,10 @@ int smu_v13_0_6_get_metrics_table(struct smu_context *smu, void *metrics_table, } amdgpu_hdp_invalidate(smu->adev, NULL); - memcpy(smu_table->metrics_table, table->cpu_addr, table_size); + ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); + if (ret) + return ret; smu_table->metrics_time = jiffies; } @@ -857,9 +860,9 @@ int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu) } amdgpu_hdp_invalidate(smu->adev, NULL); - memcpy(smu_table->metrics_table, table->cpu_addr, table_size); - return 0; + return smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); } static void smu_v13_0_6_update_caps(struct smu_context *smu) @@ -2404,13 +2407,15 @@ static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu, table_size = smu_table->tables[SMU_TABLE_I2C_COMMANDS].size; - memcpy(table->cpu_addr, table_data, table_size); + ret = smu_cmn_vram_cpy(smu, table->cpu_addr, table_data, table_size); + if (ret) + return ret; + /* Flush hdp cache */ amdgpu_hdp_flush(adev, NULL); - ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction, - NULL); - return ret; + return smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction, + NULL); } static int smu_v13_0_6_i2c_xfer(struct i2c_adapter *i2c_adap, -- cgit v1.2.3 From 3ecee2073cac99c629725f63a033c16ebac17e59 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 27 Mar 2026 13:20:40 +0530 Subject: drm/amd/pm: Use smu vram copy in SMUv15 Use smu vram copy wrapper function for vram copy operations in SMUv15.0.8 Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index cc2babc6a341..1682ef1338f1 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -344,7 +344,12 @@ static int smu_v15_0_8_get_metrics_table_internal(struct smu_context *smu, uint3 } amdgpu_device_invalidate_hdp(smu->adev, NULL); - memcpy(smu_table->metrics_table, table->cpu_addr, table_size); + ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); + if (ret) { + mutex_unlock(&smu_table->metrics_lock); + return ret; + } smu_table->metrics_time = jiffies; } @@ -551,9 +556,14 @@ static int smu_v15_0_8_get_system_metrics_table(struct smu_context *smu) } amdgpu_hdp_invalidate(smu->adev, NULL); + + ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer, + table->cpu_addr, + sizeof(SystemMetricsTable_t)); + if (ret) + return ret; + smu_table_cache_update_time(sys_table, jiffies); - memcpy(sys_table->cache.buffer, table->cpu_addr, - sizeof(SystemMetricsTable_t)); return 0; } @@ -988,9 +998,9 @@ static int smu_v15_0_8_get_static_metrics_table(struct smu_context *smu) } amdgpu_hdp_invalidate(smu->adev, NULL); - memcpy(smu_table->metrics_table, table->cpu_addr, table_size); - return 0; + return smu_cmn_vram_cpy(smu, smu_table->metrics_table, + table->cpu_addr, table_size); } static int smu_v15_0_8_fru_get_product_info(struct smu_context *smu, -- cgit v1.2.3 From 7f0fc003688e22553c16a4740ce5c6297ef9c0e3 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Wed, 24 Dec 2025 15:47:05 +0100 Subject: drm/amdgpu: replace use of system_unbound_wq with system_dfl_wq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch continues the effort to refactor workqueue APIs, which has begun with the changes introducing new workqueues and a new alloc_workqueue flag: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The point of the refactoring is to eventually alter the default behavior of workqueues to become unbound by default so that their workload placement is optimized by the scheduler. Before that to happen after a careful review and conversion of each individual case, workqueue users must be converted to the better named new workqueues with no intended behaviour changes: system_wq -> system_percpu_wq system_unbound_wq -> system_dfl_wq This way the old obsolete workqueues (system_wq, system_unbound_wq) can be removed in the future. Suggested-by: Tejun Heo Acked-by: Christian König Signed-off-by: Marco Crivellari Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/aldebaran.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 938fb0b2368d..8686c6dc2c08 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -179,7 +179,7 @@ aldebaran_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl, list_for_each_entry(tmp_adev, reset_device_list, reset_list) { /* For XGMI run all resets in parallel to speed up the process */ if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { - if (!queue_work(system_unbound_wq, + if (!queue_work(system_dfl_wq, &tmp_adev->reset_cntl->reset_work)) r = -EALREADY; } else diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 9c936519bb2b..bf271a97d1e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5339,7 +5339,7 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, list_for_each_entry(tmp_adev, device_list_handle, reset_list) { /* For XGMI run all resets in parallel to speed up the process */ if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { - if (!queue_work(system_unbound_wq, + if (!queue_work(system_dfl_wq, &tmp_adev->xgmi_reset_work)) r = -EALREADY; } else diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 7a2fcb7ded1d..1b982b803e6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -116,7 +116,7 @@ static int amdgpu_reset_xgmi_reset_on_init_perform_reset( /* Mode1 reset needs to be triggered on all devices together */ list_for_each_entry(tmp_adev, reset_device_list, reset_list) { /* For XGMI run all resets in parallel to speed up the process */ - if (!queue_work(system_unbound_wq, &tmp_adev->xgmi_reset_work)) + if (!queue_work(system_dfl_wq, &tmp_adev->xgmi_reset_work)) r = -EALREADY; if (r) { dev_err(tmp_adev->dev, -- cgit v1.2.3 From 53140a0d591298adeb6758ca57ab3334cbe35d6e Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Wed, 24 Dec 2025 15:47:06 +0100 Subject: drm/amdgpu: replace use of system_wq with system_dfl_wq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch continues the effort to refactor workqueue APIs, which has begun with the changes introducing new workqueues and a new alloc_workqueue flag: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The point of the refactoring is to eventually alter the default behavior of workqueues to become unbound by default so that their workload placement is optimized by the scheduler. Before that to happen after a careful review and conversion of each individual case, workqueue users must be converted to the better named new workqueues with no intended behaviour changes: system_wq -> system_percpu_wq system_unbound_wq -> system_dfl_wq This way the old obsolete workqueues (system_wq, system_unbound_wq) can be removed in the future. Suggested-by: Tejun Heo Acked-by: Christian König Signed-off-by: Marco Crivellari Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index bf271a97d1e8..824ac0a0549f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4065,7 +4065,7 @@ fence_driver_init: } /* must succeed. */ amdgpu_ras_resume(adev); - queue_delayed_work(system_wq, &adev->delayed_init_work, + queue_delayed_work(system_dfl_wq, &adev->delayed_init_work, msecs_to_jiffies(AMDGPU_RESUME_MS)); } @@ -4630,7 +4630,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients) if (r) goto exit; - queue_delayed_work(system_wq, &adev->delayed_init_work, + queue_delayed_work(system_dfl_wq, &adev->delayed_init_work, msecs_to_jiffies(AMDGPU_RESUME_MS)); exit: if (amdgpu_sriov_vf(adev)) { -- cgit v1.2.3 From 505b1c7342aed9cc3c35c8043fe6bc5ccbeb6b0b Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Wed, 24 Dec 2025 15:47:07 +0100 Subject: amd/amdkfd: add WQ_UNBOUND to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue flag in: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The refactoring is going to alter the default behavior of alloc_workqueue() to be unbound by default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. For more details see the Link tag below. This specific workload has no benefit being per-cpu, so its behavior has been changed using explicitly WQ_UNBOUND. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index bcd21204aa50..d28ca581cad0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -689,7 +689,8 @@ void kfd_procfs_del_queue(struct queue *q) int kfd_process_create_wq(void) { if (!kfd_process_wq) - kfd_process_wq = alloc_workqueue("kfd_process_wq", 0, 0); + kfd_process_wq = alloc_workqueue("kfd_process_wq", WQ_UNBOUND, + 0); if (!kfd_restore_wq) kfd_restore_wq = alloc_ordered_workqueue("kfd_restore_wq", WQ_FREEZABLE); -- cgit v1.2.3 From 95a599c8a25a60a63b710ea863577ee51a8b62a2 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Wed, 24 Dec 2025 15:47:08 +0100 Subject: drm/radeon: add WQ_PERCPU to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue flag in: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") The refactoring is going to alter the default behavior of alloc_workqueue() to be unbound by default. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. For more details see the Link tag below. In order to keep alloc_workqueue() behavior identical, explicitly request WQ_PERCPU. Suggested-by: Tejun Heo Acked-by: Christian König Signed-off-by: Marco Crivellari Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 5c72aad3dae7..aac6733ddd82 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -686,7 +686,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index) if (radeon_crtc == NULL) return; - radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0); + radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", + WQ_HIGHPRI | WQ_PERCPU, 0); if (!radeon_crtc->flip_queue) { kfree(radeon_crtc); return; -- cgit v1.2.3 From 592713a8960ed661bd9fcb7c256921c53eadeb49 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Wed, 25 Mar 2026 21:41:46 -0400 Subject: drm/amd/pm: correct mem_busy_percent display due to calculation errors PMFW may return invalid values due to internal calculation errors. so, the kmd driver must validate and sanitize the returned values to prevent issues caused by firmware calculation errors. For example, values 0xfffe (-2) and 0xffff (-1) are treated as invalid and clamped to 0. this applies to devices with CAB (Cache As Buffer) functionality. Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4905 Signed-off-by: Yang Wang Reviewed-by: Kenneth Feng Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 17 +++++++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 10 +++++----- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 10 +++++----- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 10 +++++----- 4 files changed, 32 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 609f5ab07d8a..126fc54cb511 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -2164,4 +2164,21 @@ static inline void smu_feature_init(struct smu_context *smu, int feature_num) smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED); } +/* + * smu_safe_u16_nn - Make u16 safe by filtering negative overflow errors + * @val: Input u16 value, may contain invalid negative overflows + * + * Convert u16 to non-negative value. Cast to s16 to detect negative values + * caused by calculation errors. Return 0 for negative errors, return + * original value if valid. + * + * Return: Valid u16 value or 0 + */ +static inline u16 smu_safe_u16_nn(u16 val) +{ + s16 tmp = (s16)val; + + return tmp < 0 ? 0 : val; +} + #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index b414a74d29fd..0a7f5fa3c1d3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -773,13 +773,13 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxclkFrequencyPreDs; break; case METRICS_AVERAGE_FCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD) *value = metrics->AverageFclkFrequencyPostDs; else *value = metrics->AverageFclkFrequencyPreDs; break; case METRICS_AVERAGE_UCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD) *value = metrics->AverageMemclkFrequencyPostDs; else *value = metrics->AverageMemclkFrequencyPreDs; @@ -800,7 +800,7 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxActivity; break; case METRICS_AVERAGE_MEMACTIVITY: - *value = metrics->AverageUclkActivity; + *value = smu_safe_u16_nn(metrics->AverageUclkActivity); break; case METRICS_AVERAGE_VCNACTIVITY: *value = max(metrics->Vcn0ActivityPercentage, @@ -2085,7 +2085,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu, metrics->AvgTemperature[TEMP_VR_MEM1]); gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity; - gpu_metrics->average_umc_activity = metrics->AverageUclkActivity; + gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity); gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage, metrics->Vcn1ActivityPercentage); @@ -2102,7 +2102,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu, else gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs; - if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD) gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs; else gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index fd0b6215364f..5abf2b0703c6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -783,13 +783,13 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxclkFrequencyPreDs; break; case METRICS_AVERAGE_FCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD) *value = metrics->AverageFclkFrequencyPostDs; else *value = metrics->AverageFclkFrequencyPreDs; break; case METRICS_AVERAGE_UCLK: - if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD) *value = metrics->AverageMemclkFrequencyPostDs; else *value = metrics->AverageMemclkFrequencyPreDs; @@ -814,7 +814,7 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxActivity; break; case METRICS_AVERAGE_MEMACTIVITY: - *value = metrics->AverageUclkActivity; + *value = smu_safe_u16_nn(metrics->AverageUclkActivity); break; case METRICS_AVERAGE_SOCKETPOWER: *value = metrics->AverageSocketPower << 8; @@ -2091,7 +2091,7 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu, metrics->AvgTemperature[TEMP_VR_MEM1]); gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity; - gpu_metrics->average_umc_activity = metrics->AverageUclkActivity; + gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity); gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage, metrics->Vcn1ActivityPercentage); @@ -2104,7 +2104,7 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu, else gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs; - if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD) gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs; else gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 31f9566f7979..62514e3ac600 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -661,13 +661,13 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxclkFrequencyPreDs; break; case METRICS_AVERAGE_FCLK: - if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD) *value = metrics->AverageFclkFrequencyPostDs; else *value = metrics->AverageFclkFrequencyPreDs; break; case METRICS_AVERAGE_UCLK: - if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD) *value = metrics->AverageMemclkFrequencyPostDs; else *value = metrics->AverageMemclkFrequencyPreDs; @@ -688,7 +688,7 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu, *value = metrics->AverageGfxActivity; break; case METRICS_AVERAGE_MEMACTIVITY: - *value = metrics->AverageUclkActivity; + *value = smu_safe_u16_nn(metrics->AverageUclkActivity); break; case METRICS_AVERAGE_VCNACTIVITY: *value = max(metrics->AverageVcn0ActivityPercentage, @@ -2147,7 +2147,7 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, metrics->AvgTemperature[TEMP_VR_MEM1]); gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity; - gpu_metrics->average_umc_activity = metrics->AverageUclkActivity; + gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity); gpu_metrics->average_mm_activity = max(metrics->AverageVcn0ActivityPercentage, metrics->Vcn1ActivityPercentage); @@ -2159,7 +2159,7 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, else gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs; - if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD) + if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD) gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs; else gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs; -- cgit v1.2.3 From 95e21dff4717c0525f80c225884ddc391911b1c3 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 30 Mar 2026 22:23:06 -0400 Subject: drm/amd/pm: fix null pointer dereference issue in smu_v15_0_8_get_power_limit() Fix null pointer issues caused by coding errors Fixes: e20e47bcb3f1 ("drm/amd/pm: add set{get}_power_limit support for smu 15.0.8") Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index 1682ef1338f1..756cf4ac00fa 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -1785,7 +1785,7 @@ static int smu_v15_0_8_get_power_limit(struct smu_context *smu, *current_power_limit = power_limit; if (default_power_limit) - *max_power_limit = pptable->MaxSocketPowerLimit; + *default_power_limit = pptable->MaxSocketPowerLimit; if (max_power_limit) *max_power_limit = pptable->MaxSocketPowerLimit; -- cgit v1.2.3 From e4465c0464a3d1b8d66d84c440ab1d49c483c01a Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 30 Mar 2026 22:39:17 -0400 Subject: drm/amd/pm: optimize logic and remove unnecessary checks in smu v15.0.8 the following two sets of logic are clearly mutually exclusive in smu_v15_0_8_set_soft_freq_limited_range. remove unnecessary code logic to keep the code logic clear. e.g: if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) return -EINVAL; if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { ... } Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- .../gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 52 ++++++++++------------ 1 file changed, 23 insertions(+), 29 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index 756cf4ac00fa..60a39c14f0e9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -1911,42 +1911,36 @@ static int smu_v15_0_8_set_soft_freq_limited_range(struct smu_context *smu, if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) return -EINVAL; - if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { - if (min >= max) { - dev_err(smu->adev->dev, - "Minimum clk should be less than the maximum allowed clock\n"); - return -EINVAL; - } + if (min >= max) { + dev_err(smu->adev->dev, + "Minimum clk should be less than the maximum allowed clock\n"); + return -EINVAL; + } - if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) { - if ((min == pstate_table->gfxclk_pstate.curr.min) && - (max == pstate_table->gfxclk_pstate.curr.max)) - return 0; + if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) { + if ((min == pstate_table->gfxclk_pstate.curr.min) && + (max == pstate_table->gfxclk_pstate.curr.max)) + return 0; - ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu, - min, max); - if (!ret) { - pstate_table->gfxclk_pstate.curr.min = min; - pstate_table->gfxclk_pstate.curr.max = max; - } + ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu, min, + max); + if (!ret) { + pstate_table->gfxclk_pstate.curr.min = min; + pstate_table->gfxclk_pstate.curr.max = max; } + } - if (clk_type == SMU_UCLK) { - if (max == pstate_table->uclk_pstate.curr.max) - return 0; - - ret = smu_v15_0_set_soft_freq_limited_range(smu, - SMU_UCLK, - 0, max, - false); - if (!ret) - pstate_table->uclk_pstate.curr.max = max; - } + if (clk_type == SMU_UCLK) { + if (max == pstate_table->uclk_pstate.curr.max) + return 0; - return ret; + ret = smu_v15_0_set_soft_freq_limited_range(smu, SMU_UCLK, 0, + max, false); + if (!ret) + pstate_table->uclk_pstate.curr.max = max; } - return 0; + return ret; } static int smu_v15_0_8_od_edit_dpm_table(struct smu_context *smu, -- cgit v1.2.3 From 48d1a5b33a5a946fca3e444c4f3df13ef847f40d Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 30 Mar 2026 22:12:57 -0400 Subject: drm/amd/pm: fix memleak issue in smu_v15_0_8_get_gpu_metrics() remove unsued code to avoid memleak issue. (NOTE: This bug occurs during internal branch switching) Fixes: 0a66ca3b351f ("drm/amd/pm: add get_gpu_metrics support for 15.0.8") Signed-off-by: Yang Wang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index 60a39c14f0e9..db85186f2d66 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -1611,8 +1611,6 @@ static ssize_t smu_v15_0_8_get_gpu_metrics(struct smu_context *smu, void **table uint32_t mid_mask = adev->aid_mask; MetricsTable_t *metrics; - metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL); - ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL); if (ret) return ret; -- cgit v1.2.3 From 1d4ade3646eb063ecc82060b607329730cca100c Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Tue, 31 Mar 2026 18:14:57 +0530 Subject: drm/amdgpu/userq: dont need check for return values in amdgpu_userq_evict MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function of amdgpu_userq_evict function do not need to check for return values as we dont use them and no need to log errors as we are already logging in called functions. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 366728ed03e3..744095d42fd0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1258,7 +1258,8 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr) } if (ret) - drm_file_err(uq_mgr->file, "Couldn't unmap all the queues\n"); + drm_file_err(uq_mgr->file, + "Couldn't unmap all the queues, eviction failed ret=%d\n", ret); return ret; } @@ -1307,18 +1308,9 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr) { - struct amdgpu_device *adev = uq_mgr->adev; - int ret; - /* Wait for any pending userqueue fence work to finish */ - ret = amdgpu_userq_wait_for_signal(uq_mgr); - if (ret) - dev_err(adev->dev, "Not evicting userqueue, timeout waiting for work\n"); - - ret = amdgpu_userq_evict_all(uq_mgr); - if (ret) - dev_err(adev->dev, "Failed to evict userqueue\n"); - + amdgpu_userq_wait_for_signal(uq_mgr); + amdgpu_userq_evict_all(uq_mgr); } int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv, -- cgit v1.2.3 From 3c863ff920b45fa7a9b7d4cb932f466488a87a58 Mon Sep 17 00:00:00 2001 From: Mikhail Gavrilov Date: Tue, 31 Mar 2026 19:21:26 +0500 Subject: drm/amdgpu: replace PASID IDR with XArray MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the PASID IDR + spinlock with XArray as noted in the TODO left by commit ea56aa262570 ("drm/amdgpu: fix the idr allocation flags"). The IDR conversion still has an IRQ safety issue: amdgpu_pasid_free() can be called from hardirq context via the fence signal path, but amdgpu_pasid_idr_lock is taken with plain spin_lock() in process context, creating a potential deadlock: CPU0 ---- spin_lock(&amdgpu_pasid_idr_lock) // process context, IRQs on spin_lock(&amdgpu_pasid_idr_lock) // deadlock The hardirq call chain is: sdma_v6_0_process_trap_irq -> amdgpu_fence_process -> dma_fence_signal -> drm_sched_job_done -> dma_fence_signal -> amdgpu_pasid_free_cb -> amdgpu_pasid_free Use XArray with XA_FLAGS_LOCK_IRQ (all xa operations use IRQ-safe locking internally) and XA_FLAGS_ALLOC1 (zero is not a valid PASID). Both xa_alloc_cyclic() and xa_erase() then handle locking consistently, fixing the IRQ safety issue and removing the need for an explicit spinlock. v8: squash in irq safe fix Reviewed-by: Christian König Suggested-by: Lijo Lazar Fixes: ea56aa262570 ("drm/amdgpu: fix the idr allocation flags") Fixes: 8f1de51f49be ("drm/amdgpu: prevent immediate PASID reuse case") Signed-off-by: Mikhail Gavrilov Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 39 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 569c5a89ff10..124fb38eb465 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -22,7 +22,7 @@ */ #include "amdgpu_ids.h" -#include +#include #include @@ -40,8 +40,8 @@ * VMs are looked up from the PASID per amdgpu_device. */ -static DEFINE_IDR(amdgpu_pasid_idr); -static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock); +static DEFINE_XARRAY_FLAGS(amdgpu_pasid_xa, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ALLOC1); +static u32 amdgpu_pasid_xa_next; /* Helper to free pasid from a fence callback */ struct amdgpu_pasid_cb { @@ -62,36 +62,37 @@ struct amdgpu_pasid_cb { */ int amdgpu_pasid_alloc(unsigned int bits) { - int pasid; + u32 pasid; + int r; if (bits == 0) return -EINVAL; - spin_lock(&amdgpu_pasid_idr_lock); - /* TODO: Need to replace the idr with an xarry, and then - * handle the internal locking with ATOMIC safe paths. - */ - pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1, - 1U << bits, GFP_ATOMIC); - spin_unlock(&amdgpu_pasid_idr_lock); - - if (pasid >= 0) - trace_amdgpu_pasid_allocated(pasid); + r = xa_alloc_cyclic_irq(&amdgpu_pasid_xa, &pasid, xa_mk_value(0), + XA_LIMIT(1, (1U << bits) - 1), + &amdgpu_pasid_xa_next, GFP_KERNEL); + if (r < 0) + return r; + trace_amdgpu_pasid_allocated(pasid); return pasid; } /** * amdgpu_pasid_free - Free a PASID * @pasid: PASID to free + * + * Called in IRQ context. */ void amdgpu_pasid_free(u32 pasid) { + unsigned long flags; + trace_amdgpu_pasid_freed(pasid); - spin_lock(&amdgpu_pasid_idr_lock); - idr_remove(&amdgpu_pasid_idr, pasid); - spin_unlock(&amdgpu_pasid_idr_lock); + xa_lock_irqsave(&amdgpu_pasid_xa, flags); + __xa_erase(&amdgpu_pasid_xa, pasid); + xa_unlock_irqrestore(&amdgpu_pasid_xa, flags); } static void amdgpu_pasid_free_cb(struct dma_fence *fence, @@ -634,7 +635,5 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev) */ void amdgpu_pasid_mgr_cleanup(void) { - spin_lock(&amdgpu_pasid_idr_lock); - idr_destroy(&amdgpu_pasid_idr); - spin_unlock(&amdgpu_pasid_idr_lock); + xa_destroy(&amdgpu_pasid_xa); } -- cgit v1.2.3 From d65bfb1782304b03862c8c725fac608015dffd36 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Sat, 21 Mar 2026 06:20:33 +0100 Subject: drm/amd/display: Change dither policy for 10 bpc output back to dithering Commit d5df648ec830 ("drm/amd/display: Change dither policy for 10bpc to round") degraded display of 12 bpc color precision output to 10 bpc sinks by switching 10 bpc output from dithering to "truncate to 10 bpc". I don't find the argumentation in that commit convincing, but the consequences highly unfortunate, especially for applications that require effective > 10 bpc precision output of > 10 bpc framebuffers. The argument wasn't something strong like "there are hardware design defects or limitations which require us to work around broken dithering to 10 bpc", or "there are some special use cases which do require truncation to 10 bpc", but essentially "at some point in the past we used truncation in Polaris/Vega times and it looks like it got inadvertently changed for Navi, so let's do that again". I couldn't find evidence for that in the git commit logs for this. The commit message also acknowledges that using dithering "...makes some sense for FP16... ...but not for ARGB2101010 surfaces..." The problem with this is that it makes fp16 surfaces, and especially rgba16 fixed point surfaces, less useful. These are now well supported by Mesa 25.3 and later via OpenGL + EGL, Vulkan/WSI, and by OSS AMDVLK Vulkan/WSI/display, and also by GNOME 50 mutter under Wayland, and they used to provide more than 10 bpc effective precision at the output. Even for 8 or 10 bpc surfaces, the color pipeline behind the framebuffer, e.g., gamma tables, CTM, can be used for color correction and will benefit from an effective > 10 bpc output precision via dithering, retaining some precision that would get lost on the way through the pipeline, e.g., due to non-linear gamma functions. Scientific apps rely on this for > 10 bpc display precision. Truncating to 10 bpc, instead of dithering the pipeline internal 12 bpc precision down to 10 bpc, causes a serious loss of precision. This also creates the undesirable and slightly absurd situation that using a cheap monitor with only 8 bpc input and display panel will yield roughly 12 bpc precision via dithering from 12 -> 8 bpc, whereas investment into a more expensive monitor with 10 bpc input and native 10 bpc display will only yield 10 bpc, even if a fp16 or rgb16 framebuffer and/or a properly set up color pipeline (gamma tables, CTM's etc. with more than 10 bpc out precision) would allow effective 12 bpc precision output. Therefore this patch proposes reverting that commit and going back to dithering down to 10 bpc, consistent with the behaviour for 6 bpc or 8 bpc output. Successfully tested on AMD Polaris DCE 11.2 and Raven Ridge DCN 1.0 with a native 10 bpc capable monitor, outputting a RGBA16 unorm framebuffer and measuring resulting color precision with a photometer. No apparent visual artifacts or problems were observed, and effective precision was measured to be 12 bpc again, as expected. Fixes: d5df648ec830 ("drm/amd/display: Change dither policy for 10bpc to round") Signed-off-by: Mario Kleiner Tested-by: Mario Kleiner Cc: stable@vger.kernel.org Cc: Aric Cyr Cc: Anthony Koo Cc: Rodrigo Siqueira Cc: Krunoslav Kovac Cc: Alex Deucher Reported-by: Mario Kleiner Signed-off-by: Harry Wentland Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 66597a1f5b78..00b894602423 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -5062,7 +5062,7 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, option = DITHER_OPTION_SPATIAL8; break; case COLOR_DEPTH_101010: - option = DITHER_OPTION_TRUN10; + option = DITHER_OPTION_SPATIAL10; break; default: option = DITHER_OPTION_DISABLE; -- cgit v1.2.3 From 1e57e72ae3c34144ccecb0a0b77e5c397ec0668a Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 26 Mar 2026 12:59:31 +0530 Subject: drm/amdgpu/userq: fence wait for max time in amdgpu_userq_wait_for_signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wait for infinite time for fences in function amdgpu_userq_wait_for_signal and for that use dma_fence_wait(f, false); Suggested-by: Christian König Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 744095d42fd0..4323fd4c7fe1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1280,29 +1280,20 @@ void amdgpu_userq_reset_work(struct work_struct *work) amdgpu_device_gpu_recover(adev, NULL, &reset_context); } -static int +static void amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) { struct amdgpu_usermode_queue *queue; unsigned long queue_id; - int ret; xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { struct dma_fence *f = queue->last_fence; - if (!f || dma_fence_is_signaled(f)) + if (!f) continue; - ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100)); - if (ret <= 0) { - drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n", - f->context, f->seqno); - - return -ETIMEDOUT; - } + dma_fence_wait(f, false); } - - return 0; } void -- cgit v1.2.3 From 4c86e12ab1be971ddb0748e373cf6d25d68bdc22 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 26 Mar 2026 13:06:07 +0530 Subject: drm/amdgpu/userq: add the return code too in error condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function amdgpu_userq_restore a. amdgpu_userq_vm_validate: add return code in error condition b. amdgpu_userq_restore_all: It already prints the error log, just update the erorr log in the function and remove it from caller. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 4323fd4c7fe1..999d8e298bce 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1023,7 +1023,8 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) mutex_unlock(&uq_mgr->userq_mutex); if (ret) - drm_file_err(uq_mgr->file, "Failed to map all the queues\n"); + drm_file_err(uq_mgr->file, + "Failed to map all the queues, restore failed ret=%d\n", ret); return ret; } @@ -1230,13 +1231,11 @@ static void amdgpu_userq_restore_worker(struct work_struct *work) ret = amdgpu_userq_vm_validate(uq_mgr); if (ret) { - drm_file_err(uq_mgr->file, "Failed to validate BOs to restore\n"); + drm_file_err(uq_mgr->file, "Failed to validate BOs to restore ret=%d\n", ret); goto put_fence; } - ret = amdgpu_userq_restore_all(uq_mgr); - if (ret) - drm_file_err(uq_mgr->file, "Failed to restore all queues\n"); + amdgpu_userq_restore_all(uq_mgr); put_fence: dma_fence_put(ev_fence); -- cgit v1.2.3 From 38476bde59948fe85e20bb1e7f3f66525d0c10cd Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 26 Mar 2026 13:22:20 +0530 Subject: drm/amdgpu/userq: call dma_resv_wait_timeout without test for signalled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function amdgpu_userq_gem_va_unmap_validate call dma_resv_wait_timeout directly. Also since we are waiting forever we should not be having any return value and hence no handling needed. Suggested-by: Christian König Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 19 ++++++------------- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 6 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 9 ++------- 3 files changed, 11 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 999d8e298bce..14e590cab2b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1462,17 +1462,16 @@ int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev, return ret; } -int amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev, - struct amdgpu_bo_va_mapping *mapping, - uint64_t saddr) +void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev, + struct amdgpu_bo_va_mapping *mapping, + uint64_t saddr) { u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev); struct amdgpu_bo_va *bo_va = mapping->bo_va; struct dma_resv *resv = bo_va->base.bo->tbo.base.resv; - int ret = 0; if (!ip_mask) - return 0; + return; dev_warn_once(adev->dev, "now unmapping a vital queue va:%llx\n", saddr); /** @@ -1483,14 +1482,8 @@ int amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev, * unmap is only for one kind of userq VAs, so at this point suppose * the eviction fence is always unsignaled. */ - if (!dma_resv_test_signaled(resv, DMA_RESV_USAGE_BOOKKEEP)) { - ret = dma_resv_wait_timeout(resv, DMA_RESV_USAGE_BOOKKEEP, true, - MAX_SCHEDULE_TIMEOUT); - if (ret <= 0) - return -EBUSY; - } - - return 0; + dma_resv_wait_timeout(resv, DMA_RESV_USAGE_BOOKKEEP, + false, MAX_SCHEDULE_TIMEOUT); } void amdgpu_userq_pre_reset(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index a4d44abf24fa..675fe6395ac8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -160,7 +160,7 @@ void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue); int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, struct amdgpu_usermode_queue *queue, u64 addr, u64 expected_size); -int amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev, - struct amdgpu_bo_va_mapping *mapping, - uint64_t saddr); +void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev, + struct amdgpu_bo_va_mapping *mapping, + uint64_t saddr); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 73abac6be5b3..00a532f4e027 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1978,7 +1978,6 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, struct amdgpu_bo_va_mapping *mapping; struct amdgpu_vm *vm = bo_va->base.vm; bool valid = true; - int r; saddr /= AMDGPU_GPU_PAGE_SIZE; @@ -2003,12 +2002,8 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, * during user requests GEM unmap IOCTL except for forcing the unmap * from user space. */ - if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0)) { - r = amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr); - if (unlikely(r == -EBUSY)) - dev_warn_once(adev->dev, - "Attempt to unmap an active userq buffer\n"); - } + if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0)) + amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr); list_del(&mapping->list); amdgpu_vm_it_remove(mapping, &vm->va); -- cgit v1.2.3 From 05ce444171cf2ec89ce0f8c37700375b817454b0 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 26 Mar 2026 22:50:56 +0530 Subject: drm/amdgpu/userq: use dma_fence_wait_timeout without test for signalled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In function amdgpu_userq_wait_for_last_fence use dma_fence_wait to wait infinitely. Also there is no need to print error as we wont be timing out anymore. Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 14e590cab2b3..093a49f82fa2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -427,23 +427,14 @@ static int amdgpu_userq_map_helper(struct amdgpu_usermode_queue *queue) return r; } -static int amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue) +static void amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue) { - struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr; struct dma_fence *f = queue->last_fence; - int ret = 0; - if (f && !dma_fence_is_signaled(f)) { - ret = dma_fence_wait_timeout(f, true, MAX_SCHEDULE_TIMEOUT); - if (ret <= 0) { - drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n", - f->context, f->seqno); - queue->state = AMDGPU_USERQ_STATE_HUNG; - return -ETIME; - } - } + if (!f) + return; - return ret; + dma_fence_wait(f, false); } static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue) -- cgit v1.2.3 From 34f31fe40f3a19cd3427130ac7558ca2504853ae Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Tue, 17 Mar 2026 11:54:55 +0100 Subject: drm/amdgpu: rework userq fence driver alloc/destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The correct fix is to tie the global xa entry lifetime to the queue lifetime: insert in amdgpu_userq_create() and erase in amdgpu_userq_cleanup(), both at the well-defined doorbell_index key, making the operation O(1) and resolve the fence driver UAF problem by binding the userq driver fence to per queue. v2: clean up the local variables initialization. (Christian) Signed-off-by: Prike Liang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 ----- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 +--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 20 +------------------- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 10 +++++----- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 10 +++++----- drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 11 ++++++----- drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 10 +++++----- drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 10 +++++----- 8 files changed, 28 insertions(+), 52 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 49e7881750fa..8bc591deb546 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1045,11 +1045,6 @@ struct amdgpu_device { struct amdgpu_mqd mqds[AMDGPU_HW_IP_NUM]; const struct amdgpu_userq_funcs *userq_funcs[AMDGPU_HW_IP_NUM]; - /* xarray used to retrieve the user queue fence driver reference - * in the EOP interrupt handler to signal the particular user - * queue fence. - */ - struct xarray userq_xa; /** * @userq_doorbell_xa: Global user queue map (doorbell index → queue) * Key: doorbell_index (unique global identifier for the queue) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 824ac0a0549f..584c9ec28bf1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3757,15 +3757,13 @@ int amdgpu_device_init(struct amdgpu_device *adev, spin_lock_init(&adev->virt.rlcg_reg_lock); spin_lock_init(&adev->wb.lock); - xa_init_flags(&adev->userq_xa, XA_FLAGS_LOCK_IRQ); - INIT_LIST_HEAD(&adev->reset_list); INIT_LIST_HEAD(&adev->ras_list); INIT_LIST_HEAD(&adev->pm.od_kobj_list); - xa_init(&adev->userq_doorbell_xa); + xa_init_flags(&adev->userq_doorbell_xa, XA_FLAGS_LOCK_IRQ); INIT_DELAYED_WORK(&adev->delayed_init_work, amdgpu_device_delayed_init_work_handler); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index fe6d83e859a0..5e1336e993e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -81,7 +81,6 @@ int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev, struct amdgpu_usermode_queue *userq) { struct amdgpu_userq_fence_driver *fence_drv; - unsigned long flags; int r; fence_drv = kzalloc_obj(*fence_drv); @@ -104,19 +103,10 @@ int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev, fence_drv->context = dma_fence_context_alloc(1); get_task_comm(fence_drv->timeline_name, current); - xa_lock_irqsave(&adev->userq_xa, flags); - r = xa_err(__xa_store(&adev->userq_xa, userq->doorbell_index, - fence_drv, GFP_KERNEL)); - xa_unlock_irqrestore(&adev->userq_xa, flags); - if (r) - goto free_seq64; - userq->fence_drv = fence_drv; return 0; -free_seq64: - amdgpu_seq64_free(adev, fence_drv->va); free_fence_drv: kfree(fence_drv); @@ -187,11 +177,9 @@ void amdgpu_userq_fence_driver_destroy(struct kref *ref) struct amdgpu_userq_fence_driver *fence_drv = container_of(ref, struct amdgpu_userq_fence_driver, refcount); - struct amdgpu_userq_fence_driver *xa_fence_drv; struct amdgpu_device *adev = fence_drv->adev; struct amdgpu_userq_fence *fence, *tmp; - struct xarray *xa = &adev->userq_xa; - unsigned long index, flags; + unsigned long flags; struct dma_fence *f; spin_lock_irqsave(&fence_drv->fence_list_lock, flags); @@ -208,12 +196,6 @@ void amdgpu_userq_fence_driver_destroy(struct kref *ref) } spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags); - xa_lock_irqsave(xa, flags); - xa_for_each(xa, index, xa_fence_drv) - if (xa_fence_drv == fence_drv) - __xa_erase(xa, index); - xa_unlock_irqrestore(xa, flags); - /* Free seq64 memory */ amdgpu_seq64_free(adev, fence_drv->va); kfree(fence_drv); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index ae39b9e1f7d6..5097de940a19 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -6502,14 +6502,14 @@ static int gfx_v11_0_eop_irq(struct amdgpu_device *adev, DRM_DEBUG("IH: CP EOP\n"); if (adev->enable_mes && doorbell_offset) { - struct amdgpu_userq_fence_driver *fence_drv = NULL; - struct xarray *xa = &adev->userq_xa; + struct amdgpu_usermode_queue *queue; + struct xarray *xa = &adev->userq_doorbell_xa; unsigned long flags; xa_lock_irqsave(xa, flags); - fence_drv = xa_load(xa, doorbell_offset); - if (fence_drv) - amdgpu_userq_fence_driver_process(fence_drv); + queue = xa_load(xa, doorbell_offset); + if (queue) + amdgpu_userq_fence_driver_process(queue->fence_drv); xa_unlock_irqrestore(xa, flags); } else { me_id = (entry->ring_id & 0x0c) >> 2; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index a418ae609c36..65c33823a688 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -4854,14 +4854,14 @@ static int gfx_v12_0_eop_irq(struct amdgpu_device *adev, DRM_DEBUG("IH: CP EOP\n"); if (adev->enable_mes && doorbell_offset) { - struct amdgpu_userq_fence_driver *fence_drv = NULL; - struct xarray *xa = &adev->userq_xa; + struct xarray *xa = &adev->userq_doorbell_xa; + struct amdgpu_usermode_queue *queue; unsigned long flags; xa_lock_irqsave(xa, flags); - fence_drv = xa_load(xa, doorbell_offset); - if (fence_drv) - amdgpu_userq_fence_driver_process(fence_drv); + queue = xa_load(xa, doorbell_offset); + if (queue) + amdgpu_userq_fence_driver_process(queue->fence_drv); xa_unlock_irqrestore(xa, flags); } else { me_id = (entry->ring_id & 0x0c) >> 2; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c index db49582a211f..68fd3c04134d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c @@ -3643,14 +3643,15 @@ static int gfx_v12_1_eop_irq(struct amdgpu_device *adev, DRM_DEBUG("IH: CP EOP\n"); if (adev->enable_mes && doorbell_offset) { - struct amdgpu_userq_fence_driver *fence_drv = NULL; - struct xarray *xa = &adev->userq_xa; + struct xarray *xa = &adev->userq_doorbell_xa; + struct amdgpu_usermode_queue *queue; unsigned long flags; xa_lock_irqsave(xa, flags); - fence_drv = xa_load(xa, doorbell_offset); - if (fence_drv) - amdgpu_userq_fence_driver_process(fence_drv); + queue = xa_load(xa, doorbell_offset); + if (queue) + amdgpu_userq_fence_driver_process(queue->fence_drv); + xa_unlock_irqrestore(xa, flags); } else { me_id = (entry->ring_id & 0x0c) >> 2; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index b005672f2f96..0f530bb8a9a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -1662,16 +1662,16 @@ static int sdma_v6_0_process_fence_irq(struct amdgpu_device *adev, u32 doorbell_offset = entry->src_data[0]; if (adev->enable_mes && doorbell_offset) { - struct amdgpu_userq_fence_driver *fence_drv = NULL; - struct xarray *xa = &adev->userq_xa; + struct amdgpu_usermode_queue *queue; + struct xarray *xa = &adev->userq_doorbell_xa; unsigned long flags; doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; xa_lock_irqsave(xa, flags); - fence_drv = xa_load(xa, doorbell_offset); - if (fence_drv) - amdgpu_userq_fence_driver_process(fence_drv); + queue = xa_load(xa, doorbell_offset); + if (queue) + amdgpu_userq_fence_driver_process(queue->fence_drv); xa_unlock_irqrestore(xa, flags); } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c index 5679a94d0815..9ed817b69a3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c @@ -1594,16 +1594,16 @@ static int sdma_v7_0_process_fence_irq(struct amdgpu_device *adev, u32 doorbell_offset = entry->src_data[0]; if (adev->enable_mes && doorbell_offset) { - struct amdgpu_userq_fence_driver *fence_drv = NULL; - struct xarray *xa = &adev->userq_xa; + struct xarray *xa = &adev->userq_doorbell_xa; + struct amdgpu_usermode_queue *queue; unsigned long flags; doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT; xa_lock_irqsave(xa, flags); - fence_drv = xa_load(xa, doorbell_offset); - if (fence_drv) - amdgpu_userq_fence_driver_process(fence_drv); + queue = xa_load(xa, doorbell_offset); + if (queue) + amdgpu_userq_fence_driver_process(queue->fence_drv); xa_unlock_irqrestore(xa, flags); } -- cgit v1.2.3 From 48c33af0b62d8bbc67e4897438573f59da8ebe17 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Fri, 27 Mar 2026 14:33:31 +0800 Subject: drm/amdgpu: make userq fence_drv drop explicit in queue destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amdgpu_userq_fence_driver_free() is now responsible only for releasing per-queue ancillary state (last_fence, fence_drv_xa) and no longer touches the ownership reference, making each function's contract clear. v2: Get the userq fence driver from amdgpu_userq_fence_driver_alloc() directly and dropping the userq fence driver reference after removing userq_doorbell_xa entry.(Christian) Signed-off-by: Prike Liang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 5 +++-- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 12 ++++++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 093a49f82fa2..bfca5b040a32 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -449,9 +449,10 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue) /* Drop the userq reference. */ amdgpu_userq_buffer_vas_list_cleanup(adev, queue); uq_funcs->mqd_destroy(queue); - amdgpu_userq_fence_driver_free(queue); /* Use interrupt-safe locking since IRQ handlers may access these XArrays */ xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index); + amdgpu_userq_fence_driver_free(queue); + queue->fence_drv = NULL; queue->userq_mgr = NULL; list_del(&queue->userq_va_list); kfree(queue); @@ -790,7 +791,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) queue->doorbell_index = index; xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC); - r = amdgpu_userq_fence_driver_alloc(adev, queue); + r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv); if (r) { drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n"); goto free_queue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 5e1336e993e0..5784f2b3ecae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -78,11 +78,15 @@ amdgpu_userq_fence_write(struct amdgpu_userq_fence_driver *fence_drv, } int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev, - struct amdgpu_usermode_queue *userq) + struct amdgpu_userq_fence_driver **fence_drv_req) { struct amdgpu_userq_fence_driver *fence_drv; int r; + if (!fence_drv_req) + return -EINVAL; + *fence_drv_req = NULL; + fence_drv = kzalloc_obj(*fence_drv); if (!fence_drv) return -ENOMEM; @@ -103,7 +107,7 @@ int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev, fence_drv->context = dma_fence_context_alloc(1); get_task_comm(fence_drv->timeline_name, current); - userq->fence_drv = fence_drv; + *fence_drv_req = fence_drv; return 0; @@ -134,10 +138,10 @@ void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) { dma_fence_put(userq->last_fence); - + userq->last_fence = NULL; amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa); xa_destroy(&userq->fence_drv_xa); - /* Drop the fence_drv reference held by user queue */ + /* Drop the queue's ownership reference to fence_drv explicitly */ amdgpu_userq_fence_driver_put(userq->fence_drv); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h index d76add2afc77..d56246ad8c26 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h @@ -64,7 +64,7 @@ void amdgpu_userq_fence_slab_fini(void); void amdgpu_userq_fence_driver_get(struct amdgpu_userq_fence_driver *fence_drv); void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv); int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev, - struct amdgpu_usermode_queue *userq); + struct amdgpu_userq_fence_driver **fence_drv_req); void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq); void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv); void amdgpu_userq_fence_driver_force_completion(struct amdgpu_usermode_queue *userq); -- cgit v1.2.3 From eea85914d15bfe3bdf9f8f80a479f0dee0aa7d73 Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Wed, 4 Feb 2026 13:11:47 +0100 Subject: drm/amdgpu: save ring content before resetting the device Otherwise the content might not be relevant. When a coredump is generated the rings with outstanding fences are saved and then printed to the final devcoredump from the worker thread. Since this requires memory allocation, the ring capture might be missing from the generated devcoredump. Signed-off-by: Pierre-Eric Pelloux-Prayer Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 86 +++++++++++++++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 12 ++++ 2 files changed, 80 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index fddf4e1252bd..f54231005f51 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -214,7 +214,9 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf struct drm_print_iterator iter; struct amdgpu_vm_fault_info *fault_info; struct amdgpu_ip_block *ip_block; - int ver; + struct amdgpu_ring *ring; + int ver, i, j; + u32 ring_idx, off; iter.data = buffer; iter.offset = 0; @@ -303,23 +305,25 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf /* Add ring buffer information */ drm_printf(&p, "Ring buffer information\n"); - for (int i = 0; i < coredump->adev->num_rings; i++) { - int j = 0; - struct amdgpu_ring *ring = coredump->adev->rings[i]; - - drm_printf(&p, "ring name: %s\n", ring->name); - drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n", - amdgpu_ring_get_rptr(ring), - amdgpu_ring_get_wptr(ring), - ring->buf_mask); - drm_printf(&p, "Ring size in dwords: %d\n", - ring->ring_size / 4); - drm_printf(&p, "Ring contents\n"); - drm_printf(&p, "Offset \t Value\n"); - - while (j < ring->ring_size) { - drm_printf(&p, "0x%x \t 0x%x\n", j, ring->ring[j / 4]); - j += 4; + if (coredump->num_rings) { + for (i = 0; i < coredump->num_rings; i++) { + ring_idx = coredump->rings[i].ring_index; + ring = coredump->adev->rings[ring_idx]; + off = coredump->rings[i].offset; + + drm_printf(&p, "ring name: %s\n", ring->name); + drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n", + coredump->rings[i].rptr, + coredump->rings[i].wptr, + ring->buf_mask); + drm_printf(&p, "Ring size in dwords: %d\n", + ring->ring_size / 4); + drm_printf(&p, "Ring contents\n"); + drm_printf(&p, "Offset \t Value\n"); + + for (j = 0; j < ring->ring_size; j += 4) + drm_printf(&p, "0x%x \t 0x%x\n", j, + coredump->rings_dw[off + j / 4]); } } @@ -359,6 +363,8 @@ static void amdgpu_devcoredump_free(void *data) struct amdgpu_coredump_info *coredump = data; kvfree(coredump->formatted); + kvfree(coredump->rings); + kvfree(coredump->rings_dw); kvfree(data); } @@ -396,6 +402,9 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, struct drm_device *dev = adev_to_drm(adev); struct amdgpu_coredump_info *coredump; struct drm_sched_job *s_job; + u64 total_ring_size, ring_count; + struct amdgpu_ring *ring; + int i, off, idx; /* No need to generate a new coredump if there's one in progress already. */ if (work_pending(&adev->coredump_work)) @@ -423,6 +432,47 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, coredump->ring = to_amdgpu_ring(s_job->sched); } + /* Dump ring content if memory allocation succeeds. */ + ring_count = 0; + total_ring_size = 0; + for (i = 0; i < adev->num_rings; i++) { + ring = adev->rings[i]; + + /* Only dump rings with unsignalled fences. */ + if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq && + coredump->ring != ring) + continue; + + total_ring_size += ring->ring_size; + ring_count++; + } + coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT); + coredump->rings = kcalloc(ring_count, sizeof(struct amdgpu_coredump_ring), GFP_NOWAIT); + if (coredump->rings && coredump->rings_dw) { + for (i = 0, off = 0, idx = 0; i < adev->num_rings; i++) { + ring = adev->rings[i]; + + if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq && + coredump->ring != ring) + continue; + + coredump->rings[idx].ring_index = ring->idx; + coredump->rings[idx].rptr = amdgpu_ring_get_rptr(ring); + coredump->rings[idx].wptr = amdgpu_ring_get_wptr(ring); + coredump->rings[idx].offset = off; + + memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size); + off += ring->ring_size; + idx++; + } + coredump->num_rings = idx; + } else { + kvfree(coredump->rings_dw); + kvfree(coredump->rings); + coredump->rings_dw = NULL; + coredump->rings = NULL; + } + coredump->adev = adev; ktime_get_ts64(&coredump->reset_time); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h index f8f2f4df129b..d65e59050293 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h @@ -31,6 +31,13 @@ #define AMDGPU_COREDUMP_VERSION "1" +struct amdgpu_coredump_ring { + u64 rptr; + u64 wptr; + u32 ring_index; + u32 offset; +}; + struct amdgpu_coredump_info { struct amdgpu_device *adev; struct amdgpu_task_info reset_task_info; @@ -39,6 +46,11 @@ struct amdgpu_coredump_info { bool skip_vram_check; bool reset_vram_lost; struct amdgpu_ring *ring; + + struct amdgpu_coredump_ring *rings; + u32 *rings_dw; + u32 num_rings; + /* Readable form of coredevdump, generate once to speed up * reading it (see drm_coredump_printer's documentation). */ -- cgit v1.2.3 From 2d23661764450fc37208c2888c91fa320e830d63 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Fri, 3 Apr 2026 10:22:06 +0200 Subject: drm/amd/display: Replace inline NUM_ELEMENTS macro with ARRAY_SIZE Replaces the use of local NUM_ELEMENTS macro with the ARRAY_SIZE macro defined in . This aligns with existing coccinelle script array_size.cocci which has been applied to other sources in order to remove inline sizeof(a)/sizeof(a[0]) patterns from other source files. Suggested-by: Robert P. J. Day Signed-off-by: Linus Probert Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 5 +++-- drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index db86e346307c..952968ecd46e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -23,6 +23,8 @@ * */ +#include + #include "dm_services.h" #include "core_types.h" #include "timing_generator.h" @@ -40,7 +42,6 @@ #include "dcn10/dcn10_hubbub.h" #include "dce/dmub_hw_lock_mgr.h" -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) #define MAX_NUM_MCACHE 8 /* used as index in array of black_color_format */ @@ -230,7 +231,7 @@ const uint16_t *find_color_matrix(enum dc_color_space color_space, int i; enum dc_color_space_type type; const uint16_t *val = NULL; - int arr_size = NUM_ELEMENTS(output_csc_matrix); + int arr_size = ARRAY_SIZE(output_csc_matrix); type = get_color_space_type(color_space); for (i = 0; i < arr_size; i++) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 34e54fdb9d13..71a876e3dfd4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -23,6 +23,8 @@ * */ +#include + #include "dm_services.h" @@ -57,8 +59,6 @@ #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) - static const struct spread_spectrum_data *get_ss_data_entry( struct dce110_clk_src *clk_src, enum signal_type signal, @@ -1271,7 +1271,7 @@ const struct pixel_rate_range_table_entry *look_up_in_video_optimized_rate_tlb( { int i; - for (i = 0; i < NUM_ELEMENTS(video_optimized_pixel_rates); i++) { + for (i = 0; i < ARRAY_SIZE(video_optimized_pixel_rates); i++) { const struct pixel_rate_range_table_entry *e = &video_optimized_pixel_rates[i]; if (e->range_min_khz <= pixel_rate_khz && pixel_rate_khz <= e->range_max_khz) { -- cgit v1.2.3 From a097dd7059cb1d4efb436092196885e3abd56518 Mon Sep 17 00:00:00 2001 From: Linus Probert Date: Fri, 3 Apr 2026 10:22:07 +0200 Subject: drm/amd/display: Remove unused NUM_ELEMENTS macros Removes unused NUM_ELEMENTS macros. Discovered while removing cases where ARRAY_SIZE from the header can be used. This also aligns with the array_size.cocci coccinelle check. Suggested-by: Robert P. J. Day Signed-off-by: Linus Probert Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c | 3 --- drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c | 3 --- drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c | 2 -- drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c | 4 ---- 4 files changed, 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c index f8f6019d8304..2bdd063cc1e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c @@ -49,9 +49,6 @@ #define FN(reg_name, field_name) \ dpp->tf_shift->field_name, dpp->tf_mask->field_name -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) - - enum dcn10_coef_filter_type_sel { SCL_COEF_LUMA_VERT_FILTER = 0, SCL_COEF_LUMA_HORZ_FILTER = 1, diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c index 821d5173b59f..4f3b48ed8679 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c @@ -49,9 +49,6 @@ #define FN(reg_name, field_name) \ dpp->tf_shift->field_name, dpp->tf_mask->field_name -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) - - enum dcn401_coef_filter_type_sel { SCL_COEF_LUMA_VERT_FILTER = 0, SCL_COEF_LUMA_HORZ_FILTER = 1, diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c index ea73473b970a..fa600593f4c1 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c @@ -43,8 +43,6 @@ #define FN(reg_name, field_name) \ mpc20->mpc_shift->field_name, mpc20->mpc_mask->field_name -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) - void mpc2_update_blending( struct mpc *mpc, struct mpcc_blnd_cfg *blnd_cfg, diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c index 4c7bb0522a8c..4e91e9f6f11a 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c @@ -40,10 +40,6 @@ #define FN(reg_name, field_name) \ mpc30->mpc_shift->field_name, mpc30->mpc_mask->field_name - -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) - - void mpc3_mpc_init(struct mpc *mpc) { struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); -- cgit v1.2.3 From d1f188b182c92b71d1bdd03436d7c6b08fbc86be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Fri, 3 Apr 2026 04:22:08 +0200 Subject: drm/amdgpu: Use amdgpu by default for CIK APUs too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CIK APUs are: Kaveri, Kabini and Mullins from 2013~2015, which all have a second generation GCN based integrated GPU. The amdgpu driver has been working well on CIK APUs for years. Features which were previously missing have been added recently, specifically DC support for analog connectors and DP bridge encoders. Now amdgpu is at feature parity with the old radeon driver on CIK APUs. Enabling the amdgpu driver by default for CIK APUs has the following benefits: - More stable OpenGL support through RadeonSI - Vulkan support through RADV - Improved performance - Better display features through DC Users who want to keep using the old driver can do so using: amdgpu.cik_support=0 radeon.cik_support=1 Signed-off-by: Timur Kristóf Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 7 ++----- drivers/gpu/drm/radeon/radeon_drv.c | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 8ed637f92322..e47921e2a9af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -641,9 +641,7 @@ module_param_named(si_support, amdgpu_si_support, int, 0444); * CIK (Sea Islands) are second generation GCN GPUs, supported by both * drivers: radeon (old) and amdgpu (new). This parameter controls whether * amdgpu should support CIK. - * By default: - * - CIK dedicated GPUs are supported by amdgpu. - * - CIK APUs are supported by radeon (except when radeon is not built). + * By default, CIK dedicated GPUs and APUs are supported by amdgpu. * Only relevant when CONFIG_DRM_AMDGPU_CIK is enabled to build CIK support in amdgpu. * See also radeon.cik_support which should be disabled when amdgpu.cik_support is * enabled, and vice versa. @@ -2323,8 +2321,6 @@ static bool amdgpu_support_enabled(struct device *dev, case CHIP_BONAIRE: case CHIP_HAWAII: - support_by_default = true; - fallthrough; case CHIP_KAVERI: case CHIP_KABINI: case CHIP_MULLINS: @@ -2332,6 +2328,7 @@ static bool amdgpu_support_enabled(struct device *dev, param = "cik_support"; module_param = amdgpu_cik_support; amdgpu_support_built = IS_ENABLED(CONFIG_DRM_AMDGPU_CIK); + support_by_default = true; break; default: diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 87fd6255c114..53d06053dec8 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -278,14 +278,13 @@ static bool radeon_support_enabled(struct device *dev, case CHIP_BONAIRE: case CHIP_HAWAII: - support_by_default = false; - fallthrough; case CHIP_KAVERI: case CHIP_KABINI: case CHIP_MULLINS: gen = "CIK"; module_param = radeon_cik_support; amdgpu_support_built &= IS_ENABLED(CONFIG_DRM_AMDGPU_CIK); + support_by_default = false; break; default: -- cgit v1.2.3 From 1b135c6da061cdb3322dc0e92ca5a7c58825c77b Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Wed, 4 Feb 2026 16:41:11 +0100 Subject: drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault This is tricky to implement right and we're going to need it from the devcoredump. Signed-off-by: Pierre-Eric Pelloux-Prayer Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 80 ++++++++++++++++++++++------------ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 3 ++ 2 files changed, 54 insertions(+), 29 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 00a532f4e027..115a7b269af3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2949,6 +2949,50 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return 0; } +/** + * amdgpu_vm_lock_by_pasid - return an amdgpu_vm and its root bo from a pasid, if possible. + * @adev: amdgpu device pointer + * @root: root BO of the VM + * @pasid: PASID of the VM + * The caller needs to unreserve and unref the root bo on success. + */ +struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev, + struct amdgpu_bo **root, u32 pasid) +{ + unsigned long irqflags; + struct amdgpu_vm *vm; + int r; + + xa_lock_irqsave(&adev->vm_manager.pasids, irqflags); + vm = xa_load(&adev->vm_manager.pasids, pasid); + *root = vm ? amdgpu_bo_ref(vm->root.bo) : NULL; + xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags); + + if (!*root) + return NULL; + + r = amdgpu_bo_reserve(*root, true); + if (r) + goto error_unref; + + /* Double check that the VM still exists */ + xa_lock_irqsave(&adev->vm_manager.pasids, irqflags); + vm = xa_load(&adev->vm_manager.pasids, pasid); + if (vm && vm->root.bo != *root) + vm = NULL; + xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags); + if (!vm) + goto error_unlock; + + return vm; +error_unlock: + amdgpu_bo_unreserve(*root); + +error_unref: + amdgpu_bo_unref(root); + return NULL; +} + /** * amdgpu_vm_handle_fault - graceful handling of VM faults. * @adev: amdgpu device pointer @@ -2964,50 +3008,29 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) * shouldn't be reported any more. */ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid, - u32 vmid, u32 node_id, uint64_t addr, uint64_t ts, - bool write_fault) + u32 vmid, u32 node_id, uint64_t addr, + uint64_t ts, bool write_fault) { bool is_compute_context = false; struct amdgpu_bo *root; - unsigned long irqflags; uint64_t value, flags; struct amdgpu_vm *vm; int r; - xa_lock_irqsave(&adev->vm_manager.pasids, irqflags); - vm = xa_load(&adev->vm_manager.pasids, pasid); - if (vm) { - root = amdgpu_bo_ref(vm->root.bo); - is_compute_context = vm->is_compute_context; - } else { - root = NULL; - } - xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags); - - if (!root) + vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid); + if (!vm) return false; + is_compute_context = vm->is_compute_context; + if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid, node_id, addr >> PAGE_SHIFT, ts, write_fault)) { + amdgpu_bo_unreserve(root); amdgpu_bo_unref(&root); return true; } addr /= AMDGPU_GPU_PAGE_SIZE; - - r = amdgpu_bo_reserve(root, true); - if (r) - goto error_unref; - - /* Double check that the VM still exists */ - xa_lock_irqsave(&adev->vm_manager.pasids, irqflags); - vm = xa_load(&adev->vm_manager.pasids, pasid); - if (vm && vm->root.bo != root) - vm = NULL; - xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags); - if (!vm) - goto error_unlock; - flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED | AMDGPU_PTE_SYSTEM; @@ -3046,7 +3069,6 @@ error_unlock: if (r < 0) dev_err(adev->dev, "Can't handle page fault (%d)\n", r); -error_unref: amdgpu_bo_unref(&root); return false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 3b32f41c3655..d083d7aab75c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -592,6 +592,9 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid, u32 vmid, u32 node_id, uint64_t addr, uint64_t ts, bool write_fault); +struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev, + struct amdgpu_bo **root, u32 pasid); + void amdgpu_vm_set_task_info(struct amdgpu_vm *vm); void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev, -- cgit v1.2.3 From 32ab301b89b30d71a2e68d86f564eca66f7c52c5 Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Wed, 4 Feb 2026 14:05:07 +0100 Subject: drm/amdgpu: store ib info for devcoredump Store the basic state of IBs so we can read it back in the amdgpu_devcoredump_format function. Signed-off-by: Pierre-Eric Pelloux-Prayer Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 12 +++++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index f54231005f51..f1b277902ff7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -401,6 +401,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, { struct drm_device *dev = adev_to_drm(adev); struct amdgpu_coredump_info *coredump; + size_t size = sizeof(*coredump); struct drm_sched_job *s_job; u64 total_ring_size, ring_count; struct amdgpu_ring *ring; @@ -410,12 +411,16 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, if (work_pending(&adev->coredump_work)) return; - coredump = kzalloc_obj(*coredump, GFP_NOWAIT); + if (job && job->pasid) + size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs; + + coredump = kzalloc(size, GFP_NOWAIT); if (!coredump) return; coredump->skip_vram_check = skip_vram_check; coredump->reset_vram_lost = vram_lost; + coredump->pasid = job->pasid; if (job && job->pasid) { struct amdgpu_task_info *ti; @@ -425,6 +430,11 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, coredump->reset_task_info = *ti; amdgpu_vm_put_task_info(ti); } + coredump->num_ibs = job->num_ibs; + for (i = 0; i < job->num_ibs; ++i) { + coredump->ibs[i].gpu_addr = job->ibs[i].gpu_addr; + coredump->ibs[i].ib_size_dw = job->ibs[i].length_dw; + } } if (job) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h index d65e59050293..2371e20fc68b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h @@ -38,6 +38,11 @@ struct amdgpu_coredump_ring { u32 offset; }; +struct amdgpu_coredump_ib_info { + uint64_t gpu_addr; + u32 ib_size_dw; +}; + struct amdgpu_coredump_info { struct amdgpu_device *adev; struct amdgpu_task_info reset_task_info; @@ -56,6 +61,10 @@ struct amdgpu_coredump_info { */ ssize_t formatted_size; char *formatted; + + unsigned int pasid; + int num_ibs; + struct amdgpu_coredump_ib_info ibs[] __counted_by(num_ibs); }; #endif -- cgit v1.2.3 From 7b15fc2d1f1a00fb99f0146e404ff2600999ec74 Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Wed, 4 Feb 2026 16:45:36 +0100 Subject: drm/amdgpu: dump job ibs in the devcoredump Now that we have a worker thread, we can try to access the IBs of the job. The process is: * get the VM from the PASID * get the BO from its VA and the VM * map the BO for CPU access * copy everything, then add it to the dump Each step can fail so we have to be cautious. These operations can be slow so when amdgpu_devcoredump_format is called only to determine the size of the buffer we skip all of them and assume they will succeed. --- v3: use kvfree --- Signed-off-by: Pierre-Eric Pelloux-Prayer Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 93 +++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index f1b277902ff7..3f1cc2265645 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -210,14 +210,24 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev, static ssize_t amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump) { + struct amdgpu_device *adev = coredump->adev; struct drm_printer p; struct drm_print_iterator iter; struct amdgpu_vm_fault_info *fault_info; + struct amdgpu_bo_va_mapping *mapping; struct amdgpu_ip_block *ip_block; + struct amdgpu_res_cursor cursor; + struct amdgpu_bo *abo, *root; + uint64_t va_start, offset; struct amdgpu_ring *ring; - int ver, i, j; + struct amdgpu_vm *vm; + u32 *ib_content; + uint8_t *kptr; + int ver, i, j, r; u32 ring_idx, off; + bool sizing_pass; + sizing_pass = buffer == NULL; iter.data = buffer; iter.offset = 0; iter.remain = count; @@ -332,6 +342,87 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf else if (coredump->reset_vram_lost) drm_printf(&p, "VRAM is lost due to GPU reset!\n"); + if (coredump->num_ibs) { + /* Don't try to lookup the VM or map the BOs when calculating the + * size required to store the devcoredump. + */ + if (sizing_pass) + vm = NULL; + else + vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid); + + for (int i = 0; i < coredump->num_ibs && (sizing_pass || vm); i++) { + ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4, + GFP_KERNEL); + if (!ib_content) + continue; + + /* vm=NULL can only happen when 'sizing_pass' is true. Skip to the + * drm_printf() calls (ib_content doesn't need to be initialized + * as its content won't be written anywhere). + */ + if (!vm) + goto output_ib_content; + + va_start = coredump->ibs[i].gpu_addr & AMDGPU_GMC_HOLE_MASK; + mapping = amdgpu_vm_bo_lookup_mapping(vm, va_start / AMDGPU_GPU_PAGE_SIZE); + if (!mapping) + goto free_ib_content; + + offset = va_start - (mapping->start * AMDGPU_GPU_PAGE_SIZE); + abo = amdgpu_bo_ref(mapping->bo_va->base.bo); + r = amdgpu_bo_reserve(abo, false); + if (r) + goto free_ib_content; + + if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) { + off = 0; + + if (abo->tbo.resource->mem_type != TTM_PL_VRAM) + goto unreserve_abo; + + amdgpu_res_first(abo->tbo.resource, offset, + coredump->ibs[i].ib_size_dw * 4, + &cursor); + while (cursor.remaining) { + amdgpu_device_mm_access(adev, cursor.start / 4, + &ib_content[off], cursor.size / 4, + false); + off += cursor.size; + amdgpu_res_next(&cursor, cursor.size); + } + } else { + r = ttm_bo_kmap(&abo->tbo, 0, + PFN_UP(abo->tbo.base.size), + &abo->kmap); + if (r) + goto unreserve_abo; + + kptr = amdgpu_bo_kptr(abo); + kptr += offset; + memcpy(ib_content, kptr, + coredump->ibs[i].ib_size_dw * 4); + + amdgpu_bo_kunmap(abo); + } + +output_ib_content: + drm_printf(&p, "\nIB #%d 0x%llx %d dw\n", + i, coredump->ibs[i].gpu_addr, coredump->ibs[i].ib_size_dw); + for (int j = 0; j < coredump->ibs[i].ib_size_dw; j++) + drm_printf(&p, "0x%08x\n", ib_content[j]); +unreserve_abo: + if (vm) + amdgpu_bo_unreserve(abo); +free_ib_content: + kvfree(ib_content); + } + if (vm) { + amdgpu_bo_unreserve(root); + amdgpu_bo_unref(&root); + } + } + return count - iter.remain; } -- cgit v1.2.3