[PATCH] drm/amd/pm: bump SMU v13.0.5 driver_if header version
Align the SMU driver interface version with PMFW to suppress the version mismatch message on driver loading. Signed-off-by: Tim Huang --- .../gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h index 7589faa0232d..779c2524806c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_5.h @@ -23,7 +23,7 @@ #ifndef __SMU13_DRIVER_IF_V13_0_5_H__ #define __SMU13_DRIVER_IF_V13_0_5_H__ -#define SMU13_0_5_DRIVER_IF_VERSION 4 +#define SMU13_0_5_DRIVER_IF_VERSION 5 // Throttler Status Bitmask #define THROTTLER_STATUS_BIT_SPL0 @@ -103,7 +103,6 @@ typedef struct { uint16_t ThrottlerStatus; uint16_t CurrentSocketPower; //[mW] - uint16_t spare1; } SmuMetrics_t; //Freq in MHz -- 2.34.1
[PATCH 3/4] drm/amdgpu: Add bootloader wait for PSP v13
Implement the wait for bootloader call back for PSP v13.0 ASICs. Only for ASICs with PSP v13.0.6, it needs an additional check for VBIOS mailbox status. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Reviewed-by: Asad Kamal Tested-by: Asad Kamal --- drivers/gpu/drm/amd/amdgpu/psp_v13_0.c | 28 -- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index 10b17bd5aebe..d2a88bc630d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -133,12 +133,35 @@ static bool psp_v13_0_is_sos_alive(struct psp_context *psp) return sol_reg != 0x0; } +static int psp_v13_0_wait_for_vmbx_ready(struct psp_context *psp) +{ + struct amdgpu_device *adev = psp->adev; + int retry_loop, ret; + + for (retry_loop = 0; retry_loop < 70; retry_loop++) { + /* Wait for bootloader to signify that is + ready having bit 31 of C2PMSG_33 set to 1 */ + ret = psp_wait_for( + psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_33), + 0x8000, 0x, false); + + if (ret == 0) + break; + } + + if (ret) + dev_warn(adev->dev, "Bootloader wait timed out"); + + return ret; +} + static int psp_v13_0_wait_for_bootloader(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; + int retry_loop, ret; - int ret; - int retry_loop; + if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 6)) + psp_v13_0_wait_for_vmbx_ready(psp); /* Wait for bootloader to signify that it is ready having bit 31 of * C2PMSG_35 set to 1. All other bits are expected to be cleared. @@ -714,6 +737,7 @@ static int psp_v13_0_fatal_error_recovery_quirk(struct psp_context *psp) static const struct psp_funcs psp_v13_0_funcs = { .init_microcode = psp_v13_0_init_microcode, + .wait_for_bootloader = psp_v13_0_wait_for_bootloader, .bootloader_load_kdb = psp_v13_0_bootloader_load_kdb, .bootloader_load_spl = psp_v13_0_bootloader_load_spl, .bootloader_load_sysdrv = psp_v13_0_bootloader_load_sysdrv, -- 2.25.1
[PATCH 4/4] drm/amdgpu: Add SMU v13.0.6 default reset methods
For APUs with SMU v13.0.6, mode-2 reset is kept as default and for others mode-1 is the default reset method. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Reviewed-by: Asad Kamal Tested-by: Asad Kamal --- drivers/gpu/drm/amd/amdgpu/soc15.c | 4 +++- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index c45721ca916e..f5be40d7ba36 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -559,8 +559,10 @@ soc15_asic_reset_method(struct amdgpu_device *adev) */ if (amdgpu_gpu_recovery == 4 || amdgpu_gpu_recovery == 5) return AMD_RESET_METHOD_MODE2; + else if (!(adev->flags & AMD_IS_APU)) + return AMD_RESET_METHOD_MODE1; else - return AMD_RESET_METHOD_NONE; + return AMD_RESET_METHOD_MODE2; default: break; } 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 362acbb242bb..552a739533ea 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 @@ -2096,8 +2096,7 @@ static int smu_v13_0_6_mode1_reset(struct smu_context *smu) static bool smu_v13_0_6_is_mode1_reset_supported(struct smu_context *smu) { - /* TODO: Enable this when FW support is added */ - return false; + return true; } static bool smu_v13_0_6_is_mode2_reset_supported(struct smu_context *smu) -- 2.25.1
[PATCH 2/4] drm/amdgpu: Add bootloader status check
Add a function to wait till bootloader has reached steady state. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Reviewed-by: Asad Kamal Tested-by: Asad Kamal --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 17 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c| 11 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h| 3 +++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 6809bf7dae57..9061d79cd387 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -885,13 +885,20 @@ static void amdgpu_block_invalid_wreg(struct amdgpu_device *adev, */ static int amdgpu_device_asic_init(struct amdgpu_device *adev) { + int ret; + amdgpu_asic_pre_asic_init(adev); if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 3) || - adev->ip_versions[GC_HWIP][0] >= IP_VERSION(11, 0, 0)) - return amdgpu_atomfirmware_asic_init(adev, true); - else + adev->ip_versions[GC_HWIP][0] >= IP_VERSION(11, 0, 0)) { + amdgpu_psp_wait_for_bootloader(adev); + ret = amdgpu_atomfirmware_asic_init(adev, true); + return ret; + } else { return amdgpu_atom_asic_init(adev->mode_info.atom_context); + } + + return 0; } /** @@ -4702,6 +4709,9 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev) dev_err(adev->dev, "GPU mode1 reset failed\n"); amdgpu_device_load_pci_state(adev->pdev); + ret = amdgpu_psp_wait_for_bootloader(adev); + if (ret) + return ret; /* wait for asic to come out of reset */ for (i = 0; i < adev->usec_timeout; i++) { @@ -4713,6 +4723,7 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev) } amdgpu_atombios_scratch_regs_engine_hung(adev, false); + return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 8fdca54bb8a1..429ef212c1f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -2078,6 +2078,17 @@ int psp_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id) } /* SECUREDISPLAY end */ +int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev) +{ + struct psp_context *psp = >psp; + int ret = 0; + + if (!amdgpu_sriov_vf(adev) && psp->funcs && psp->funcs->wait_for_bootloader != NULL) + ret = psp->funcs->wait_for_bootloader(psp); + + return ret; +} + static int psp_hw_start(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 3384eb94fde0..3e67ed63e638 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -109,6 +109,7 @@ enum psp_reg_prog_id { struct psp_funcs { int (*init_microcode)(struct psp_context *psp); + int (*wait_for_bootloader)(struct psp_context *psp); int (*bootloader_load_kdb)(struct psp_context *psp); int (*bootloader_load_spl)(struct psp_context *psp); int (*bootloader_load_sysdrv)(struct psp_context *psp); @@ -533,4 +534,6 @@ int psp_spatial_partition(struct psp_context *psp, int mode); int is_psp_fw_valid(struct psp_bin_desc bin); +int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev); + #endif -- 2.25.1
[PATCH 1/4] drm/amdgpu: Unset baco dummy mode on nbio v7.9
BACO dummy mode could be set under reset conditions and that affects framebuffer access. Check If baco dummy mode is set, unset it if so. Signed-off-by: Lijo Lazar Signed-off-by: Le Ma Reviewed-by: Hawking Zhang Reviewed-by: Asad Kamal Tested-by: Asad Kamal --- drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c index 9ea072374cb7..f85eec05d218 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c @@ -437,6 +437,24 @@ static void nbio_v7_9_init_registers(struct amdgpu_device *adev) XCC_DOORBELL_FENCE__SHUB_SLV_MODE_MASK); } + + if (!amdgpu_sriov_vf(adev)) { + u32 baco_cntl; + for_each_inst(i, adev->aid_mask) { + baco_cntl = RREG32_SOC15(NBIO, i, regBIF_BX0_BACO_CNTL); + if (baco_cntl & (BIF_BX0_BACO_CNTL__BACO_DUMMY_EN_MASK | +BIF_BX0_BACO_CNTL__BACO_EN_MASK)) { + baco_cntl &= ~( + BIF_BX0_BACO_CNTL__BACO_DUMMY_EN_MASK | + BIF_BX0_BACO_CNTL__BACO_EN_MASK); + dev_dbg(adev->dev, + "Unsetting baco dummy mode %x", + baco_cntl); + WREG32_SOC15(NBIO, i, regBIF_BX0_BACO_CNTL, +baco_cntl); + } + } + } } static u64 nbio_v7_9_get_pcie_replay_count(struct amdgpu_device *adev) -- 2.25.1
[PATCH 0/4] Add mode-1 reset support for SMU v13.0.6
The series adds mode-1 reset support to SMU v13.0.6 SOCs. For now, it's used as the default reset method on dGPUs with SMU v13.0.6. Presently, reset takes longer than expected. Hence a method is added to check the bootloader status after reset. It checks if bootloader has set mailbox ready bit which is an indication that boot loader has completed initialization. Lijo Lazar (4): drm/amdgpu: Unset baco dummy mode on nbio v7.9 drm/amdgpu: Add bootloader status check drm/amdgpu: Add bootloader wait for PSP v13 drm/amdgpu: Add SMU v13.0.6 default reset methods drivers/gpu/drm/amd/amdgpu/amdgpu_device.c| 17 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 11 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 3 ++ drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c| 18 drivers/gpu/drm/amd/amdgpu/psp_v13_0.c| 28 +-- drivers/gpu/drm/amd/amdgpu/soc15.c| 4 ++- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 3 +- 7 files changed, 76 insertions(+), 8 deletions(-) -- 2.25.1
RE: [PATCH] drm/amd/pm: add unique_id for gc 11.0.3
[AMD Official Use Only - General] Reviewed-by: Feifei Xu -Original Message- From: amd-gfx On Behalf Of Kenneth Feng Sent: Friday, August 11, 2023 12:28 PM To: amd-gfx@lists.freedesktop.org Cc: Feng, Kenneth Subject: [PATCH] drm/amd/pm: add unique_id for gc 11.0.3 drm/amd/pm: add unique_id for gc 11.0.3 Signed-off-by: Kenneth Feng --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 5aed023f7402..c69701da94ea 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2076,6 +2076,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): *states = ATTR_STATE_SUPPORTED; break; default: -- 2.34.1
[PATCH] drm/amd/pm: add unique_id for gc 11.0.3
drm/amd/pm: add unique_id for gc 11.0.3 Signed-off-by: Kenneth Feng --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 5aed023f7402..c69701da94ea 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2076,6 +2076,7 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): *states = ATTR_STATE_SUPPORTED; break; default: -- 2.34.1
[PATCH] drm/amdgpu: Add memory vendor information
For ASICs with GC v9.4.3, determine the vendor information from scratch register. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 26 ++ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 880460cd3239..f9a5a2c0573e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1998,6 +1998,19 @@ static int gmc_v9_0_init_mem_ranges(struct amdgpu_device *adev) return 0; } +static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev) +{ + static const u32 regBIF_BIOS_SCRATCH_4 = 0x50; + u32 vram_info; + + if (!amdgpu_sriov_vf(adev)) { + vram_info = RREG32(regBIF_BIOS_SCRATCH_4); + adev->gmc.vram_vendor = vram_info & 0xF; + } + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM; + adev->gmc.vram_width = 128 * 64; +} + static int gmc_v9_0_sw_init(void *handle) { int r, vram_width = 0, vram_type = 0, vram_vendor = 0, dma_addr_bits; @@ -2010,15 +2023,12 @@ static int gmc_v9_0_sw_init(void *handle) spin_lock_init(>gmc.invalidate_lock); - if (!(adev->bios) || adev->gmc.is_app_apu) { + if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 3)) { + gmc_v9_4_3_init_vram_info(adev); + } else if (!adev->bios) { if (adev->flags & AMD_IS_APU) { - if (adev->gmc.is_app_apu) { - adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM; - adev->gmc.vram_width = 128 * 64; - } else { - adev->gmc.vram_type = AMDGPU_VRAM_TYPE_DDR4; - adev->gmc.vram_width = 64 * 64; - } + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_DDR4; + adev->gmc.vram_width = 64 * 64; } else { adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM; adev->gmc.vram_width = 128 * 64; -- 2.25.1
[PATCH 9/9] drm/amd: Hide unsupported power attributes
Some ASICS only offer one type of power attribute, so in the visible callback check whether the attributes are supported and hide if not supported. Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 8133d968f75b9..5b1d73b00ef73 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -3179,6 +3179,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, struct amdgpu_device *adev = dev_get_drvdata(dev); umode_t effective_mode = attr->mode; uint32_t gc_ver = adev->ip_versions[GC_HWIP][0]; + uint32_t tmp; /* under multi-vf mode, the hwmon attributes are all not supported */ if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) @@ -3264,6 +3265,14 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, (attr == _dev_attr_power1_average.dev_attr.attr)) return 0; + /* not all products support both average and instantaneous */ + if (attr == _dev_attr_power1_average.dev_attr.attr && + amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)) == -EOPNOTSUPP) + return 0; + if (attr == _dev_attr_power1_input.dev_attr.attr && + amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)) == -EOPNOTSUPP) + return 0; + /* hide max/min values if we can't both query and manage the fan */ if (((amdgpu_dpm_set_fan_speed_pwm(adev, U32_MAX) == -EOPNOTSUPP) && (amdgpu_dpm_get_fan_speed_pwm(adev, NULL) == -EOPNOTSUPP) && -- 2.34.1
[PATCH 7/9] drm/amd: Show both power attributes for vega20
Vega20 can offer average power in some versions of the PMFW and current power in others. Signed-off-by: Mario Limonciello --- .../drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c | 18 +- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c index b6dd7f8daf725..ad40395be6028 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c @@ -2129,7 +2129,7 @@ static int vega20_get_metrics_table(struct pp_hwmgr *hwmgr, return ret; } -static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, +static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, int idx, uint32_t *query) { int ret = 0; @@ -2140,10 +2140,17 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, return ret; /* For the 40.46 release, they changed the value name */ - if (hwmgr->smu_version == 0x282e00) - *query = metrics_table.AverageSocketPower << 8; - else + switch (idx) { + case AMDGPU_PP_SENSOR_GPU_POWER: + if (hwmgr->smu_version == 0x282e00) + *query = metrics_table.AverageSocketPower << 8; + else + ret = -EOPNOTSUPP; + break; + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: *query = metrics_table.CurrSocketPower << 8; + break; + } return ret; } @@ -2253,9 +2260,10 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; *size = 4; break; + case AMDGPU_PP_SENSOR_GPU_POWER: case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: *size = 16; - ret = vega20_get_gpu_power(hwmgr, (uint32_t *)value); + ret = vega20_get_gpu_power(hwmgr, idx, (uint32_t *)value); break; case AMDGPU_PP_SENSOR_VDDGFX: val_vid = (RREG32_SOC15(SMUIO, 0, mmSMUSVI0_TEL_PLANE0) & -- 2.34.1
[PATCH 8/9] drm/amd: Rename AMDGPU_PP_SENSOR_GPU_POWER
Use the clearer name `AMDGPU_PP_SENSOR_GPU_AVG_POWER` instead. Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 +- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 2 +- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 4 ++-- drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c | 4 ++-- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c| 2 +- drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c| 2 +- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c| 2 +- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c| 1 + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c| 1 + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c| 2 +- drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c| 1 + 17 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 631c5ab3f7dc5..99f4df133ed3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1019,7 +1019,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) case AMDGPU_INFO_SENSOR_GPU_AVG_POWER: /* get average GPU power */ if (amdgpu_dpm_read_sensor(adev, - AMDGPU_PP_SENSOR_GPU_POWER, + AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *), _size)) { return -EINVAL; } diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 6582cdf2736f3..84c5224d994c4 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -132,7 +132,7 @@ enum amd_pp_sensors { AMDGPU_PP_SENSOR_MEM_TEMP, AMDGPU_PP_SENSOR_VCE_POWER, AMDGPU_PP_SENSOR_UVD_POWER, - AMDGPU_PP_SENSOR_GPU_POWER, + AMDGPU_PP_SENSOR_GPU_AVG_POWER, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, AMDGPU_PP_SENSOR_SS_APU_SHARE, AMDGPU_PP_SENSOR_SS_DGPU_SHARE, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index bb42851592291..8133d968f75b9 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2796,7 +2796,7 @@ static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, { unsigned int val; - val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_POWER); + val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_AVG_POWER); if (val < 0) return val; @@ -3460,7 +3460,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *), )) seq_printf(m, "\t%u mV (VDDNB)\n", value); size = sizeof(uint32_t); - if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER, (void *), )) + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *), )) seq_printf(m, "\t%u.%u W (average GPU)\n", query >> 8, query & 0xff); size = sizeof(value); seq_printf(m, "\n"); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c index ad40395be6028..3b33af30eb0fb 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c @@ -2141,7 +2141,7 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, int idx, /* For the 40.46 release, they changed the value name */ switch (idx) { - case AMDGPU_PP_SENSOR_GPU_POWER: + case AMDGPU_PP_SENSOR_GPU_AVG_POWER: if (hwmgr->smu_version == 0x282e00) *query = metrics_table.AverageSocketPower << 8; else @@ -2260,7 +2260,7 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; *size = 4; break; - case AMDGPU_PP_SENSOR_GPU_POWER: + case AMDGPU_PP_SENSOR_GPU_AVG_POWER: case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: *size = 16; ret = vega20_get_gpu_power(hwmgr, idx, (uint32_t *)value); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
[PATCH 4/9] drm/amd: Fix SMU 13.0.4/13.0.11 GPU metrics average power
The average power for the GPU metrics sysfs file contains the input power not the average power. The member that is set is called average power though, so correct it to the right value. Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index a4e87984645ec..0951659299c15 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -257,7 +257,7 @@ static ssize_t smu_v13_0_4_get_gpu_metrics(struct smu_context *smu, gpu_metrics->average_gfx_activity = metrics.GfxActivity; gpu_metrics->average_mm_activity = metrics.UvdActivity; - gpu_metrics->average_socket_power = metrics.CurrentSocketPower; + gpu_metrics->average_socket_power = metrics.AverageSocketPower; gpu_metrics->average_gfx_power = metrics.Power[0]; gpu_metrics->average_soc_power = metrics.Power[1]; memcpy(_metrics->average_core_power[0], -- 2.34.1
[PATCH 5/9] drm/amd: Drop unnecessary helper for aldebaran
aldebaran_get_gpu_power() is only called by one place and just calls aldebaran_get_smu_metrics_data(), so drop the helper. Signed-off-by: Mario Limonciello --- .../gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c| 15 +++ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 4e5043b6ce40b..0dbb1a1c25d24 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1094,16 +1094,6 @@ static int aldebaran_get_current_activity_percent(struct smu_context *smu, return ret; } -static int aldebaran_get_gpu_power(struct smu_context *smu, uint32_t *value) -{ - if (!value) - return -EINVAL; - - return aldebaran_get_smu_metrics_data(smu, - METRICS_AVERAGE_SOCKETPOWER, - value); -} - static int aldebaran_thermal_get_temperature(struct smu_context *smu, enum amd_pp_sensors sensor, uint32_t *value) @@ -1157,8 +1147,9 @@ static int aldebaran_read_sensor(struct smu_context *smu, (uint32_t *)data); *size = 4; break; - case AMDGPU_PP_SENSOR_GPU_POWER: - ret = aldebaran_get_gpu_power(smu, (uint32_t *)data); + ret = aldebaran_get_smu_metrics_data(smu, + METRICS_AVERAGE_SOCKETPOWER, +(uint32_t *)data); *size = 4; break; case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: -- 2.34.1
[PATCH 3/9] drm/amd: Introduce `AMDGPU_PP_SENSOR_GPU_INPUT_POWER`
Some GPUs have been overloading average power values and input power values. To disambiguate these, introduce a new `AMDGPU_PP_SENSOR_GPU_INPUT_POWER` and the GPUs that share input power update to use this instead of average power. Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 + drivers/gpu/drm/amd/pm/amdgpu_pm.c | 2 +- .../gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 2 +- .../drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c | 2 +- .../drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c | 2 +- .../drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 1 + .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 1 + .../drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 12 +++- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 1 + .../drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 1 + .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c| 10 ++ drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 6 +++--- .../gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 1 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c| 1 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c| 9 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c| 6 +++--- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c| 17 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c| 1 + .../drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c| 6 +++--- 20 files changed, 57 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 90989405eddcf..6582cdf2736f3 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -133,6 +133,7 @@ enum amd_pp_sensors { AMDGPU_PP_SENSOR_VCE_POWER, AMDGPU_PP_SENSOR_UVD_POWER, AMDGPU_PP_SENSOR_GPU_POWER, + AMDGPU_PP_SENSOR_GPU_INPUT_POWER, AMDGPU_PP_SENSOR_SS_APU_SHARE, AMDGPU_PP_SENSOR_SS_DGPU_SHARE, AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 816f034cfe3f1..bb42851592291 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2809,7 +2809,7 @@ static ssize_t amdgpu_hwmon_show_power_input(struct device *dev, { unsigned int val; - val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_POWER); + val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER); if (val < 0) return val; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index c91b2a3966cdb..5a2371484a58c 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -4039,7 +4039,7 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; *size = 4; return 0; - case AMDGPU_PP_SENSOR_GPU_POWER: + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: return smu7_get_gpu_power(hwmgr, (uint32_t *)value); case AMDGPU_PP_SENSOR_VDDGFX: if ((data->vr_config & VRCONF_VDDGFX_MASK) == diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c index 52ae6fa2d2a6d..6d6bc6a380b36 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c @@ -3966,7 +3966,7 @@ static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; *size = 4; break; - case AMDGPU_PP_SENSOR_GPU_POWER: + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: ret = vega10_get_gpu_power(hwmgr, (uint32_t *)value); break; case AMDGPU_PP_SENSOR_VDDGFX: diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c index 4bd573d815ff5..460067933de2e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c @@ -1529,7 +1529,7 @@ static int vega12_read_sensor(struct pp_hwmgr *hwmgr, int idx, *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; *size = 4; break; - case AMDGPU_PP_SENSOR_GPU_POWER: + case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: ret = vega12_get_gpu_power(hwmgr, (uint32_t *)value); if (!ret) *size = 4; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c index 492ca33637d6f..b6dd7f8daf725 100644 ---
[PATCH 6/9] drm/amd: Fix the return for average power on aldebaran
Aldebaran can only return average socket power for the first die. The other dies return 0. Instead of returning a bad value, return -EOPNOTSUPP so that the attribute will be hidden. Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 0dbb1a1c25d24..1341363ab01a8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -625,9 +625,10 @@ static int aldebaran_get_smu_metrics_data(struct smu_context *smu, break; case METRICS_AVERAGE_SOCKETPOWER: /* Valid power data is available only from primary die */ - *value = aldebaran_is_primary(smu) ? -metrics->AverageSocketPower << 8 : -0; + if (aldebaran_is_primary(smu)) + *value = metrics->AverageSocketPower << 8; + else + ret = -EOPNOTSUPP; break; case METRICS_TEMPERATURE_EDGE: *value = metrics->TemperatureEdge * -- 2.34.1
[PATCH 1/9] drm/amd: Add amdgpu_hwmon_get_sensor_generic()
Many sensor function have a lot of boilerplate checks. Move these into a generic amdgpu_hwmon_get_sensor_generic() instead. No intended functional changes. Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 321 - 1 file changed, 88 insertions(+), 233 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 5aed023f74022..c0eda9bf09824 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -1467,6 +1467,32 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, return -EINVAL; } +static unsigned int amdgpu_hwmon_get_sensor_generic(struct amdgpu_device *adev, + enum amd_pp_sensors sensor, + void *query) +{ + int r, size = sizeof(uint32_t); + + if (amdgpu_in_reset(adev)) + return -EPERM; + if (adev->in_suspend && !adev->in_runpm) + return -EPERM; + + r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + if (r < 0) { + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + return r; + } + + /* get the sensor value */ + r = amdgpu_dpm_read_sensor(adev, sensor, query, ); + + pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + + return r; +} + /** * DOC: gpu_busy_percent * @@ -1481,26 +1507,10 @@ static ssize_t amdgpu_get_gpu_busy_percent(struct device *dev, { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - int r, value, size = sizeof(value); - - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_get_sync(ddev->dev); - if (r < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return r; - } - - /* read the IP busy sensor */ - r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, - (void *), ); - - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + unsigned int value; + int r; + r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_LOAD, ); if (r) return r; @@ -1521,26 +1531,10 @@ static ssize_t amdgpu_get_mem_busy_percent(struct device *dev, { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - int r, value, size = sizeof(value); - - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_get_sync(ddev->dev); - if (r < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return r; - } - - /* read the IP busy sensor */ - r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MEM_LOAD, - (void *), ); - - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); + unsigned int value; + int r; + r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_LOAD, ); if (r) return r; @@ -1814,45 +1808,15 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev, return size; } -static int amdgpu_device_read_powershift(struct amdgpu_device *adev, - uint32_t *ss_power, bool dgpu_share) -{ - struct drm_device *ddev = adev_to_drm(adev); - uint32_t size; - int r = 0; - - if (amdgpu_in_reset(adev)) - return -EPERM; - if (adev->in_suspend && !adev->in_runpm) - return -EPERM; - - r = pm_runtime_get_sync(ddev->dev); - if (r < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return r; - } - - if (dgpu_share) - r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_SS_DGPU_SHARE, - (void *)ss_power, ); - else - r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_SS_APU_SHARE, - (void *)ss_power, ); - - pm_runtime_mark_last_busy(ddev->dev); - pm_runtime_put_autosuspend(ddev->dev); - return r; -} - static int amdgpu_show_powershift_percent(struct device *dev, - char *buf, bool dgpu_share) + char *buf, enum amd_pp_sensors sensor) { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t ss_power; int r = 0, i; - r =
[PATCH 2/9] drm/amd: Add a new hwmon attribute for instantaneous power
Some GPUs provide support for current power, some average power, and some both. To be able to support all these combinations, introduce a new attribute. Signed-off-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index c0eda9bf09824..816f034cfe3f1 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2803,6 +2803,19 @@ static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, return sysfs_emit(buf, "%u\n", val); } +static ssize_t amdgpu_hwmon_show_power_input(struct device *dev, +struct device_attribute *attr, +char *buf) +{ + unsigned int val; + + val = amdgpu_hwmon_get_power(dev, AMDGPU_PP_SENSOR_GPU_POWER); + if (val < 0) + return val; + + return sysfs_emit(buf, "%u\n", val); +} + static ssize_t amdgpu_hwmon_show_power_cap_min(struct device *dev, struct device_attribute *attr, char *buf) @@ -3023,6 +3036,8 @@ static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev, * * - power1_average: average power used by the SoC in microWatts. On APUs this includes the CPU. * + * - power1_input: instantaneous power used by the SoC in microWatts. On APUs this includes the CPU. + * * - power1_cap_min: minimum cap supported in microWatts * * - power1_cap_max: maximum cap supported in microWatts @@ -3091,6 +3106,7 @@ static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, amdgpu_hwmon_show_vddgfx_label, NU static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, amdgpu_hwmon_show_vddnb, NULL, 0); static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, amdgpu_hwmon_show_vddnb_label, NULL, 0); static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 0); +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, amdgpu_hwmon_show_power_input, NULL, 0); static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0); static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0); static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0); @@ -3137,6 +3153,7 @@ static struct attribute *hwmon_attributes[] = { _dev_attr_in1_input.dev_attr.attr, _dev_attr_in1_label.dev_attr.attr, _dev_attr_power1_average.dev_attr.attr, + _dev_attr_power1_input.dev_attr.attr, _dev_attr_power1_cap_max.dev_attr.attr, _dev_attr_power1_cap_min.dev_attr.attr, _dev_attr_power1_cap.dev_attr.attr, -- 2.34.1
RE: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
[Public] Sounds good. I'd also change: >> KFD currently relies on MEC FW to clear tcp watch control >> register by sending MAP_PROCESS packet with 0 of field >> tcp_watch_cntl to HWS, but if the queue is suspended, the >> packet will not be sent and the previous value will be >> left on the register, that will affect the following apps. >> So the solution is to clear the register as gfx v9 in KFD. To something like: KFD currently relies on MEC FW to clear tcp watch control register on UNMAP_QUEUES. Due to a FW bug, MEC does not do this. So the solution is to clear the register as gfx v9 in KFD. With those fixed, this patch is Reviewed-by: Jonathan Kim Hopefully we can get away with this since every watch instance register is supposed to be 1-1 to a process ... And that there's no race scenarios with trailing exceptions on dynamic watch point address changes ... Thanks, Jon > -Original Message- > From: Huang, JinHuiEric > Sent: Thursday, August 10, 2023 6:31 PM > To: Kim, Jonathan ; Kuehling, Felix > ; amd-gfx@lists.freedesktop.org > Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 > > I will change title to "drm/amdkfd: workaround address watch clearing > bug for gfx v9.4.2". is it OK? > > Regards, > Eric > > On 2023-08-10 18:25, Kim, Jonathan wrote: > > [Public] > > > > Yeah this is a recent bug so this workaround is new. More rigorous tests > revealed this is probably a miss on the FW side. We explicitly requested > UNMAP_QUEUES unconditionally invalidate watch controls during the > beginning of design to prevent any watch point racing. > > > > Note GFX11 MES calls are different on the surface but under the hood it's > the same (registers get invalidated on unmap then get updated on map. > Only difference it's at the queue level). > > > > I'm fine with this solution but I think it'd be good to describe this as a > workaround somewhere (as opposed to a driver issue) so that folks aren't > scratching their heads later on looking at code for GFX11 and up and > wondering why we don't nuke the control setting with the KFD for those > devices. > > > > Thanks, > > > > Jon > > > >> -Original Message- > >> From: Kuehling, Felix > >> Sent: Thursday, August 10, 2023 5:56 PM > >> To: Huang, JinHuiEric ; Kim, Jonathan > >> ; amd-gfx@lists.freedesktop.org > >> Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx > v9.4.2 > >> > >> I think Jon is suggesting that the UNMAP_QUEUES command should clear > the > >> address watch registers. Requesting such a change from the the HWS team > >> may take a long time. > >> > >> That said, when was this workaround implemented and reviewed? Did I > >> review it as part of Jon's debugger upstreaming patch series? Or did > >> this come later? This patch only enables the workaround for v9.4.2. > >> > >> Regards, > >> Felix > >> > >> > >> On 2023-08-10 17:52, Eric Huang wrote: > >>> The problem is the queue is suspended before clearing address watch > >>> call in KFD, there is not queue preemption and queue resume after > >>> clearing call, and the test ends. So there is not chance to send > >>> MAP_PROCESS to HWS. At this point FW has nothing to do. We have > >>> several test FWs from Tej, none of them works, so I recalled the > >>> kernel debug log and found out the problem. > >>> > >>> GFX11 has different scheduler, when calling clear address watch, KFD > >>> directly sends the MES_MISC_OP_SET_SHADER_DEBUGGER to MES, it > >> doesn't > >>> consider if the queue is suspended. So GFX11 doesn't have this issue. > >>> > >>> Regards, > >>> Eric > >>> > >>> On 2023-08-10 17:27, Kim, Jonathan wrote: > [AMD Official Use Only - General] > > This is a strange solution because the MEC should set watch controls > as non-valid automatically on queue preemption to avoid this kind of > issue in the first place by design. MAP_PROCESS on resume will take > whatever the driver requests. > GFX11 has no issue with letting the HWS do this. > > Are we sure we're not working around some HWS bug? > > Thanks, > > Jon > > > -Original Message- > > From: Kuehling, Felix > > Sent: Thursday, August 10, 2023 5:03 PM > > To: Huang, JinHuiEric ; amd- > > g...@lists.freedesktop.org > > Cc: Kim, Jonathan > > Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for > > gfx v9.4.2 > > > > I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a > bit > > different because it needs to support multiple XCCs. > > > > That said, this patch is > > > > Reviewed-by: Felix Kuehling > > > > > > On 2023-08-10 16:47, Eric Huang wrote: > >> KFD currently relies on MEC FW to clear tcp watch control > >> register by sending MAP_PROCESS packet with 0 of field > >> tcp_watch_cntl to HWS, but if the queue is suspended, the > >> packet will
Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
I will change title to "drm/amdkfd: workaround address watch clearing bug for gfx v9.4.2". is it OK? Regards, Eric On 2023-08-10 18:25, Kim, Jonathan wrote: [Public] Yeah this is a recent bug so this workaround is new. More rigorous tests revealed this is probably a miss on the FW side. We explicitly requested UNMAP_QUEUES unconditionally invalidate watch controls during the beginning of design to prevent any watch point racing. Note GFX11 MES calls are different on the surface but under the hood it's the same (registers get invalidated on unmap then get updated on map. Only difference it's at the queue level). I'm fine with this solution but I think it'd be good to describe this as a workaround somewhere (as opposed to a driver issue) so that folks aren't scratching their heads later on looking at code for GFX11 and up and wondering why we don't nuke the control setting with the KFD for those devices. Thanks, Jon -Original Message- From: Kuehling, Felix Sent: Thursday, August 10, 2023 5:56 PM To: Huang, JinHuiEric ; Kim, Jonathan ; amd-gfx@lists.freedesktop.org Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 I think Jon is suggesting that the UNMAP_QUEUES command should clear the address watch registers. Requesting such a change from the the HWS team may take a long time. That said, when was this workaround implemented and reviewed? Did I review it as part of Jon's debugger upstreaming patch series? Or did this come later? This patch only enables the workaround for v9.4.2. Regards, Felix On 2023-08-10 17:52, Eric Huang wrote: The problem is the queue is suspended before clearing address watch call in KFD, there is not queue preemption and queue resume after clearing call, and the test ends. So there is not chance to send MAP_PROCESS to HWS. At this point FW has nothing to do. We have several test FWs from Tej, none of them works, so I recalled the kernel debug log and found out the problem. GFX11 has different scheduler, when calling clear address watch, KFD directly sends the MES_MISC_OP_SET_SHADER_DEBUGGER to MES, it doesn't consider if the queue is suspended. So GFX11 doesn't have this issue. Regards, Eric On 2023-08-10 17:27, Kim, Jonathan wrote: [AMD Official Use Only - General] This is a strange solution because the MEC should set watch controls as non-valid automatically on queue preemption to avoid this kind of issue in the first place by design. MAP_PROCESS on resume will take whatever the driver requests. GFX11 has no issue with letting the HWS do this. Are we sure we're not working around some HWS bug? Thanks, Jon -Original Message- From: Kuehling, Felix Sent: Thursday, August 10, 2023 5:03 PM To: Huang, JinHuiEric ; amd- g...@lists.freedesktop.org Cc: Kim, Jonathan Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit different because it needs to support multiple XCCs. That said, this patch is Reviewed-by: Felix Kuehling On 2023-08-10 16:47, Eric Huang wrote: KFD currently relies on MEC FW to clear tcp watch control register by sending MAP_PROCESS packet with 0 of field tcp_watch_cntl to HWS, but if the queue is suspended, the packet will not be sent and the previous value will be left on the register, that will affect the following apps. So the solution is to clear the register as gfx v9 in KFD. Signed-off-by: Eric Huang --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +- -- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c index e2fed6edbdd0..aff08321e976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c @@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch( return watch_address_cntl; } -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev, - uint32_t watch_id) -{ - return 0; -} - const struct kfd2kgd_calls aldebaran_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { .set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override, .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, .set_address_watch = kgd_gfx_aldebaran_set_address_watch, - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, + .clear_address_watch = kgd_gfx_v9_clear_address_watch, .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, .build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info, .program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
There is not UNMAP_QUEUES command sending for queue preemption because the queue is suspended and test is closed to the end. Function unmap_queue_cpsch will do nothing after that. The workaround is new and only for gfx v9.4.2, because debugger tests has changed to check if all address watch points are correctly set, i.e. test A sets more than one watchpoint and leave, the following test B only sets one watchpoint, and test A's setting will cause more than one watchpoint event, so test B check out and report error on second or third watchpoint not set by itself. Regards, Eric On 2023-08-10 17:56, Felix Kuehling wrote: I think Jon is suggesting that the UNMAP_QUEUES command should clear the address watch registers. Requesting such a change from the the HWS team may take a long time. That said, when was this workaround implemented and reviewed? Did I review it as part of Jon's debugger upstreaming patch series? Or did this come later? This patch only enables the workaround for v9.4.2. Regards, Felix On 2023-08-10 17:52, Eric Huang wrote: The problem is the queue is suspended before clearing address watch call in KFD, there is not queue preemption and queue resume after clearing call, and the test ends. So there is not chance to send MAP_PROCESS to HWS. At this point FW has nothing to do. We have several test FWs from Tej, none of them works, so I recalled the kernel debug log and found out the problem. GFX11 has different scheduler, when calling clear address watch, KFD directly sends the MES_MISC_OP_SET_SHADER_DEBUGGER to MES, it doesn't consider if the queue is suspended. So GFX11 doesn't have this issue. Regards, Eric On 2023-08-10 17:27, Kim, Jonathan wrote: [AMD Official Use Only - General] This is a strange solution because the MEC should set watch controls as non-valid automatically on queue preemption to avoid this kind of issue in the first place by design. MAP_PROCESS on resume will take whatever the driver requests. GFX11 has no issue with letting the HWS do this. Are we sure we're not working around some HWS bug? Thanks, Jon -Original Message- From: Kuehling, Felix Sent: Thursday, August 10, 2023 5:03 PM To: Huang, JinHuiEric ; amd- g...@lists.freedesktop.org Cc: Kim, Jonathan Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit different because it needs to support multiple XCCs. That said, this patch is Reviewed-by: Felix Kuehling On 2023-08-10 16:47, Eric Huang wrote: KFD currently relies on MEC FW to clear tcp watch control register by sending MAP_PROCESS packet with 0 of field tcp_watch_cntl to HWS, but if the queue is suspended, the packet will not be sent and the previous value will be left on the register, that will affect the following apps. So the solution is to clear the register as gfx v9 in KFD. Signed-off-by: Eric Huang --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +--- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c index e2fed6edbdd0..aff08321e976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c @@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch( return watch_address_cntl; } -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev, - uint32_t watch_id) -{ - return 0; -} - const struct kfd2kgd_calls aldebaran_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { .set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override, .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, .set_address_watch = kgd_gfx_aldebaran_set_address_watch, - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, + .clear_address_watch = kgd_gfx_v9_clear_address_watch, .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, .build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info, .program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
RE: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
[Public] Yeah this is a recent bug so this workaround is new. More rigorous tests revealed this is probably a miss on the FW side. We explicitly requested UNMAP_QUEUES unconditionally invalidate watch controls during the beginning of design to prevent any watch point racing. Note GFX11 MES calls are different on the surface but under the hood it's the same (registers get invalidated on unmap then get updated on map. Only difference it's at the queue level). I'm fine with this solution but I think it'd be good to describe this as a workaround somewhere (as opposed to a driver issue) so that folks aren't scratching their heads later on looking at code for GFX11 and up and wondering why we don't nuke the control setting with the KFD for those devices. Thanks, Jon > -Original Message- > From: Kuehling, Felix > Sent: Thursday, August 10, 2023 5:56 PM > To: Huang, JinHuiEric ; Kim, Jonathan > ; amd-gfx@lists.freedesktop.org > Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 > > I think Jon is suggesting that the UNMAP_QUEUES command should clear the > address watch registers. Requesting such a change from the the HWS team > may take a long time. > > That said, when was this workaround implemented and reviewed? Did I > review it as part of Jon's debugger upstreaming patch series? Or did > this come later? This patch only enables the workaround for v9.4.2. > > Regards, >Felix > > > On 2023-08-10 17:52, Eric Huang wrote: > > The problem is the queue is suspended before clearing address watch > > call in KFD, there is not queue preemption and queue resume after > > clearing call, and the test ends. So there is not chance to send > > MAP_PROCESS to HWS. At this point FW has nothing to do. We have > > several test FWs from Tej, none of them works, so I recalled the > > kernel debug log and found out the problem. > > > > GFX11 has different scheduler, when calling clear address watch, KFD > > directly sends the MES_MISC_OP_SET_SHADER_DEBUGGER to MES, it > doesn't > > consider if the queue is suspended. So GFX11 doesn't have this issue. > > > > Regards, > > Eric > > > > On 2023-08-10 17:27, Kim, Jonathan wrote: > >> [AMD Official Use Only - General] > >> > >> This is a strange solution because the MEC should set watch controls > >> as non-valid automatically on queue preemption to avoid this kind of > >> issue in the first place by design. MAP_PROCESS on resume will take > >> whatever the driver requests. > >> GFX11 has no issue with letting the HWS do this. > >> > >> Are we sure we're not working around some HWS bug? > >> > >> Thanks, > >> > >> Jon > >> > >>> -Original Message- > >>> From: Kuehling, Felix > >>> Sent: Thursday, August 10, 2023 5:03 PM > >>> To: Huang, JinHuiEric ; amd- > >>> g...@lists.freedesktop.org > >>> Cc: Kim, Jonathan > >>> Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for > >>> gfx v9.4.2 > >>> > >>> I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit > >>> different because it needs to support multiple XCCs. > >>> > >>> That said, this patch is > >>> > >>> Reviewed-by: Felix Kuehling > >>> > >>> > >>> On 2023-08-10 16:47, Eric Huang wrote: > KFD currently relies on MEC FW to clear tcp watch control > register by sending MAP_PROCESS packet with 0 of field > tcp_watch_cntl to HWS, but if the queue is suspended, the > packet will not be sent and the previous value will be > left on the register, that will affect the following apps. > So the solution is to clear the register as gfx v9 in KFD. > > Signed-off-by: Eric Huang > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +- > -- > 1 file changed, 1 insertion(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > >>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > index e2fed6edbdd0..aff08321e976 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > @@ -163,12 +163,6 @@ static uint32_t > >>> kgd_gfx_aldebaran_set_address_watch( > return watch_address_cntl; > } > > -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct > >>> amdgpu_device *adev, > - uint32_t watch_id) > -{ > - return 0; > -} > - > const struct kfd2kgd_calls aldebaran_kfd2kgd = { > .program_sh_mem_settings = > >>> kgd_gfx_v9_program_sh_mem_settings, > .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, > @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = > { > .set_wave_launch_trap_override = > >>> kgd_aldebaran_set_wave_launch_trap_override, > .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, > .set_address_watch = kgd_gfx_aldebaran_set_address_watch, > - .clear_address_watch =
Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
I think Jon is suggesting that the UNMAP_QUEUES command should clear the address watch registers. Requesting such a change from the the HWS team may take a long time. That said, when was this workaround implemented and reviewed? Did I review it as part of Jon's debugger upstreaming patch series? Or did this come later? This patch only enables the workaround for v9.4.2. Regards, Felix On 2023-08-10 17:52, Eric Huang wrote: The problem is the queue is suspended before clearing address watch call in KFD, there is not queue preemption and queue resume after clearing call, and the test ends. So there is not chance to send MAP_PROCESS to HWS. At this point FW has nothing to do. We have several test FWs from Tej, none of them works, so I recalled the kernel debug log and found out the problem. GFX11 has different scheduler, when calling clear address watch, KFD directly sends the MES_MISC_OP_SET_SHADER_DEBUGGER to MES, it doesn't consider if the queue is suspended. So GFX11 doesn't have this issue. Regards, Eric On 2023-08-10 17:27, Kim, Jonathan wrote: [AMD Official Use Only - General] This is a strange solution because the MEC should set watch controls as non-valid automatically on queue preemption to avoid this kind of issue in the first place by design. MAP_PROCESS on resume will take whatever the driver requests. GFX11 has no issue with letting the HWS do this. Are we sure we're not working around some HWS bug? Thanks, Jon -Original Message- From: Kuehling, Felix Sent: Thursday, August 10, 2023 5:03 PM To: Huang, JinHuiEric ; amd- g...@lists.freedesktop.org Cc: Kim, Jonathan Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit different because it needs to support multiple XCCs. That said, this patch is Reviewed-by: Felix Kuehling On 2023-08-10 16:47, Eric Huang wrote: KFD currently relies on MEC FW to clear tcp watch control register by sending MAP_PROCESS packet with 0 of field tcp_watch_cntl to HWS, but if the queue is suspended, the packet will not be sent and the previous value will be left on the register, that will affect the following apps. So the solution is to clear the register as gfx v9 in KFD. Signed-off-by: Eric Huang --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +--- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c index e2fed6edbdd0..aff08321e976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c @@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch( return watch_address_cntl; } -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev, - uint32_t watch_id) -{ - return 0; -} - const struct kfd2kgd_calls aldebaran_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { .set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override, .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, .set_address_watch = kgd_gfx_aldebaran_set_address_watch, - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, + .clear_address_watch = kgd_gfx_v9_clear_address_watch, .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, .build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info, .program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
The problem is the queue is suspended before clearing address watch call in KFD, there is not queue preemption and queue resume after clearing call, and the test ends. So there is not chance to send MAP_PROCESS to HWS. At this point FW has nothing to do. We have several test FWs from Tej, none of them works, so I recalled the kernel debug log and found out the problem. GFX11 has different scheduler, when calling clear address watch, KFD directly sends the MES_MISC_OP_SET_SHADER_DEBUGGER to MES, it doesn't consider if the queue is suspended. So GFX11 doesn't have this issue. Regards, Eric On 2023-08-10 17:27, Kim, Jonathan wrote: [AMD Official Use Only - General] This is a strange solution because the MEC should set watch controls as non-valid automatically on queue preemption to avoid this kind of issue in the first place by design. MAP_PROCESS on resume will take whatever the driver requests. GFX11 has no issue with letting the HWS do this. Are we sure we're not working around some HWS bug? Thanks, Jon -Original Message- From: Kuehling, Felix Sent: Thursday, August 10, 2023 5:03 PM To: Huang, JinHuiEric ; amd- g...@lists.freedesktop.org Cc: Kim, Jonathan Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit different because it needs to support multiple XCCs. That said, this patch is Reviewed-by: Felix Kuehling On 2023-08-10 16:47, Eric Huang wrote: KFD currently relies on MEC FW to clear tcp watch control register by sending MAP_PROCESS packet with 0 of field tcp_watch_cntl to HWS, but if the queue is suspended, the packet will not be sent and the previous value will be left on the register, that will affect the following apps. So the solution is to clear the register as gfx v9 in KFD. Signed-off-by: Eric Huang --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +--- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c index e2fed6edbdd0..aff08321e976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c @@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch( return watch_address_cntl; } -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev, - uint32_t watch_id) -{ - return 0; -} - const struct kfd2kgd_calls aldebaran_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { .set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override, .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, .set_address_watch = kgd_gfx_aldebaran_set_address_watch, - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, + .clear_address_watch = kgd_gfx_v9_clear_address_watch, .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, .build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info, .program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
RE: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
[AMD Official Use Only - General] This is a strange solution because the MEC should set watch controls as non-valid automatically on queue preemption to avoid this kind of issue in the first place by design. MAP_PROCESS on resume will take whatever the driver requests. GFX11 has no issue with letting the HWS do this. Are we sure we're not working around some HWS bug? Thanks, Jon > -Original Message- > From: Kuehling, Felix > Sent: Thursday, August 10, 2023 5:03 PM > To: Huang, JinHuiEric ; amd- > g...@lists.freedesktop.org > Cc: Kim, Jonathan > Subject: Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2 > > I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit > different because it needs to support multiple XCCs. > > That said, this patch is > > Reviewed-by: Felix Kuehling > > > On 2023-08-10 16:47, Eric Huang wrote: > > KFD currently relies on MEC FW to clear tcp watch control > > register by sending MAP_PROCESS packet with 0 of field > > tcp_watch_cntl to HWS, but if the queue is suspended, the > > packet will not be sent and the previous value will be > > left on the register, that will affect the following apps. > > So the solution is to clear the register as gfx v9 in KFD. > > > > Signed-off-by: Eric Huang > > --- > > drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +--- > > 1 file changed, 1 insertion(+), 7 deletions(-) > > > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > > index e2fed6edbdd0..aff08321e976 100644 > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c > > @@ -163,12 +163,6 @@ static uint32_t > kgd_gfx_aldebaran_set_address_watch( > > return watch_address_cntl; > > } > > > > -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct > amdgpu_device *adev, > > - uint32_t watch_id) > > -{ > > - return 0; > > -} > > - > > const struct kfd2kgd_calls aldebaran_kfd2kgd = { > > .program_sh_mem_settings = > kgd_gfx_v9_program_sh_mem_settings, > > .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, > > @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { > > .set_wave_launch_trap_override = > kgd_aldebaran_set_wave_launch_trap_override, > > .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, > > .set_address_watch = kgd_gfx_aldebaran_set_address_watch, > > - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, > > + .clear_address_watch = kgd_gfx_v9_clear_address_watch, > > .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, > > .build_grace_period_packet_info = > kgd_gfx_v9_build_grace_period_packet_info, > > .program_trap_handler_settings = > kgd_gfx_v9_program_trap_handler_settings,
Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
Yes. I will send out the fix for gc v9.4.3 later. Thanks for your review. Eric On 2023-08-10 17:02, Felix Kuehling wrote: I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit different because it needs to support multiple XCCs. That said, this patch is Reviewed-by: Felix Kuehling On 2023-08-10 16:47, Eric Huang wrote: KFD currently relies on MEC FW to clear tcp watch control register by sending MAP_PROCESS packet with 0 of field tcp_watch_cntl to HWS, but if the queue is suspended, the packet will not be sent and the previous value will be left on the register, that will affect the following apps. So the solution is to clear the register as gfx v9 in KFD. Signed-off-by: Eric Huang --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +--- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c index e2fed6edbdd0..aff08321e976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c @@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch( return watch_address_cntl; } -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev, - uint32_t watch_id) -{ - return 0; -} - const struct kfd2kgd_calls aldebaran_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { .set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override, .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, .set_address_watch = kgd_gfx_aldebaran_set_address_watch, - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, + .clear_address_watch = kgd_gfx_v9_clear_address_watch, .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, .build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info, .program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
Re: [PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
I think amdgpu_amdkfd_gc_9_4_3.c needs a similar fix. But maybe a bit different because it needs to support multiple XCCs. That said, this patch is Reviewed-by: Felix Kuehling On 2023-08-10 16:47, Eric Huang wrote: KFD currently relies on MEC FW to clear tcp watch control register by sending MAP_PROCESS packet with 0 of field tcp_watch_cntl to HWS, but if the queue is suspended, the packet will not be sent and the previous value will be left on the register, that will affect the following apps. So the solution is to clear the register as gfx v9 in KFD. Signed-off-by: Eric Huang --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +--- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c index e2fed6edbdd0..aff08321e976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c @@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch( return watch_address_cntl; } -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev, - uint32_t watch_id) -{ - return 0; -} - const struct kfd2kgd_calls aldebaran_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { .set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override, .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, .set_address_watch = kgd_gfx_aldebaran_set_address_watch, - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, + .clear_address_watch = kgd_gfx_v9_clear_address_watch, .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, .build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info, .program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings,
[PATCH] drm/amdkfd: fix address watch clearing bug for gfx v9.4.2
KFD currently relies on MEC FW to clear tcp watch control register by sending MAP_PROCESS packet with 0 of field tcp_watch_cntl to HWS, but if the queue is suspended, the packet will not be sent and the previous value will be left on the register, that will affect the following apps. So the solution is to clear the register as gfx v9 in KFD. Signed-off-by: Eric Huang --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c | 8 +--- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c index e2fed6edbdd0..aff08321e976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_aldebaran.c @@ -163,12 +163,6 @@ static uint32_t kgd_gfx_aldebaran_set_address_watch( return watch_address_cntl; } -static uint32_t kgd_gfx_aldebaran_clear_address_watch(struct amdgpu_device *adev, - uint32_t watch_id) -{ - return 0; -} - const struct kfd2kgd_calls aldebaran_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping, @@ -193,7 +187,7 @@ const struct kfd2kgd_calls aldebaran_kfd2kgd = { .set_wave_launch_trap_override = kgd_aldebaran_set_wave_launch_trap_override, .set_wave_launch_mode = kgd_aldebaran_set_wave_launch_mode, .set_address_watch = kgd_gfx_aldebaran_set_address_watch, - .clear_address_watch = kgd_gfx_aldebaran_clear_address_watch, + .clear_address_watch = kgd_gfx_v9_clear_address_watch, .get_iq_wait_times = kgd_gfx_v9_get_iq_wait_times, .build_grace_period_packet_info = kgd_gfx_v9_build_grace_period_packet_info, .program_trap_handler_settings = kgd_gfx_v9_program_trap_handler_settings, -- 2.34.1
Re: [PATCH] drm/amdkfd: fix double assign skip process context clear
On 2023-08-10 15:03, Jonathan Kim wrote: Remove redundant assignment when skipping process ctx clear. Signed-off-by: Jonathan Kim Reviewed-by: Felix Kuehling --- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index aa5091f18681..89c2bfcb36ce 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -227,7 +227,6 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, queue_input.tba_addr = qpd->tba_addr; queue_input.tma_addr = qpd->tma_addr; queue_input.trap_en = !kfd_dbg_has_cwsr_workaround(q->device); - queue_input.skip_process_ctx_clear = qpd->pqm->process->debug_trap_enabled; queue_input.skip_process_ctx_clear = qpd->pqm->process->debug_trap_enabled || kfd_dbg_has_ttmps_always_setup(q->device);
Re: [PATCH v3 0/4] Add GPU page fault query interface
Ping? On Thu, Jul 27, 2023 at 2:11 PM Alex Deucher wrote: > > This patch set adds support for an application to query GPU > page faults. It's useful for debugging and there are > vulkan extensions that could make use of this. Preliminary > user space code which uses this can be found here: > https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23238 > https://gitlab.freedesktop.org/mesa/drm/-/merge_requests/298 > > Note, that I made a small change to the vmhub definition to > decouple it from how the kernel tracks vmhubs so that we have > a consistent user view even if we decide to add more vmhubs > like we recently did for gfx 9.4.3. > > I've also pushed the changed to: > https://gitlab.freedesktop.org/agd5f/linux/-/commits/gpu_fault_info_ioctl > > Open question, currently we just expose the raw GPU fault status > register value for each GPU so UMDs need GPU specific knowlege to decode > it, although it's largely the same across generations. One option would be to > translate to a generic GPU independent fault status. Opinions? > > v2: > - Fix spelling typos noted by Guchun > v3: > - Add locking in IOCTL query > - Only update cache if fault status is valid > > Alex Deucher (4): > drm/amdgpu: add cached GPU fault structure to vm struct > drm/amdgpu: cache gpuvm fault information for gmc7+ > drm/amdgpu: add new INFO ioctl query for the last GPU page fault > drm/amdgpu: refine fault cache updates > > drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 +- > drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 20 ++ > drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 50 + > drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 31 +-- > drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c | 3 ++ > drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 3 ++ > drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 3 ++ > drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 3 ++ > drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 11 -- > include/uapi/drm/amdgpu_drm.h | 16 > 10 files changed, 135 insertions(+), 8 deletions(-) > > -- > 2.41.0 >
[RESEND v3 5/5] drm/amdgpu: Create version number for coredumps
Even if there's nothing currently parsing amdgpu's coredump files, if we eventually have such tools they will be glad to find a version field to properly read the file. Create a version number to be displayed on top of coredump file, to be incremented when the file format or content get changed. Signed-off-by: André Almeida --- drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index b02b56193447..202c101772a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -192,6 +192,7 @@ static ssize_t amdgpu_devcoredump_read(char *buffer, loff_t offset, p = drm_coredump_printer(); drm_printf(, " AMDGPU Device Coredump \n"); + drm_printf(, "version: " AMDGPU_COREDUMP_VERSION "\n"); drm_printf(, "kernel: " UTS_RELEASE "\n"); drm_printf(, "module: " KBUILD_MODNAME "\n"); drm_printf(, "time: %lld.%09ld\n", coredump->reset_time.tv_sec, coredump->reset_time.tv_nsec); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index 362954521721..7b6767ca8127 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -88,6 +88,9 @@ struct amdgpu_reset_domain { }; #ifdef CONFIG_DEV_COREDUMP + +#define AMDGPU_COREDUMP_VERSION "1" + struct amdgpu_coredump_info { struct amdgpu_device*adev; struct amdgpu_task_info reset_task_info; -- 2.41.0
[RESEND v3 4/5] drm/amdgpu: Move coredump code to amdgpu_reset file
Giving that we use codedump just for device resets, move it's functions and structs to a more semantic file, the amdgpu_reset.{c, h}. Signed-off-by: André Almeida --- drivers/gpu/drm/amd/amdgpu/amdgpu.h| 9 --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 80 -- drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 78 + drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h | 11 +++ 4 files changed, 89 insertions(+), 89 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 0d560b713948..314b06cddc39 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1100,15 +1100,6 @@ struct amdgpu_device { uint32_taid_mask; }; -#ifdef CONFIG_DEV_COREDUMP -struct amdgpu_coredump_info { - struct amdgpu_device*adev; - struct amdgpu_task_info reset_task_info; - struct timespec64 reset_time; - boolreset_vram_lost; -}; -#endif - static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev) { return container_of(ddev, struct amdgpu_device, ddev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 419b6336de64..9706f608723a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include #include @@ -4799,84 +4797,6 @@ static int amdgpu_reset_reg_dumps(struct amdgpu_device *adev) return 0; } -#ifndef CONFIG_DEV_COREDUMP -static void amdgpu_coredump(struct amdgpu_device *adev, bool vram_lost, - struct amdgpu_reset_context *reset_context) -{ -} -#else -static ssize_t amdgpu_devcoredump_read(char *buffer, loff_t offset, - size_t count, void *data, size_t datalen) -{ - struct drm_printer p; - struct amdgpu_coredump_info *coredump = data; - struct drm_print_iterator iter; - int i; - - iter.data = buffer; - iter.offset = 0; - iter.start = offset; - iter.remain = count; - - p = drm_coredump_printer(); - - drm_printf(, " AMDGPU Device Coredump \n"); - drm_printf(, "kernel: " UTS_RELEASE "\n"); - drm_printf(, "module: " KBUILD_MODNAME "\n"); - drm_printf(, "time: %lld.%09ld\n", coredump->reset_time.tv_sec, coredump->reset_time.tv_nsec); - if (coredump->reset_task_info.pid) - drm_printf(, "process_name: %s PID: %d\n", - coredump->reset_task_info.process_name, - coredump->reset_task_info.pid); - - if (coredump->reset_vram_lost) - drm_printf(, "VRAM is lost due to GPU reset!\n"); - if (coredump->adev->num_regs) { - drm_printf(, "AMDGPU register dumps:\nOffset: Value:\n"); - - for (i = 0; i < coredump->adev->num_regs; i++) - drm_printf(, "0x%08x: 0x%08x\n", - coredump->adev->reset_dump_reg_list[i], - coredump->adev->reset_dump_reg_value[i]); - } - - return count - iter.remain; -} - -static void amdgpu_devcoredump_free(void *data) -{ - kfree(data); -} - -static void amdgpu_coredump(struct amdgpu_device *adev, bool vram_lost, - struct amdgpu_reset_context *reset_context) -{ - struct amdgpu_coredump_info *coredump; - struct drm_device *dev = adev_to_drm(adev); - - coredump = kmalloc(sizeof(*coredump), GFP_NOWAIT); - - if (!coredump) { - DRM_ERROR("%s: failed to allocate memory for coredump\n", __func__); - return; - } - - memset(coredump, 0, sizeof(*coredump)); - - coredump->reset_vram_lost = vram_lost; - - if (reset_context->job && reset_context->job->vm) - coredump->reset_task_info = reset_context->job->vm->task_info; - - coredump->adev = adev; - - ktime_get_ts64(>reset_time); - - dev_coredumpm(dev->dev, THIS_MODULE, coredump, 0, GFP_NOWAIT, - amdgpu_devcoredump_read, amdgpu_devcoredump_free); -} -#endif - int amdgpu_do_asic_reset(struct list_head *device_list_handle, struct amdgpu_reset_context *reset_context) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 5fed06ffcc6b..b02b56193447 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -21,6 +21,9 @@ * */ +#include +#include + #include "amdgpu_reset.h" #include "aldebaran.h" #include "sienna_cichlid.h" @@ -167,5 +170,80 @@ void amdgpu_device_unlock_reset_domain(struct amdgpu_reset_domain *reset_domain) up_write(_domain->sem); } +#ifndef CONFIG_DEV_COREDUMP +void
[RESEND v3 3/5] drm/amdgpu: Rework coredump to use memory dynamically
Instead of storing coredump information inside amdgpu_device struct, move if to a proper separated struct and allocate it dynamically. This will make it easier to further expand the logged information. Signed-off-by: André Almeida --- drivers/gpu/drm/amd/amdgpu/amdgpu.h| 14 +++-- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 65 ++ 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9c6a332261ab..0d560b713948 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1088,11 +1088,6 @@ struct amdgpu_device { uint32_t*reset_dump_reg_list; uint32_t*reset_dump_reg_value; int num_regs; -#ifdef CONFIG_DEV_COREDUMP - struct amdgpu_task_info reset_task_info; - boolreset_vram_lost; - struct timespec64 reset_time; -#endif boolscpm_enabled; uint32_tscpm_status; @@ -1105,6 +1100,15 @@ struct amdgpu_device { uint32_taid_mask; }; +#ifdef CONFIG_DEV_COREDUMP +struct amdgpu_coredump_info { + struct amdgpu_device*adev; + struct amdgpu_task_info reset_task_info; + struct timespec64 reset_time; + boolreset_vram_lost; +}; +#endif + static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev) { return container_of(ddev, struct amdgpu_device, ddev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index bf4781551f88..419b6336de64 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4799,12 +4799,17 @@ static int amdgpu_reset_reg_dumps(struct amdgpu_device *adev) return 0; } -#ifdef CONFIG_DEV_COREDUMP +#ifndef CONFIG_DEV_COREDUMP +static void amdgpu_coredump(struct amdgpu_device *adev, bool vram_lost, + struct amdgpu_reset_context *reset_context) +{ +} +#else static ssize_t amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count, void *data, size_t datalen) { struct drm_printer p; - struct amdgpu_device *adev = data; + struct amdgpu_coredump_info *coredump = data; struct drm_print_iterator iter; int i; @@ -4818,21 +4823,21 @@ static ssize_t amdgpu_devcoredump_read(char *buffer, loff_t offset, drm_printf(, " AMDGPU Device Coredump \n"); drm_printf(, "kernel: " UTS_RELEASE "\n"); drm_printf(, "module: " KBUILD_MODNAME "\n"); - drm_printf(, "time: %lld.%09ld\n", adev->reset_time.tv_sec, adev->reset_time.tv_nsec); - if (adev->reset_task_info.pid) + drm_printf(, "time: %lld.%09ld\n", coredump->reset_time.tv_sec, coredump->reset_time.tv_nsec); + if (coredump->reset_task_info.pid) drm_printf(, "process_name: %s PID: %d\n", - adev->reset_task_info.process_name, - adev->reset_task_info.pid); + coredump->reset_task_info.process_name, + coredump->reset_task_info.pid); - if (adev->reset_vram_lost) + if (coredump->reset_vram_lost) drm_printf(, "VRAM is lost due to GPU reset!\n"); - if (adev->num_regs) { + if (coredump->adev->num_regs) { drm_printf(, "AMDGPU register dumps:\nOffset: Value:\n"); - for (i = 0; i < adev->num_regs; i++) + for (i = 0; i < coredump->adev->num_regs; i++) drm_printf(, "0x%08x: 0x%08x\n", - adev->reset_dump_reg_list[i], - adev->reset_dump_reg_value[i]); + coredump->adev->reset_dump_reg_list[i], + coredump->adev->reset_dump_reg_value[i]); } return count - iter.remain; @@ -4840,14 +4845,34 @@ static ssize_t amdgpu_devcoredump_read(char *buffer, loff_t offset, static void amdgpu_devcoredump_free(void *data) { + kfree(data); } -static void amdgpu_reset_capture_coredumpm(struct amdgpu_device *adev) +static void amdgpu_coredump(struct amdgpu_device *adev, bool vram_lost, + struct amdgpu_reset_context *reset_context) { + struct amdgpu_coredump_info *coredump; struct drm_device *dev = adev_to_drm(adev); - ktime_get_ts64(>reset_time); - dev_coredumpm(dev->dev, THIS_MODULE, adev, 0, GFP_NOWAIT, + coredump = kmalloc(sizeof(*coredump), GFP_NOWAIT); + + if (!coredump) { + DRM_ERROR("%s: failed to allocate memory for coredump\n", __func__); +
[RESEND v3 2/5] drm/amdgpu: Allocate coredump memory in a nonblocking way
During a GPU reset, a normal memory reclaim could block to reclaim memory. Giving that coredump is a best effort mechanism, it shouldn't disturb the reset path. Change its memory allocation flag to a nonblocking one. Signed-off-by: André Almeida Reviewed-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index aa171db68639..bf4781551f88 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4847,7 +4847,7 @@ static void amdgpu_reset_capture_coredumpm(struct amdgpu_device *adev) struct drm_device *dev = adev_to_drm(adev); ktime_get_ts64(>reset_time); - dev_coredumpm(dev->dev, THIS_MODULE, adev, 0, GFP_KERNEL, + dev_coredumpm(dev->dev, THIS_MODULE, adev, 0, GFP_NOWAIT, amdgpu_devcoredump_read, amdgpu_devcoredump_free); } #endif -- 2.41.0
[RESEND v3 1/5] drm/amdgpu: Create a module param to disable soft recovery
Create a module parameter to disable soft recoveries on amdgpu, making every recovery go through the device reset path. This option makes easier to force device resets for testing and debugging purposes. Signed-off-by: André Almeida --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 9 + drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 6 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 2e3c7c15cb8e..9c6a332261ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -189,6 +189,7 @@ extern uint amdgpu_force_long_training; extern int amdgpu_lbpw; extern int amdgpu_compute_multipipe; extern int amdgpu_gpu_recovery; +extern bool amdgpu_soft_recovery; extern int amdgpu_emu_mode; extern uint amdgpu_smu_memory_pool_size; extern int amdgpu_smu_pptable_id; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 0fec81d6a7df..27e7fa36cc60 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -163,6 +163,7 @@ uint amdgpu_force_long_training; int amdgpu_lbpw = -1; int amdgpu_compute_multipipe = -1; int amdgpu_gpu_recovery = -1; /* auto */ +bool amdgpu_soft_recovery = true; int amdgpu_emu_mode; uint amdgpu_smu_memory_pool_size; int amdgpu_smu_pptable_id = -1; @@ -538,6 +539,14 @@ module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444); MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto)"); module_param_named(gpu_recovery, amdgpu_gpu_recovery, int, 0444); +/** + * DOC: gpu_soft_recovery (bool) + * Set true to allow the driver to try soft recoveries if a job get stuck. Set + * to false to always force a GPU reset during recovery. + */ +MODULE_PARM_DESC(gpu_soft_recovery, "Enable GPU soft recovery mechanism (default: true)"); +module_param_named(gpu_soft_recovery, amdgpu_soft_recovery, bool, 0644); + /** * DOC: emu_mode (int) * Set value 1 to enable emulation mode. This is only needed when running on an emulator. The default is 0 (disabled). diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 80d6e132e409..40678d9fb17e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -434,8 +434,12 @@ bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid, struct dma_fence *fence) { unsigned long flags; + ktime_t deadline; - ktime_t deadline = ktime_add_us(ktime_get(), 1); + if (!amdgpu_soft_recovery) + return false; + + deadline = ktime_add_us(ktime_get(), 1); if (amdgpu_sriov_vf(ring->adev) || !ring->funcs->soft_recovery || !fence) return false; -- 2.41.0
[RESEND v3 0/5] drm/amdgpu: Add new reset option and rework coredump
Hi, The goal of this patchset is to improve debugging device resets on amdgpu. The first patch creates a new module parameter to disable soft recoveries, ensuring every recovery go through the full device reset, making easier to generate resets from userspace tools like [0] and [1]. This is important to validate how the stack behaves on resets, from end-to-end. The last patches are a rework to alloc devcoredump dynamically and to move it to a better source file. I have dropped the patches that add more information to devcoredump for now, until I figure out a better way to do so, like storing the IB address in the fence. Thanks, André [0] https://gitlab.freedesktop.org/andrealmeid/gpu-timeout [1] https://github.com/andrealmeid/vulkan-triangle-v1 Changelog: v2: https://lore.kernel.org/dri-devel/20230713213242.680944-1-andrealm...@igalia.com/ - Drop the IB and ring patch - Drop patch that limited information from kernel threads - Add patch to move coredump to amdgpu_reset v1: https://lore.kernel.org/dri-devel/20230711213501.526237-1-andrealm...@igalia.com/ - Drop "Mark contexts guilty for causing soft recoveries" patch - Use GFP_NOWAIT for devcoredump allocation André Almeida (5): drm/amdgpu: Create a module param to disable soft recovery drm/amdgpu: Allocate coredump memory in a nonblocking way drm/amdgpu: Rework coredump to use memory dynamically drm/amdgpu: Move coredump code to amdgpu_reset file drm/amdgpu: Create version number for coredumps drivers/gpu/drm/amd/amdgpu/amdgpu.h| 6 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 67 +- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c| 9 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 79 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h | 14 drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 6 +- 6 files changed, 111 insertions(+), 70 deletions(-) -- 2.41.0
[PATCH] drm/amdkfd: fix double assign skip process context clear
Remove redundant assignment when skipping process ctx clear. Signed-off-by: Jonathan Kim --- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index aa5091f18681..89c2bfcb36ce 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -227,7 +227,6 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, queue_input.tba_addr = qpd->tba_addr; queue_input.tma_addr = qpd->tma_addr; queue_input.trap_en = !kfd_dbg_has_cwsr_workaround(q->device); - queue_input.skip_process_ctx_clear = qpd->pqm->process->debug_trap_enabled; queue_input.skip_process_ctx_clear = qpd->pqm->process->debug_trap_enabled || kfd_dbg_has_ttmps_always_setup(q->device); -- 2.25.1
Re: [PATCH] drm/amdgpu: Keep reset handlers shared
On 8/10/2023 8:41 PM, Christian König wrote: Am 10.08.23 um 13:44 schrieb Lijo Lazar: Instead of maintaining a list per device, keep the reset handlers common per ASIC family. A pointer to the list of handlers is maintained in reset control. Why should this be beneficial? There is a global reset handler object for each type of reset for a particular ASIC family. Each device has a reset control which holds a reference to these handlers. Earlier, the handler used to be a list object. This creates trouble when there are multiple devices of the same ASIC family - the same global object gets added to reset control of each device and that corrupts list. Keeping an array of reset handlers and having the reset control holding a reference to the array of handlers makes it simpler. Thanks, Lijo Christian. Signed-off-by: Lijo Lazar --- drivers/gpu/drm/amd/amdgpu/aldebaran.c | 19 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 8 drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h | 16 drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c | 20 +++- drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c | 19 +++ 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 2b97b8a96fb4..82e1c83a7ccc 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -48,20 +48,19 @@ aldebaran_get_reset_handler(struct amdgpu_reset_control *reset_ctl, { struct amdgpu_reset_handler *handler; struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + int i; if (reset_context->method != AMD_RESET_METHOD_NONE) { dev_dbg(adev->dev, "Getting reset handler for method %d\n", reset_context->method); - list_for_each_entry(handler, _ctl->reset_handlers, - handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == reset_context->method) return handler; } } if (aldebaran_is_mode2_default(reset_ctl)) { - list_for_each_entry(handler, _ctl->reset_handlers, - handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == AMD_RESET_METHOD_MODE2) { reset_context->method = AMD_RESET_METHOD_MODE2; return handler; @@ -124,9 +123,9 @@ static void aldebaran_async_reset(struct work_struct *work) struct amdgpu_reset_control *reset_ctl = container_of(work, struct amdgpu_reset_control, reset_work); struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + int i; - list_for_each_entry(handler, _ctl->reset_handlers, - handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == reset_ctl->active_reset) { dev_dbg(adev->dev, "Resetting device\n"); handler->do_reset(adev); @@ -395,6 +394,11 @@ static struct amdgpu_reset_handler aldebaran_mode2_handler = { .do_reset = aldebaran_mode2_reset, }; +static struct amdgpu_reset_handler + *aldebaran_rst_handlers[AMDGPU_RESET_MAX_HANDLERS] = { + _mode2_handler, + }; + int aldebaran_reset_init(struct amdgpu_device *adev) { struct amdgpu_reset_control *reset_ctl; @@ -408,10 +412,9 @@ int aldebaran_reset_init(struct amdgpu_device *adev) reset_ctl->active_reset = AMD_RESET_METHOD_NONE; reset_ctl->get_reset_handler = aldebaran_get_reset_handler; - INIT_LIST_HEAD(_ctl->reset_handlers); INIT_WORK(_ctl->reset_work, reset_ctl->async_reset); /* Only mode2 is handled through reset control now */ - amdgpu_reset_add_handler(reset_ctl, _mode2_handler); + reset_ctl->reset_handlers = _rst_handlers; adev->reset_cntl = reset_ctl; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 5fed06ffcc6b..02d874799c16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -26,14 +26,6 @@ #include "sienna_cichlid.h" #include "smu_v13_0_10.h" -int amdgpu_reset_add_handler(struct amdgpu_reset_control *reset_ctl, - struct amdgpu_reset_handler *handler) -{ - /* TODO: Check if handler exists? */ - list_add_tail(>handler_list, _ctl->reset_handlers); - return 0; -} - int amdgpu_reset_init(struct amdgpu_device *adev) { int ret = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index f4a501ff87d9..471d789b33a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -26,6 +26,8 @@ #include "amdgpu.h" +#define AMDGPU_RESET_MAX_HANDLERS 5 + enum AMDGPU_RESET_FLAGS { AMDGPU_NEED_FULL_RESET
[PATCH] drm/amdkfd: ratelimited SQ interrupt messages
No functional change. Use ratelimited version of pr_ to avoid overflowing of dmesg buffer Signed-off-by: Harish Kasiviswanathan --- drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c | 6 +++--- drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c | 6 +++--- drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c index c7991e07b6be..a7697ec8188e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v10.c @@ -268,7 +268,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, SQ_INTERRUPT_WORD_WAVE_CTXID1, ENCODING); switch (encoding) { case SQ_INTERRUPT_WORD_ENCODING_AUTO: - pr_debug( + pr_debug_ratelimited( "sq_intr: auto, se %d, ttrace %d, wlt %d, ttrac_buf0_full %d, ttrac_buf1_full %d, ttrace_utc_err %d\n", REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_AUTO_CTXID1, SE_ID), @@ -284,7 +284,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, THREAD_TRACE_UTC_ERROR)); break; case SQ_INTERRUPT_WORD_ENCODING_INST: - pr_debug("sq_intr: inst, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", + pr_debug_ratelimited("sq_intr: inst, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, SE_ID), REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, @@ -310,7 +310,7 @@ static void event_interrupt_wq_v10(struct kfd_node *dev, case SQ_INTERRUPT_WORD_ENCODING_ERROR: sq_intr_err_type = REG_GET_FIELD(context_id0, KFD_CTXID0, ERR_TYPE); - pr_warn("sq_intr: error, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d, err_type %d\n", + pr_warn_ratelimited("sq_intr: error, se %d, data 0x%x, sa %d, priv %d, wave_id %d, simd_id %d, wgp_id %d, err_type %d\n", REG_GET_FIELD(context_id1, SQ_INTERRUPT_WORD_WAVE_CTXID1, SE_ID), REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c index f933bd231fb9..2a65792fd116 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v11.c @@ -150,7 +150,7 @@ enum SQ_INTERRUPT_ERROR_TYPE { static void print_sq_intr_info_auto(uint32_t context_id0, uint32_t context_id1) { - pr_debug( + pr_debug_ratelimited( "sq_intr: auto, ttrace %d, wlt %d, ttrace_buf_full %d, reg_tms %d, cmd_tms %d, host_cmd_ovf %d, host_reg_ovf %d, immed_ovf %d, ttrace_utc_err %d\n", REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, THREAD_TRACE), REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_AUTO_CTXID0, WLT), @@ -165,7 +165,7 @@ static void print_sq_intr_info_auto(uint32_t context_id0, uint32_t context_id1) static void print_sq_intr_info_inst(uint32_t context_id0, uint32_t context_id1) { - pr_debug( + pr_debug_ratelimited( "sq_intr: inst, data 0x%08x, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, DATA), REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_WAVE_CTXID0, SH_ID), @@ -177,7 +177,7 @@ static void print_sq_intr_info_inst(uint32_t context_id0, uint32_t context_id1) static void print_sq_intr_info_error(uint32_t context_id0, uint32_t context_id1) { - pr_warn( + pr_warn_ratelimited( "sq_intr: error, detail 0x%08x, type %d, sh %d, priv %d, wave_id %d, simd_id %d, wgp_id %d\n", REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, DETAIL), REG_GET_FIELD(context_id0, SQ_INTERRUPT_WORD_ERROR_CTXID0, TYPE), diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c index f0731a6a5306..02695ccd22d6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++
[PATCH v2 34/34] drm/amd/display: Use 3x4 CTM for plane CTM
From: Joshua Ashton Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 32 +-- .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 2 +- include/uapi/drm/drm_mode.h | 8 + 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 7ff329101fd4..0a51af44efd5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -412,6 +412,32 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, } } +/** + * __drm_ctm2_to_dc_matrix - converts a DRM CTM2 to a DC CSC float matrix + * @ctm: DRM color transformation matrix + * @matrix: DC CSC float matrix + * + * The matrix needs to be a 3x4 (12 entry) matrix. + */ +static void __drm_ctm2_to_dc_matrix(const struct drm_color_ctm2 *ctm, + struct fixed31_32 *matrix) +{ + int i; + + /* +* DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating +* with homogeneous coordinates, augment the matrix with 0's. +* +* The format provided is S31.32, using signed-magnitude representation. +* Our fixed31_32 is also S31.32, but is using 2's complement. We have +* to convert from signed-magnitude to 2's complement. +*/ + for (i = 0; i < 12; i++) { + /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ + matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i]); + } +} + /** * __set_legacy_tf - Calculates the legacy transfer function * @func: transfer function @@ -1159,7 +1185,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, { struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev); struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); - struct drm_color_ctm *ctm = NULL; + struct drm_color_ctm2 *ctm = NULL; struct dc_color_caps *color_caps = NULL; bool has_crtc_cm_degamma; int ret; @@ -1213,7 +1239,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, /* Setup CRTC CTM. */ if (dm_plane_state->ctm) { - ctm = (struct drm_color_ctm *)dm_plane_state->ctm->data; + ctm = (struct drm_color_ctm2 *)dm_plane_state->ctm->data; /* * So far, if we have both plane and CRTC CTM, plane CTM takes @@ -1224,7 +1250,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, * provide support for both DPP and MPC matrix at the same * time. */ - __drm_ctm_to_dc_matrix(ctm, dc_plane_state->gamut_remap_matrix.matrix); + __drm_ctm2_to_dc_matrix(ctm, dc_plane_state->gamut_remap_matrix.matrix); dc_plane_state->gamut_remap_matrix.enable_remap = true; dc_plane_state->input_csc_color_matrix.enable_adjustment = false; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 0b1081c690cb..27962a3d30f5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1543,7 +1543,7 @@ dm_atomic_plane_set_property(struct drm_plane *plane, ret = drm_property_replace_blob_from_id(plane->dev, _plane_state->ctm, val, - sizeof(struct drm_color_ctm), -1, + sizeof(struct drm_color_ctm2), -1, ); dm_plane_state->base.color_mgmt_changed |= replaced; return ret; diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 46becedf5b2f..402288133e4c 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -838,6 +838,14 @@ struct drm_color_ctm { __u64 matrix[9]; }; +struct drm_color_ctm2 { + /* +* Conversion matrix in S31.32 sign-magnitude +* (not two's complement!) format. +*/ + __u64 matrix[12]; +}; + struct drm_color_lut { /* * Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and -- 2.40.1
[PATCH v2 33/34] drm/amd/display: add plane CTM support
Map the plane CTM driver-specific property to DC plane, instead of DC stream. The remaining steps to program DPP block are already implemented on DC shared-code. Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 25 +++ 2 files changed, 26 insertions(+) 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 dfe61c5ed49e..f239410234b3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -9578,6 +9578,7 @@ static bool should_reset_plane(struct drm_atomic_state *state, if (dm_old_other_state->degamma_tf != dm_new_other_state->degamma_tf || dm_old_other_state->degamma_lut != dm_new_other_state->degamma_lut || dm_old_other_state->hdr_mult != dm_new_other_state->hdr_mult || + dm_old_other_state->ctm != dm_new_other_state->ctm || dm_old_other_state->shaper_lut != dm_new_other_state->shaper_lut || dm_old_other_state->shaper_tf != dm_new_other_state->shaper_tf || dm_old_other_state->lut3d != dm_new_other_state->lut3d || diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 86a918ab82be..7ff329101fd4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -1158,6 +1158,8 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, struct dc_plane_state *dc_plane_state) { struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev); + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + struct drm_color_ctm *ctm = NULL; struct dc_color_caps *color_caps = NULL; bool has_crtc_cm_degamma; int ret; @@ -1209,6 +1211,29 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, return ret; } + /* Setup CRTC CTM. */ + if (dm_plane_state->ctm) { + ctm = (struct drm_color_ctm *)dm_plane_state->ctm->data; + + /* +* So far, if we have both plane and CRTC CTM, plane CTM takes +* the priority and we discard data for CRTC CTM, as +* implemented in dcn10_program_gamut_remap(). However, we +* have MPC gamut_remap_matrix from DCN3 family, therefore we +* can remap MPC programing of the matrix to MPC block and +* provide support for both DPP and MPC matrix at the same +* time. +*/ + __drm_ctm_to_dc_matrix(ctm, dc_plane_state->gamut_remap_matrix.matrix); + + dc_plane_state->gamut_remap_matrix.enable_remap = true; + dc_plane_state->input_csc_color_matrix.enable_adjustment = false; + } else { + /* Bypass CTM. */ + dc_plane_state->gamut_remap_matrix.enable_remap = false; + dc_plane_state->input_csc_color_matrix.enable_adjustment = false; + } + return amdgpu_dm_plane_set_color_properties(plane_state, dc_plane_state, color_caps); } -- 2.40.1
[PATCH v2 32/34] drm/amd/display: add plane CTM driver-specific property
Plane CTM for pre-blending color space conversion. Only enable driver-specific plane CTM property on drivers that support both pre- and post-blending gamut remap matrix, i.e., DCN3+ family. Otherwise it conflits with DRM CRTC CTM property. Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 2 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 +++ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 7 +++ .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 20 +++ 4 files changed, 36 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index abb871a912d7..84bf501b02f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -363,6 +363,8 @@ struct amdgpu_mode_info { * @plane_hdr_mult_property: */ struct drm_property *plane_hdr_mult_property; + + struct drm_property *plane_ctm_property; /** * @shaper_lut_property: Plane property to set pre-blending shaper LUT * that converts color content before 3D LUT. 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 095f39f04210..6252ee912a63 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -769,6 +769,13 @@ struct dm_plane_state { * S31.32 sign-magnitude. */ __u64 hdr_mult; + /** +* @ctm: +* +* Color transformation matrix. See drm_crtc_enable_color_mgmt(). The +* blob (if not NULL) is a drm_color_ctm. +*/ + struct drm_property_blob *ctm; /** * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an * array of drm_color_lut. diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 4356846a2bce..86a918ab82be 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -218,6 +218,13 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.plane_hdr_mult_property = prop; + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_CTM", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_ctm_property = prop; + prop = drm_property_create(adev_to_drm(adev), DRM_MODE_PROP_BLOB, "AMD_PLANE_SHAPER_LUT", 0); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 3fd57de7c5be..0b1081c690cb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1355,6 +1355,8 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) if (dm_plane_state->degamma_lut) drm_property_blob_get(dm_plane_state->degamma_lut); + if (dm_plane_state->ctm) + drm_property_blob_get(dm_plane_state->ctm); if (dm_plane_state->shaper_lut) drm_property_blob_get(dm_plane_state->shaper_lut); if (dm_plane_state->lut3d) @@ -1436,6 +1438,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, if (dm_plane_state->degamma_lut) drm_property_blob_put(dm_plane_state->degamma_lut); + if (dm_plane_state->ctm) + drm_property_blob_put(dm_plane_state->ctm); if (dm_plane_state->lut3d) drm_property_blob_put(dm_plane_state->lut3d); if (dm_plane_state->shaper_lut) @@ -1473,6 +1477,11 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, dm->adev->mode_info.plane_hdr_mult_property, AMDGPU_HDR_MULT_DEFAULT); + /* Only enable plane CTM if both DPP and MPC gamut remap is available. */ + if (dm->dc->caps.color.mpc.gamut_remap) + drm_object_attach_property(>base, + dm->adev->mode_info.plane_ctm_property, 0); + if (dpp_color_caps.hw_3d_lut) { drm_object_attach_property(>base, mode_info.plane_shaper_lut_property, 0); @@ -1530,6 +1539,14 @@ dm_atomic_plane_set_property(struct drm_plane *plane, dm_plane_state->hdr_mult = val; dm_plane_state->base.color_mgmt_changed = 1; } + } else if (property == adev->mode_info.plane_ctm_property) { + ret = drm_property_replace_blob_from_id(plane->dev, +
[PATCH v2 29/34] drm/amd/display: allow newer DC hardware to use degamma ROM for PQ/HLG
From: Joshua Ashton Need to funnel the color caps through to these functions so it can check that the hardware is capable. v2: - remove redundant color caps assignment on plane degamma map (Harry) - pass color caps to degamma params Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 35 --- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index f638e5b3a70b..4356846a2bce 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -538,6 +538,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, /** * __set_input_tf - calculates the input transfer function based on expected * input space. + * @caps: dc color capabilities * @func: transfer function * @lut: lookup table that defines the color space * @lut_size: size of respective lut. @@ -545,7 +546,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, * Returns: * 0 in case of success. -ENOMEM if fails. */ -static int __set_input_tf(struct dc_transfer_func *func, +static int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func *func, const struct drm_color_lut *lut, uint32_t lut_size) { struct dc_gamma *gamma = NULL; @@ -562,7 +563,7 @@ static int __set_input_tf(struct dc_transfer_func *func, __drm_lut_to_dc_gamma(lut, gamma, false); } - res = mod_color_calculate_degamma_params(NULL, func, gamma, gamma != NULL); + res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != NULL); if (gamma) dc_gamma_release(); @@ -725,7 +726,7 @@ static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut, func_blend->tf = tf; func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; - ret = __set_input_tf(func_blend, blend_lut, blend_size); + ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size); } else { func_blend->type = TF_TYPE_BYPASS; func_blend->tf = TRANSFER_FUNCTION_LINEAR; @@ -950,7 +951,8 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) static int map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, -struct dc_plane_state *dc_plane_state) +struct dc_plane_state *dc_plane_state, +struct dc_color_caps *caps) { const struct drm_color_lut *degamma_lut; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; @@ -1005,7 +1007,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; - r = __set_input_tf(dc_plane_state->in_transfer_func, + r = __set_input_tf(caps, dc_plane_state->in_transfer_func, degamma_lut, degamma_size); if (r) return r; @@ -1018,7 +1020,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, dc_plane_state->in_transfer_func->tf = tf; if (tf != TRANSFER_FUNCTION_SRGB && - !mod_color_calculate_degamma_params(NULL, + !mod_color_calculate_degamma_params(caps, dc_plane_state->in_transfer_func, NULL, false)) return -ENOMEM; @@ -1029,7 +1031,8 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, static int __set_dm_plane_degamma(struct drm_plane_state *plane_state, - struct dc_plane_state *dc_plane_state) + struct dc_plane_state *dc_plane_state, + struct dc_color_caps *color_caps) { struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); const struct drm_color_lut *degamma_lut; @@ -1060,7 +1063,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; - ret = __set_input_tf(dc_plane_state->in_transfer_func, + ret = __set_input_tf(color_caps, dc_plane_state->in_transfer_func, degamma_lut, degamma_size); if (ret) return ret; @@ -1068,7 +1071,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED; - if (!mod_color_calculate_degamma_params(NULL, +
[PATCH v2 31/34] drm/amd/display: set stream gamut remap matrix to MPC for DCN301
dc->caps.color.mpc.gamut_remap says there is a post-blending color block for gamut remap matrix for DCN3 HW family and newer versions. However, those drivers still follow DCN10 programming that remap stream gamut_remap_matrix to DPP (pre-blending). To enable pre-blending and post-blending gamut_remap matrix supports at the same time, set stream gamut_remap to MPC and plane gamut_remap to DPP for DCN301 that support both. It was tested using IGT KMS color tests for DRM CRTC CTM property and it preserves test results. Signed-off-by: Melissa Wen --- .../drm/amd/display/dc/dcn30/dcn30_hwseq.c| 37 +++ .../drm/amd/display/dc/dcn30/dcn30_hwseq.h| 3 ++ .../drm/amd/display/dc/dcn301/dcn301_init.c | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 4cd4ae07d73d..4fb4e9ec03f1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -186,6 +186,43 @@ bool dcn30_set_input_transfer_func(struct dc *dc, return result; } +void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx) +{ + int i = 0; + struct dpp_grph_csc_adjustment dpp_adjust; + struct mpc_grph_gamut_adjustment mpc_adjust; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + + memset(_adjust, 0, sizeof(dpp_adjust)); + dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + if (pipe_ctx->plane_state && + pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { + dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + dpp_adjust.temperature_matrix[i] = + pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; + } + + pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, + _adjust); + + memset(_adjust, 0, sizeof(mpc_adjust)); + mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + if (pipe_ctx->top_pipe == NULL) { + if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { + mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + mpc_adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + } + } + + mpc->funcs->set_gamut_remap(mpc, mpcc_id, _adjust); +} + bool dcn30_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h index a24a8e33a3d2..cb34ca932a5f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h @@ -58,6 +58,9 @@ bool dcn30_set_blend_lut(struct pipe_ctx *pipe_ctx, bool dcn30_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); + +void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx); + bool dcn30_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream); diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c index 257df8660b4c..81fd50ee97c3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c @@ -33,7 +33,7 @@ #include "dcn301_init.h" static const struct hw_sequencer_funcs dcn301_funcs = { - .program_gamut_remap = dcn10_program_gamut_remap, + .program_gamut_remap = dcn30_program_gamut_remap, .init_hw = dcn10_init_hw, .power_down_on_boot = dcn10_power_down_on_boot, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, -- 2.40.1
[PATCH v2 30/34] drm/amd/display: copy 3D LUT settings from crtc state to stream_update
From: Joshua Ashton When commiting planes, we copy color mgmt resources to the stream state. Do the same for shaper and 3D LUTs. Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Co-developed-by: Melissa Wen Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 1 file changed, 4 insertions(+) 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 d37269a2179e..dfe61c5ed49e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8274,6 +8274,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, _state->stream->csc_color_matrix; bundle->stream_update.out_transfer_func = acrtc_state->stream->out_transfer_func; + bundle->stream_update.lut3d_func = + (struct dc_3dlut *) acrtc_state->stream->lut3d_func; + bundle->stream_update.func_shaper = + (struct dc_transfer_func *) acrtc_state->stream->func_shaper; } acrtc_state->stream->abm_level = acrtc_state->abm_level; -- 2.40.1
[PATCH v2 26/34] drm/amd/display: add plane 3D LUT support
Wire up DC 3D LUT to DM plane color management (pre-blending). On AMD display HW, 3D LUT comes after a shaper curve and we always have to program a shaper curve to delinearize or normalize the color space before applying a 3D LUT (since we have a reduced number of LUT entries). In this version, the default values of 3D LUT for size and bit_depth are 17x17x17 and 12-bit, but we already provide here a more generic mechanisms to program other supported values (9x9x9 size and 10-bit). v2: - started with plane 3D LUT instead of CRTC 3D LUT support Reviewed-by: Harry Wentland (v1) Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 96 ++- 2 files changed, 94 insertions(+), 3 deletions(-) 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 347ecff2c920..025a7eb5c8aa 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8062,6 +8062,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].gamut_remap_matrix = _plane->gamut_remap_matrix; bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func; + bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func; } amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 90ec09ca4118..58c4797f506e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -598,6 +598,85 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf) } } +static void __to_dc_lut3d_color(struct dc_rgb *rgb, + const struct drm_color_lut lut, + int bit_precision) +{ + rgb->red = drm_color_lut_extract(lut.red, bit_precision); + rgb->green = drm_color_lut_extract(lut.green, bit_precision); + rgb->blue = drm_color_lut_extract(lut.blue, bit_precision); +} + +static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut, + uint32_t lut3d_size, + struct tetrahedral_params *params, + bool use_tetrahedral_9, + int bit_depth) +{ + struct dc_rgb *lut0; + struct dc_rgb *lut1; + struct dc_rgb *lut2; + struct dc_rgb *lut3; + int lut_i, i; + + + if (use_tetrahedral_9) { + lut0 = params->tetrahedral_9.lut0; + lut1 = params->tetrahedral_9.lut1; + lut2 = params->tetrahedral_9.lut2; + lut3 = params->tetrahedral_9.lut3; + } else { + lut0 = params->tetrahedral_17.lut0; + lut1 = params->tetrahedral_17.lut1; + lut2 = params->tetrahedral_17.lut2; + lut3 = params->tetrahedral_17.lut3; + } + + for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) { + /* We should consider the 3dlut RGB values are distributed +* along four arrays lut0-3 where the first sizes 1229 and the +* other 1228. The bit depth supported for 3dlut channel is +* 12-bit, but DC also supports 10-bit. +* +* TODO: improve color pipeline API to enable the userspace set +* bit depth and 3D LUT size/stride, as specified by VA-API. +*/ + __to_dc_lut3d_color([lut_i], lut[i], bit_depth); + __to_dc_lut3d_color([lut_i], lut[i + 1], bit_depth); + __to_dc_lut3d_color([lut_i], lut[i + 2], bit_depth); + __to_dc_lut3d_color([lut_i], lut[i + 3], bit_depth); + } + /* lut0 has 1229 points (lut_size/4 + 1) */ + __to_dc_lut3d_color([lut_i], lut[i], bit_depth); +} + +/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream + * @drm_lut3d: DRM CRTC (user) 3D LUT + * @drm_lut3d_size: size of 3D LUT + * @lut3d: DC 3D LUT + * + * Map DRM CRTC 3D LUT to DC 3D LUT and all necessary bits to program it + * on DCN MPC accordingly. + */ +static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut, + uint32_t drm_lut3d_size, + struct dc_3dlut *lut) +{ + if (!drm_lut3d_size) { + lut->state.bits.initialized = 0; + } else { + /* Stride and bit depth are not programmable by API yet. +* Therefore, only supports 17x17x17 3D LUT (12-bit).
[PATCH v2 28/34] drm/amd/display: add plane blend LUT and TF support
From: Joshua Ashton Map plane blend properties to DPP blend gamma. Plane blend is a post-3D LUT curve that linearizes color space for blending. It may be defined by a user-blob LUT and/or predefined transfer function. As hardcoded curve (ROM) is not supported on blend gamma, we use AMD color module to fill parameters when setting non-linear TF with empty LUT. v2: - rename DRM TFs to AMDGPU TFs Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 55 +-- 2 files changed, 52 insertions(+), 4 deletions(-) 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 025a7eb5c8aa..d37269a2179e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8063,6 +8063,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func; bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func; + bundle->surface_updates[planes_count].blend_tf = dc_plane->blend_tf; } amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 2c96501d2fc0..f638e5b3a70b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -706,6 +706,34 @@ static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, return ret; } +static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut, + bool has_rom, + enum dc_transfer_func_predefined tf, + uint32_t blend_size, + struct dc_transfer_func *func_blend) +{ + int ret = 0; + + if (blend_size || tf != TRANSFER_FUNCTION_LINEAR) { + /* DRM plane gamma LUT or TF means we are linearizing color +* space before blending (similar to degamma programming). As +* we don't have hardcoded curve support, or we use AMD color +* module to fill the parameters that will be translated to HW +* points. +*/ + func_blend->type = TF_TYPE_DISTRIBUTED_POINTS; + func_blend->tf = tf; + func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + + ret = __set_input_tf(func_blend, blend_lut, blend_size); + } else { + func_blend->type = TF_TYPE_BYPASS; + func_blend->tf = TRANSFER_FUNCTION_LINEAR; + } + + return ret; +} + /* amdgpu_dm_lut3d_size - get expected size according to hw color caps * @adev: amdgpu device * @lut_size: default size @@ -1053,8 +1081,9 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, { struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); enum amdgpu_transfer_function shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; - const struct drm_color_lut *shaper_lut, *lut3d; - uint32_t shaper_size, lut3d_size; + enum amdgpu_transfer_function blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + const struct drm_color_lut *shaper_lut, *lut3d, *blend_lut; + uint32_t shaper_size, lut3d_size, blend_size; int ret; /* We have nothing to do here, return */ @@ -1074,12 +1103,30 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, amdgpu_tf_to_dc_tf(shaper_tf), shaper_size, dc_plane_state->in_shaper_func); - if (ret) + if (ret) { drm_dbg_kms(plane_state->plane->dev, "setting plane %d shaper LUT failed.\n", plane_state->plane->index); - return ret; + return ret; + } + + blend_tf = dm_plane_state->blend_tf; + blend_lut = __extract_blob_lut(dm_plane_state->blend_lut, _size); + blend_size = blend_lut != NULL ? blend_size : 0; + + ret = amdgpu_dm_atomic_blend_lut(blend_lut, false, +amdgpu_tf_to_dc_tf(blend_tf), +blend_size, dc_plane_state->blend_tf); + if (ret) { + drm_dbg_kms(plane_state->plane->dev, + "setting plane %d gamma lut
[PATCH v2 24/34] drm/amd/display: add plane shaper LUT support
Map DC shaper LUT to DM plane color management. Shaper LUT can be used to delinearize and/or normalize the color space for computational efficiency and achiving specific visual styles. If a plane degamma is apply to linearize the color space, a custom shaper 1D LUT can be used just before applying 3D LUT. v2: - use DPP color caps to verify plane 3D LUT support - add debug message if shaper LUT programming fails Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 108 +- 3 files changed, 107 insertions(+), 4 deletions(-) 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 9fcc169fb87b..347ecff2c920 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8061,6 +8061,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func; bundle->surface_updates[planes_count].gamut_remap_matrix = _plane->gamut_remap_matrix; bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; + bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func; } amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, 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 23e3984f17fb..095f39f04210 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -893,6 +893,8 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); /* 3D LUT max size is 17x17x17 */ #define MAX_COLOR_3DLUT_ENTRIES 4913 #define MAX_COLOR_3DLUT_BITDEPTH 12 +int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, + struct drm_plane_state *plane_state); /* 1D LUT size */ #define MAX_COLOR_LUT_ENTRIES 4096 /* Legacy gamm LUT users such as X doesn't like large LUT sizes */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 15f7304d8f33..958bb5a5644d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -598,6 +598,74 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf) } } +static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, + uint32_t shaper_size, + struct dc_transfer_func *func_shaper) +{ + int ret = 0; + + if (shaper_size) { + /* If DRM shaper LUT is set, we assume a linear color space +* (linearized by DRM degamma 1D LUT or not) +*/ + func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS; + func_shaper->tf = TRANSFER_FUNCTION_LINEAR; + + ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, false); + } else { + func_shaper->type = TF_TYPE_BYPASS; + func_shaper->tf = TRANSFER_FUNCTION_LINEAR; + } + + return ret; +} + +/* amdgpu_dm_lut3d_size - get expected size according to hw color caps + * @adev: amdgpu device + * @lut_size: default size + * + * Return: + * lut_size if DC 3D LUT is supported, zero otherwise. + */ +static uint32_t amdgpu_dm_get_lut3d_size(struct amdgpu_device *adev, +uint32_t lut_size) +{ + return adev->dm.dc->caps.color.dpp.hw_3d_lut ? lut_size : 0; +} + +/** + * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if DRM 3D + * LUT matches the hw supported size + * @adev: amdgpu device + * @crtc_state: the DRM CRTC state + * + * Verifies if post-blending (MPC) 3D LUT is supported by the HW (DCN 3.0 or + * newer) and if the DRM 3D LUT matches the supported size. + * + * Returns: + * 0 on success. -EINVAL if lut size are invalid. + */ +int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, + struct drm_plane_state *plane_state) +{ + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + const struct drm_color_lut *shaper = NULL; + uint32_t exp_size, size; + + /* shaper LUT is only available if 3D LUT color caps*/ + exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_LUT_ENTRIES); + shaper = __extract_blob_lut(dm_plane_state->shaper_lut, ); + + if (shaper && size != exp_size) { + drm_dbg(>ddev, + "Invalid Shaper LUT size. Should be %u but got %u.\n", + exp_size, size); + return
[PATCH v2 27/34] drm/amd/display: handle empty LUTs in __set_input_tf
From: Joshua Ashton Unlike degamma, blend gamma doesn't support hardcoded curve (predefined/ROM), but we can use AMD color module to fill blend gamma parameters when we have non-linear plane gamma TF without plane gamma LUT. The regular degamma path doesn't hit this. Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 20 +++ 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 58c4797f506e..2c96501d2fc0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -551,17 +551,21 @@ static int __set_input_tf(struct dc_transfer_func *func, struct dc_gamma *gamma = NULL; bool res; - gamma = dc_create_gamma(); - if (!gamma) - return -ENOMEM; + if (lut_size) { + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; - gamma->type = GAMMA_CUSTOM; - gamma->num_entries = lut_size; + gamma->type = GAMMA_CUSTOM; + gamma->num_entries = lut_size; - __drm_lut_to_dc_gamma(lut, gamma, false); + __drm_lut_to_dc_gamma(lut, gamma, false); + } - res = mod_color_calculate_degamma_params(NULL, func, gamma, true); - dc_gamma_release(); + res = mod_color_calculate_degamma_params(NULL, func, gamma, gamma != NULL); + + if (gamma) + dc_gamma_release(); return res ? 0 : -ENOMEM; } -- 2.40.1
[PATCH v2 25/34] drm/amd/display: add plane shaper TF support
Enable usage of predefined transfer func in addition to shaper 1D LUT. That means we can save some complexity by just setting a predefined curve, instead of programming a custom curve when preparing color space for applying 3D LUT. Reviewed-by: Harry Wentland Signed-off-by: Melissa Wen --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 958bb5a5644d..90ec09ca4118 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -599,19 +599,22 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf) } static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, + bool has_rom, + enum dc_transfer_func_predefined tf, uint32_t shaper_size, struct dc_transfer_func *func_shaper) { int ret = 0; - if (shaper_size) { + if (shaper_size || tf != TRANSFER_FUNCTION_LINEAR) { /* If DRM shaper LUT is set, we assume a linear color space * (linearized by DRM degamma 1D LUT or not) */ func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS; - func_shaper->tf = TRANSFER_FUNCTION_LINEAR; + func_shaper->tf = tf; + func_shaper->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; - ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, false); + ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, has_rom); } else { func_shaper->type = TF_TYPE_BYPASS; func_shaper->tf = TRANSFER_FUNCTION_LINEAR; @@ -958,6 +961,7 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, struct dc_plane_state *dc_plane_state) { struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + enum amdgpu_transfer_function shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; const struct drm_color_lut *shaper_lut; uint32_t shaper_size; int ret; @@ -970,8 +974,11 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, shaper_lut = __extract_blob_lut(dm_plane_state->shaper_lut, _size); shaper_size = shaper_lut != NULL ? shaper_size : 0; + shaper_tf = dm_plane_state->shaper_tf; - ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, shaper_size, + ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false, + amdgpu_tf_to_dc_tf(shaper_tf), + shaper_size, dc_plane_state->in_shaper_func); if (ret) drm_dbg_kms(plane_state->plane->dev, -- 2.40.1
[PATCH v2 22/34] drm/amd/display: add dc_fixpt_from_s3132 helper
From: Joshua Ashton Detach value translation from CTM to reuse it for programming HDR multiplier property. Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 8 +--- drivers/gpu/drm/amd/display/include/fixed31_32.h | 12 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 5659f88d1f2c..db771c895720 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -383,7 +383,6 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut, static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, struct fixed31_32 *matrix) { - int64_t val; int i; /* @@ -402,12 +401,7 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, } /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ - val = ctm->matrix[i - (i / 4)]; - /* If negative, convert to 2's complement. */ - if (val & (1ULL << 63)) - val = -(val & ~(1ULL << 63)); - - matrix[i].value = val; + matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i - (i / 4)]); } } diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h index d4cf7ead1d87..84da1dd34efd 100644 --- a/drivers/gpu/drm/amd/display/include/fixed31_32.h +++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h @@ -69,6 +69,18 @@ static const struct fixed31_32 dc_fixpt_epsilon = { 1LL }; static const struct fixed31_32 dc_fixpt_half = { 0x8000LL }; static const struct fixed31_32 dc_fixpt_one = { 0x1LL }; +static inline struct fixed31_32 dc_fixpt_from_s3132(__u64 x) +{ + struct fixed31_32 val; + + /* If negative, convert to 2's complement. */ + if (x & (1ULL << 63)) + x = -(x & ~(1ULL << 63)); + + val.value = x; + return val; +} + /* * @brief * Initialization routines -- 2.40.1
[PATCH v2 23/34] drm/amd/display: add HDR multiplier support
From: Joshua Ashton With `dc_fixpt_from_s3132()` translation, we can just use it to set hdr_mult. Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 3 +++ 2 files changed, 4 insertions(+) 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 3e5aa1e46662..9fcc169fb87b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8060,6 +8060,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].gamma = dc_plane->gamma_correction; bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func; bundle->surface_updates[planes_count].gamut_remap_matrix = _plane->gamut_remap_matrix; + bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; } amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index db771c895720..15f7304d8f33 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -902,6 +902,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, struct drm_plane_state *plane_state, struct dc_plane_state *dc_plane_state) { + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); bool has_crtc_cm_degamma; int ret; @@ -912,6 +913,8 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, /* After, we start to update values according to color props */ has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); + dc_plane_state->hdr_mult = dc_fixpt_from_s3132(dm_plane_state->hdr_mult); + ret = __set_dm_plane_degamma(plane_state, dc_plane_state); if (ret == -ENOMEM) return ret; -- 2.40.1
[PATCH v2 19/34] drm/amd/display: decouple steps for mapping CRTC degamma to DC plane
The next patch adds pre-blending degamma to AMD color mgmt pipeline, but pre-blending degamma caps (DPP) is currently in use to provide DRM CRTC atomic degamma or implict degamma on legacy gamma. Detach degamma usage regarging CRTC color properties to manage plane and CRTC color correction combinations. Reviewed-by: Harry Wentland Signed-off-by: Melissa Wen --- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 59 +-- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 68e9f2c62f2e..74eb02655d96 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -764,20 +764,9 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) return 0; } -/** - * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. - * @crtc: amdgpu_dm crtc state - * @dc_plane_state: target DC surface - * - * Update the underlying dc_stream_state's input transfer function (ITF) in - * preparation for hardware commit. The transfer function used depends on - * the preparation done on the stream for color management. - * - * Returns: - * 0 on success. -ENOMEM if mem allocation fails. - */ -int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, - struct dc_plane_state *dc_plane_state) +static int +map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, +struct dc_plane_state *dc_plane_state) { const struct drm_color_lut *degamma_lut; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; @@ -800,8 +789,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, _size); ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES); - dc_plane_state->in_transfer_func->type = - TF_TYPE_DISTRIBUTED_POINTS; + dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; /* * This case isn't fully correct, but also fairly @@ -837,7 +825,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, degamma_lut, degamma_size); if (r) return r; - } else if (crtc->cm_is_degamma_srgb) { + } else { /* * For legacy gamma support we need the regamma input * in linear space. Assume that the input is sRGB. @@ -847,8 +835,43 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, if (tf != TRANSFER_FUNCTION_SRGB && !mod_color_calculate_degamma_params(NULL, - dc_plane_state->in_transfer_func, NULL, false)) + dc_plane_state->in_transfer_func, + NULL, false)) return -ENOMEM; + } + + return 0; +} + +/** + * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. + * @crtc: amdgpu_dm crtc state + * @dc_plane_state: target DC surface + * + * Update the underlying dc_stream_state's input transfer function (ITF) in + * preparation for hardware commit. The transfer function used depends on + * the preparation done on the stream for color management. + * + * Returns: + * 0 on success. -ENOMEM if mem allocation fails. + */ +int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct dc_plane_state *dc_plane_state) +{ + bool has_crtc_cm_degamma; + int ret; + + has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); + if (has_crtc_cm_degamma){ + /* AMD HW doesn't have post-blending degamma caps. When DRM +* CRTC atomic degamma is set, we maps it to DPP degamma block +* (pre-blending) or, on legacy gamma, we use DPP degamma to +* linearize (implicit degamma) from sRGB/BT709 according to +* the input space. +*/ + ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state); + if (ret) + return ret; } else { /* ...Otherwise we can just bypass the DGM block. */ dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; -- 2.40.1
[PATCH v2 20/34] drm/amd/display: add plane degamma TF and LUT support
From: Joshua Ashton Set DC plane with user degamma LUT or predefined TF from driver-specific plane color properties. If plane and CRTC degamma are set in the same time, plane degamma has priority. That means, we only set CRTC degamma if we don't have plane degamma LUT or TF to configure. We return -EINVAL if we don't have plane degamma settings, so we can continue and check CRTC degamma. Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 70 +-- 3 files changed, 69 insertions(+), 6 deletions(-) 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 78fdd0b95ae8..3e5aa1e46662 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5009,7 +5009,9 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, * Always set input transfer function, since plane state is refreshed * every time. */ - ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state); + ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, + plane_state, + dc_plane_state); if (ret) return ret; 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 51471675c298..23e3984f17fb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -903,6 +903,7 @@ int amdgpu_dm_create_color_properties(struct amdgpu_device *adev); int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state); int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc); int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct drm_plane_state *plane_state, struct dc_plane_state *dc_plane_state); void amdgpu_dm_update_connector_after_detect( diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 74eb02655d96..d019a091b08e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -843,9 +843,58 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, return 0; } +static int +__set_dm_plane_degamma(struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state) +{ + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + const struct drm_color_lut *degamma_lut; + enum amdgpu_transfer_function tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + uint32_t degamma_size; + bool has_degamma_lut; + int ret; + + degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut, +_size); + + has_degamma_lut = degamma_lut && + !__is_lut_linear(degamma_lut, degamma_size); + + tf = dm_plane_state->degamma_tf; + + /* If we don't have plane degamma LUT nor TF to set on DC, we have +* nothing to do here, return. +*/ + if (!has_degamma_lut && tf == AMDGPU_TRANSFER_FUNCTION_DEFAULT) + return -EINVAL; + + dc_plane_state->in_transfer_func->tf = amdgpu_tf_to_dc_tf(tf); + + if (has_degamma_lut) { + ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES); + + dc_plane_state->in_transfer_func->type = + TF_TYPE_DISTRIBUTED_POINTS; + + ret = __set_input_tf(dc_plane_state->in_transfer_func, +degamma_lut, degamma_size); + if (ret) + return ret; + } else { + dc_plane_state->in_transfer_func->type = + TF_TYPE_PREDEFINED; + + if (!mod_color_calculate_degamma_params(NULL, + dc_plane_state->in_transfer_func, NULL, false)) + return -ENOMEM; + } + return 0; +} + /** * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. * @crtc: amdgpu_dm crtc state + * @plane_state: DRM plane state * @dc_plane_state: target DC surface * * Update the underlying dc_stream_state's input transfer function (ITF) in @@ -856,13 +905,28 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, * 0 on success. -ENOMEM if mem allocation fails. */ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct drm_plane_state *plane_state, struct
[PATCH v2 21/34] drm/amd/display: reject atomic commit if setting both plane and CRTC degamma
DC only has pre-blending degamma caps (plane/DPP) that is currently in use for CRTC/post-blending degamma, so that we don't have HW caps to perform plane and CRTC degamma at the same time. Reject atomic updates when serspace sets both plane and CRTC degamma properties. Reviewed-by: Harry Wentland Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index d019a091b08e..5659f88d1f2c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -919,9 +919,20 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); ret = __set_dm_plane_degamma(plane_state, dc_plane_state); - if (ret != -EINVAL) + if (ret == -ENOMEM) return ret; + /* We only have one degamma block available (pre-blending) for the +* whole color correction pipeline, so that we can't actually perform +* plane and CRTC degamma at the same time. Explicitly reject atomic +* updates when userspace sets both plane and CRTC degamma properties. +*/ + if (has_crtc_cm_degamma && ret != -EINVAL){ + drm_dbg_kms(crtc->base.crtc->dev, + "doesn't support plane and CRTC degamma at the same time\n"); + return -EINVAL; + } + /* If we are here, it means we don't have plane degamma settings, check * if we have CRTC degamma waiting for mapping to pre-blending degamma * block -- 2.40.1
[PATCH v2 14/34] drm/amd/display: add comments to describe DM crtc color mgmt behavior
Describe some expected behavior of the AMD DM color mgmt programming. Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 841e0391f7fb..0a9aa162d4a0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -640,12 +640,23 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + /* Note: although we pass has_rom as parameter here, we never +* actually use ROM because the color module only takes the ROM +* path if transfer_func->type == PREDEFINED. +* +* See more in mod_color_calculate_regamma_params() +*/ r = __set_legacy_tf(stream->out_transfer_func, regamma_lut, regamma_size, has_rom); if (r) return r; } else if (has_regamma) { - /* If atomic regamma, CRTC RGM goes into RGM LUT. */ + /* CRTC RGM goes into RGM LUT. +* +* Note: there is no implicit sRGB regamma here. We are using +* degamma calculation from color module to calculate the curve +* from a linear base. +*/ stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; -- 2.40.1
[PATCH v2 18/34] drm/amd/display: mark plane as needing reset if color props change
From: Joshua Ashton We should reset a plane state if at least one of the color management properties differs from old and new state. Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Co-developed-by: Melissa Wen Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 +++ 1 file changed, 15 insertions(+) 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 272974b88cda..78fdd0b95ae8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -9524,6 +9524,10 @@ static bool should_reset_plane(struct drm_atomic_state *state, */ for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) { struct amdgpu_framebuffer *old_afb, *new_afb; + struct dm_plane_state *dm_new_other_state, *dm_old_other_state; + + dm_new_other_state = to_dm_plane_state(new_other_state); + dm_old_other_state = to_dm_plane_state(old_other_state); if (other->type == DRM_PLANE_TYPE_CURSOR) continue; @@ -9560,6 +9564,17 @@ static bool should_reset_plane(struct drm_atomic_state *state, old_other_state->color_encoding != new_other_state->color_encoding) return true; + /* HDR/Transfer Function changes. */ + if (dm_old_other_state->degamma_tf != dm_new_other_state->degamma_tf || + dm_old_other_state->degamma_lut != dm_new_other_state->degamma_lut || + dm_old_other_state->hdr_mult != dm_new_other_state->hdr_mult || + dm_old_other_state->shaper_lut != dm_new_other_state->shaper_lut || + dm_old_other_state->shaper_tf != dm_new_other_state->shaper_tf || + dm_old_other_state->lut3d != dm_new_other_state->lut3d || + dm_old_other_state->blend_lut != dm_new_other_state->blend_lut || + dm_old_other_state->blend_tf != dm_new_other_state->blend_tf) + return true; + /* Framebuffer checks fall at the end. */ if (!old_other_state->fb || !new_other_state->fb) continue; -- 2.40.1
[PATCH v2 17/34] drm/amd/display: set sdr_ref_white_level to 80 for out_transfer_func
From: Joshua Ashton Otherwise this is just initialized to 0. This needs to actually have a value so that compute_curve can work for PQ EOTF. Reviewed-by: Harry Wentland Signed-off-by: Joshua Ashton Co-developed-by: Melissa Wen Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 0188e82d1fdd..68e9f2c62f2e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -72,6 +72,7 @@ */ #define MAX_DRM_LUT_VALUE 0x +#define SDR_WHITE_LEVEL_INIT_VALUE 80 /** * amdgpu_dm_init_color_mod - Initialize the color module. @@ -525,6 +526,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, */ out_tf->type = TF_TYPE_DISTRIBUTED_POINTS; out_tf->tf = tf; + out_tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom); } else { -- 2.40.1
[PATCH v2 16/34] drm/amd/display: add CRTC gamma TF support
From: Joshua Ashton Add predefined transfer function programming. There is no pre-blending out gamma ROM, but we can use AMD color modules to program LUT parameters from a pre-defined TF and an empty regamma LUT (or bump up LUT parameters with pre-defined TF setup). v2: - update crtc color mgmt if regamma TF differs between states (Joshua) - map inverse EOTF to DC transfer function (Melissa) Signed-off-by: Joshua Ashton Co-developed-by: Melissa Wen Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 73 +++ 2 files changed, 58 insertions(+), 16 deletions(-) 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 77b4d671a9e0..272974b88cda 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -9456,6 +9456,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * when a modeset is needed, to ensure it gets reprogrammed. */ if (dm_new_crtc_state->base.color_mgmt_changed || + dm_old_crtc_state->regamma_tf != dm_new_crtc_state->regamma_tf || drm_atomic_crtc_needs_modeset(new_crtc_state)) { ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state); if (ret) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index c0bf55416b4d..0188e82d1fdd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -468,16 +468,18 @@ static int __set_output_tf(struct dc_transfer_func *func, struct calculate_buffer cal_buffer = {0}; bool res; - ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES); - cal_buffer.buffer_index = -1; - gamma = dc_create_gamma(); - if (!gamma) - return -ENOMEM; + if (lut_size) { + ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES); - gamma->num_entries = lut_size; - __drm_lut_to_dc_gamma(lut, gamma, false); + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; + + gamma->num_entries = lut_size; + __drm_lut_to_dc_gamma(lut, gamma, false); + } if (func->tf == TRANSFER_FUNCTION_LINEAR) { /* @@ -485,32 +487,36 @@ static int __set_output_tf(struct dc_transfer_func *func, * on top of a linear input. But degamma params can be used * instead to simulate this. */ - gamma->type = GAMMA_CUSTOM; + if (gamma) + gamma->type = GAMMA_CUSTOM; res = mod_color_calculate_degamma_params(NULL, func, - gamma, true); +gamma, gamma != NULL); } else { /* * Assume sRGB. The actual mapping will depend on whether the * input was legacy or not. */ - gamma->type = GAMMA_CS_TFM_1D; - res = mod_color_calculate_regamma_params(func, gamma, false, + if (gamma) + gamma->type = GAMMA_CS_TFM_1D; + res = mod_color_calculate_regamma_params(func, gamma, gamma != NULL, has_rom, NULL, _buffer); } - dc_gamma_release(); + if (gamma) + dc_gamma_release(); return res ? 0 : -ENOMEM; } static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, const struct drm_color_lut *regamma_lut, - uint32_t regamma_size, bool has_rom) + uint32_t regamma_size, bool has_rom, + enum dc_transfer_func_predefined tf) { struct dc_transfer_func *out_tf = stream->out_transfer_func; int ret = 0; - if (regamma_size) { + if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) { /* CRTC RGM goes into RGM LUT. * * Note: there is no implicit sRGB regamma here. We are using @@ -518,7 +524,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, * from a linear base. */ out_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - out_tf->tf = TRANSFER_FUNCTION_LINEAR; + out_tf->tf = tf; ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom); } else { @@ -564,6 +570,38 @@ static int __set_input_tf(struct dc_transfer_func *func, return res ? 0 : -ENOMEM;
[PATCH v2 15/34] drm/amd/display: encapsulate atomic regamma operation
We will wire up MPC 3D LUT to DM CRTC color pipeline in the next patch, but so far, only for atomic interface. By checking set_output_transfer_func in DC drivers with MPC 3D LUT support, we can verify that regamma is only programmed when 3D LUT programming fails. As a groundwork to introduce 3D LUT programming and better understand each step, detach atomic regamma programming from the crtc colocr updating code. Reviewed-by: Harry Wentland Signed-off-by: Melissa Wen --- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 53 --- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 0a9aa162d4a0..c0bf55416b4d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -503,6 +503,36 @@ static int __set_output_tf(struct dc_transfer_func *func, return res ? 0 : -ENOMEM; } +static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, + const struct drm_color_lut *regamma_lut, + uint32_t regamma_size, bool has_rom) +{ + struct dc_transfer_func *out_tf = stream->out_transfer_func; + int ret = 0; + + if (regamma_size) { + /* CRTC RGM goes into RGM LUT. +* +* Note: there is no implicit sRGB regamma here. We are using +* degamma calculation from color module to calculate the curve +* from a linear base. +*/ + out_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + out_tf->tf = TRANSFER_FUNCTION_LINEAR; + + ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom); + } else { + /* +* No CRTC RGM means we can just put the block into bypass +* since we don't have any plane level adjustments using it. +*/ + out_tf->type = TF_TYPE_BYPASS; + out_tf->tf = TRANSFER_FUNCTION_LINEAR; + } + + return ret; +} + /** * __set_input_tf - calculates the input transfer function based on expected * input space. @@ -650,27 +680,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) regamma_size, has_rom); if (r) return r; - } else if (has_regamma) { - /* CRTC RGM goes into RGM LUT. -* -* Note: there is no implicit sRGB regamma here. We are using -* degamma calculation from color module to calculate the curve -* from a linear base. -*/ - stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; - stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; - - r = __set_output_tf(stream->out_transfer_func, regamma_lut, - regamma_size, has_rom); + } else { + regamma_size = has_regamma ? regamma_size : 0; + r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut, +regamma_size, has_rom); if (r) return r; - } else { - /* -* No CRTC RGM means we can just put the block into bypass -* since we don't have any plane level adjustments using it. -*/ - stream->out_transfer_func->type = TF_TYPE_BYPASS; - stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; } /* -- 2.40.1
[PATCH v2 12/34] drm/amd/display: add plane blend LUT and TF driver-specific properties
From: Joshua Ashton Blend 1D LUT or a pre-defined transfer function can be set to linearize content before blending, so that it's positioned just before blending planes in the AMD color mgmt pipeline, and after 3D LUT (non-linear space). Shaper and Blend LUTs are 1D LUTs that sandwich 3D LUT. Drivers should advertize blend properties according to HW caps. Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 18 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 +++ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 21 +++ .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 36 +++ 4 files changed, 87 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 4fb164204ee6..fd0b7047d56b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -389,6 +389,24 @@ struct amdgpu_mode_info { * size of 3D LUT as supported by the driver (read-only). */ struct drm_property *plane_lut3d_size_property; + /** +* @plane_blend_lut_property: Plane property for output gamma before +* blending. Userspace set a blend LUT to convert colors after 3D LUT +* conversion. It works as a post-3D LUT 1D LUT, with shaper LUT, they +* are sandwiching 3D LUT with two 1D LUT. +*/ + struct drm_property *plane_blend_lut_property; + /** +* @plane_blend_lut_size_property: Plane property to define the max +* size of blend LUT as supported by the driver (read-only). +*/ + struct drm_property *plane_blend_lut_size_property; + /** +* @plane_blend_tf_property: Plane property to set a predefined +* transfer function for pre-blending blend (before applying 3D LUT) +* with or without LUT. +*/ + struct drm_property *plane_blend_tf_property; }; #define AMDGPU_MAX_BL_LEVEL 0xFF 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 6b6c2980f0af..b6fa271ab0dd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -785,6 +785,18 @@ struct dm_plane_state { * drm_color_lut. */ struct drm_property_blob *lut3d; + /** +* @blend_lut: blend lut lookup table blob. The blob (if not NULL) is an +* array of drm_color_lut. +*/ + struct drm_property_blob *blend_lut; + /** +* @blend_tf: +* +* Pre-defined transfer function for converting plane pixel data before +* applying blend LUT. +*/ + enum amdgpu_transfer_function blend_tf; }; struct dm_crtc_state { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index fbcee717bf0a..2d64332e6b80 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -252,6 +252,27 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.plane_lut3d_size_property = prop; + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_BLEND_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), +DRM_MODE_PROP_IMMUTABLE, +"AMD_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_lut_size_property = prop; + + prop = amdgpu_create_tf_property(adev_to_drm(adev), +"AMD_PLANE_BLEND_TF", +amdgpu_eotf); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_tf_property = prop; + return 0; } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 8d6ddf19bb87..3fd57de7c5be 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1333,6 +1333,7 @@ static void dm_drm_plane_reset(struct drm_plane *plane) amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; amdgpu_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + amdgpu_state->blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; } static struct drm_plane_state * @@ -1358,10 +1359,13 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane)
[PATCH v2 13/34] drm/amd/display: add CRTC gamma TF driver-specific property
Add AMD pre-defined transfer function property to default DRM CRTC gamma to convert to wire encoding with or without a user gamma LUT. v2: - enable CRTC prop in the end of driver-specific prop sequence - define inverse EOTFs as supported regamma TFs - reword driver-specific function doc to remove shaper/3D LUT Co-developed-by: Joshua Ashton Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 5 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 8 +++ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 7 ++ .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c| 72 +++ 4 files changed, 92 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index fd0b7047d56b..abb871a912d7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -407,6 +407,11 @@ struct amdgpu_mode_info { * with or without LUT. */ struct drm_property *plane_blend_tf_property; + /* @regamma_tf_property: Transfer function for CRTC regamma +* (post-blending). Possible values are defined by `enum +* amdgpu_transfer_function`. +*/ + struct drm_property *regamma_tf_property; }; #define AMDGPU_MAX_BL_LEVEL 0xFF 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 b6fa271ab0dd..51471675c298 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -821,6 +821,14 @@ struct dm_crtc_state { struct dc_info_packet vrr_infopacket; int abm_level; + +/** +* @regamma_tf: +* +* Pre-defined transfer function for converting internal FB -> wire +* encoding. +*/ + enum amdgpu_transfer_function regamma_tf; }; #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 2d64332e6b80..841e0391f7fb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -273,6 +273,13 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.plane_blend_tf_property = prop; + prop = amdgpu_create_tf_property(adev_to_drm(adev), +"AMD_CRTC_REGAMMA_TF", +amdgpu_inv_eotf); + if (!prop) + return -ENOMEM; + adev->mode_info.regamma_tf_property = prop; + return 0; } #endif 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 440fc0869a34..d746f0aa0f11 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 @@ -253,6 +253,7 @@ static struct drm_crtc_state *dm_crtc_duplicate_state(struct drm_crtc *crtc) state->freesync_config = cur->freesync_config; state->cm_has_degamma = cur->cm_has_degamma; state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb; + state->regamma_tf = cur->regamma_tf; state->crc_skip_count = cur->crc_skip_count; state->mpo_requested = cur->mpo_requested; /* TODO Duplicate dc_stream after objects are stream object is flattened */ @@ -289,6 +290,70 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc) } #endif +#ifdef AMD_PRIVATE_COLOR +/** + * drm_crtc_additional_color_mgmt - enable additional color properties + * @crtc: DRM CRTC + * + * This function lets the driver enable post-blending CRTC regamma transfer + * function property in addition to DRM CRTC gamma LUT. Default value means + * linear transfer function, which is the default CRTC gamma LUT behaviour + * without this property. + */ +static void +dm_crtc_additional_color_mgmt(struct drm_crtc *crtc) +{ + struct amdgpu_device *adev = drm_to_adev(crtc->dev); + + if(adev->dm.dc->caps.color.mpc.ogam_ram) + drm_object_attach_property(>base, + adev->mode_info.regamma_tf_property, + AMDGPU_TRANSFER_FUNCTION_DEFAULT); +} + +static int +amdgpu_dm_atomic_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_property *property, + uint64_t val) +{ + struct amdgpu_device *adev = drm_to_adev(crtc->dev); + struct dm_crtc_state *acrtc_state = to_dm_crtc_state(state); + + if (property == adev->mode_info.regamma_tf_property) { + if (acrtc_state->regamma_tf != val) { +
[PATCH v2 10/34] drm/amd/display: add plane 3D LUT driver-specific properties
Add 3D LUT property for plane gamma correction using a 3D lookup table. Since a 3D LUT has a limited number of entries in each dimension we want to use them in an optimal fashion. This means using the 3D LUT in a colorspace that is optimized for human vision, such as sRGB, PQ, or another non-linear space. Therefore, userpace may need one 1D LUT (shaper) before it to delinearize content and another 1D LUT after 3D LUT (blend) to linearize content again for blending. The next patches add these 1D LUTs to the plane color mgmt pipeline. Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 10 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 9 .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 14 +++ .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 23 +++ 4 files changed, 56 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 66bae0eed80c..730a88236501 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -363,6 +363,16 @@ struct amdgpu_mode_info { * @plane_hdr_mult_property: */ struct drm_property *plane_hdr_mult_property; + /** +* @plane_lut3d_property: Plane property for gamma correction using a +* 3D LUT (pre-blending). +*/ + struct drm_property *plane_lut3d_property; + /** +* @plane_degamma_lut_size_property: Plane property to define the max +* size of 3D LUT as supported by the driver (read-only). +*/ + struct drm_property *plane_lut3d_size_property; }; #define AMDGPU_MAX_BL_LEVEL 0xFF 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 44f17ac11a5f..deea90212e31 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -769,6 +769,11 @@ struct dm_plane_state { * S31.32 sign-magnitude. */ __u64 hdr_mult; + /** +* @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of +* drm_color_lut. +*/ + struct drm_property_blob *lut3d; }; struct dm_crtc_state { @@ -854,6 +859,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); +/* 3D LUT max size is 17x17x17 */ +#define MAX_COLOR_3DLUT_ENTRIES 4913 +#define MAX_COLOR_3DLUT_BITDEPTH 12 +/* 1D LUT size */ #define MAX_COLOR_LUT_ENTRIES 4096 /* Legacy gamm LUT users such as X doesn't like large LUT sizes */ #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index b891aaf5f7c1..7e6d4df99a0c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -209,6 +209,20 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.plane_hdr_mult_property = prop; + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_LUT3D", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_lut3d_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), +DRM_MODE_PROP_IMMUTABLE, +"AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_lut3d_size_property = prop; + return 0; } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index ab7f0332c431..882391f7add6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1353,6 +1353,8 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) if (dm_plane_state->degamma_lut) drm_property_blob_get(dm_plane_state->degamma_lut); + if (dm_plane_state->lut3d) + drm_property_blob_get(dm_plane_state->lut3d); dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult; @@ -1426,6 +1428,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, if (dm_plane_state->degamma_lut) drm_property_blob_put(dm_plane_state->degamma_lut); + if (dm_plane_state->lut3d) + drm_property_blob_put(dm_plane_state->lut3d); if (dm_plane_state->dc_state) dc_plane_state_release(dm_plane_state->dc_state); @@ -1456,6 +1460,14 @@ dm_atomic_plane_attach_color_mgmt_properties(struct
[PATCH v2 11/34] drm/amd/display: add plane shaper LUT and TF driver-specific properties
On AMD HW, 3D LUT always assumes a preceding shaper 1D LUT used for delinearizing and/or normalizing the color space before applying a 3D LUT. Add pre-defined transfer function to enable delinearizing content with or without shaper LUT, where AMD color module calculates the resulted shaper curve. We apply an inverse EOTF to go from linear values to encoded values. If we are already in a non-linear space and/or don't need to normalize values, we can bypass shaper LUT with a linear transfer function that is also the default TF value. v2: - squash commits for shaper LUT and shaper TF - define inverse EOTF as supported shaper TFs Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 16 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +++ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 29 + .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 32 +++ 4 files changed, 88 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 730a88236501..4fb164204ee6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -363,6 +363,22 @@ struct amdgpu_mode_info { * @plane_hdr_mult_property: */ struct drm_property *plane_hdr_mult_property; + /** +* @shaper_lut_property: Plane property to set pre-blending shaper LUT +* that converts color content before 3D LUT. +*/ + struct drm_property *plane_shaper_lut_property; + /** +* @shaper_lut_size_property: Plane property for the size of +* pre-blending shaper LUT as supported by the driver (read-only). +*/ + struct drm_property *plane_shaper_lut_size_property; + /** +* @plane_shaper_tf_property: Plane property to set a predefined +* transfer function for pre-blending shaper (before applying 3D LUT) +* with or without LUT. +*/ + struct drm_property *plane_shaper_tf_property; /** * @plane_lut3d_property: Plane property for gamma correction using a * 3D LUT (pre-blending). 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 deea90212e31..6b6c2980f0af 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -769,6 +769,17 @@ struct dm_plane_state { * S31.32 sign-magnitude. */ __u64 hdr_mult; + /** +* @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an +* array of drm_color_lut. +*/ + struct drm_property_blob *shaper_lut; + /** +* @shaper_tf: +* +* Predefined transfer function to delinearize color space. +*/ + enum amdgpu_transfer_function shaper_tf; /** * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of * drm_color_lut. diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 7e6d4df99a0c..fbcee717bf0a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -151,6 +151,14 @@ static const u32 amdgpu_eotf = BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) | BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF); +static const u32 amdgpu_inv_eotf = + BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_BT709_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF); + static struct drm_property * amdgpu_create_tf_property(struct drm_device *dev, const char *name, @@ -209,6 +217,27 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.plane_hdr_mult_property = prop; + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_SHAPER_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_shaper_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), +DRM_MODE_PROP_IMMUTABLE, +"AMD_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_shaper_lut_size_property = prop; + + prop = amdgpu_create_tf_property(adev_to_drm(adev), +"AMD_PLANE_SHAPER_TF", +amdgpu_inv_eotf); + if (!prop) + return
[PATCH v2 09/34] drm/amd/display: add plane HDR multiplier driver-specific property
From: Joshua Ashton Multiplier to 'gain' the plane. When PQ is decoded using the fixed func transfer function to the internal FP16 fb, 1.0 -> 80 nits (on AMD at least) When sRGB is decoded, 1.0 -> 1.0. Therefore, 1.0 multiplier = 80 nits for SDR content. So if you want, 203 nits for SDR content, pass in (203.0 / 80.0). Signed-off-by: Joshua Ashton Co-developed-by: Melissa Wen Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 4 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 14 ++ .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c| 6 ++ .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c| 13 + 4 files changed, 37 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 6ef958a14e16..66bae0eed80c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -359,6 +359,10 @@ struct amdgpu_mode_info { * to go from scanout/encoded values to linear values. */ struct drm_property *plane_degamma_tf_property; + /** +* @plane_hdr_mult_property: +*/ + struct drm_property *plane_hdr_mult_property; }; #define AMDGPU_MAX_BL_LEVEL 0xFF 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 f6251ed89684..44f17ac11a5f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -54,6 +54,9 @@ #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x1A #define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40 #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3 + +#define AMDGPU_HDR_MULT_DEFAULT (0x1LL) + /* #include "include/amdgpu_dal_power_if.h" #include "amdgpu_dm_irq.h" @@ -755,6 +758,17 @@ struct dm_plane_state { * linearize. */ enum amdgpu_transfer_function degamma_tf; + /** +* @hdr_mult: +* +* Multiplier to 'gain' the plane. When PQ is decoded using the fixed +* func transfer function to the internal FP16 fb, 1.0 -> 80 nits (on +* AMD at least). When sRGB is decoded, 1.0 -> 1.0, obviously. +* Therefore, 1.0 multiplier = 80 nits for SDR content. So if you +* want, 203 nits for SDR content, pass in (203.0 / 80.0). Format is +* S31.32 sign-magnitude. +*/ + __u64 hdr_mult; }; struct dm_crtc_state { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 7f13bcdaf016..b891aaf5f7c1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -203,6 +203,12 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.plane_degamma_tf_property = prop; + prop = drm_property_create_range(adev_to_drm(adev), +0, "AMD_PLANE_HDR_MULT", 0, U64_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_hdr_mult_property = prop; + return 0; } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 0a955abb1abf..ab7f0332c431 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1331,6 +1331,7 @@ static void dm_drm_plane_reset(struct drm_plane *plane) __drm_atomic_helper_plane_reset(plane, _state->base); amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; } static struct drm_plane_state * @@ -1354,6 +1355,7 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) drm_property_blob_get(dm_plane_state->degamma_lut); dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; + dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult; return _plane_state->base; } @@ -1450,6 +1452,10 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, dm->adev->mode_info.plane_degamma_tf_property, AMDGPU_TRANSFER_FUNCTION_DEFAULT); } + /* HDR MULT is always available */ + drm_object_attach_property(>base, + dm->adev->mode_info.plane_hdr_mult_property, + AMDGPU_HDR_MULT_DEFAULT); } static int @@ -1476,6 +1482,11 @@ dm_atomic_plane_set_property(struct drm_plane *plane, dm_plane_state->degamma_tf = val; dm_plane_state->base.color_mgmt_changed = 1; } + } else if (property ==
[PATCH v2 07/34] drm/amd/display: explicitly define EOTF and inverse EOTF
Instead of relying on color block names to get the transfer function intention regarding encoding pixel's luminance, define supported Electro-Optical Transfer Functions (EOTFs) and inverse EOTFs, that includes pure gamma or standardized transfer functions. Suggested-by: Harry Wentland Signed-off-by: Melissa Wen --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 19 +++-- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 69 +++ 2 files changed, 67 insertions(+), 21 deletions(-) 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 c749c9cb3d94..f6251ed89684 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -718,14 +718,21 @@ extern const struct amdgpu_ip_block_version dm_ip_block; enum amdgpu_transfer_function { AMDGPU_TRANSFER_FUNCTION_DEFAULT, - AMDGPU_TRANSFER_FUNCTION_SRGB, - AMDGPU_TRANSFER_FUNCTION_BT709, - AMDGPU_TRANSFER_FUNCTION_PQ, + AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF, + AMDGPU_TRANSFER_FUNCTION_BT709_EOTF, + AMDGPU_TRANSFER_FUNCTION_PQ_EOTF, AMDGPU_TRANSFER_FUNCTION_LINEAR, AMDGPU_TRANSFER_FUNCTION_UNITY, - AMDGPU_TRANSFER_FUNCTION_GAMMA22, - AMDGPU_TRANSFER_FUNCTION_GAMMA24, - AMDGPU_TRANSFER_FUNCTION_GAMMA26, + AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF, + AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_BT709_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF, +AMDGPU_TRANSFER_FUNCTION_COUNT }; struct dm_plane_state { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 56ce008b9095..cc2187c0879a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -85,18 +85,59 @@ void amdgpu_dm_init_color_mod(void) } #ifdef AMD_PRIVATE_COLOR -static const struct drm_prop_enum_list amdgpu_transfer_function_enum_list[] = { - { AMDGPU_TRANSFER_FUNCTION_DEFAULT, "Default" }, - { AMDGPU_TRANSFER_FUNCTION_SRGB, "sRGB" }, - { AMDGPU_TRANSFER_FUNCTION_BT709, "BT.709" }, - { AMDGPU_TRANSFER_FUNCTION_PQ, "PQ (Perceptual Quantizer)" }, - { AMDGPU_TRANSFER_FUNCTION_LINEAR, "Linear" }, - { AMDGPU_TRANSFER_FUNCTION_UNITY, "Unity" }, - { AMDGPU_TRANSFER_FUNCTION_GAMMA22, "Gamma 2.2" }, - { AMDGPU_TRANSFER_FUNCTION_GAMMA24, "Gamma 2.4" }, - { AMDGPU_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" }, +static const char * const +amdgpu_transfer_function_names[] = { + [AMDGPU_TRANSFER_FUNCTION_DEFAULT] = "Default", + [AMDGPU_TRANSFER_FUNCTION_LINEAR] = "Linear", + [AMDGPU_TRANSFER_FUNCTION_UNITY]= "Unity", + [AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF]= "sRGB EOTF", + [AMDGPU_TRANSFER_FUNCTION_BT709_EOTF] = "BT.709 EOTF", + [AMDGPU_TRANSFER_FUNCTION_PQ_EOTF] = "PQ EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF] = "Gamma 2.2 EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF] = "Gamma 2.4 EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF] = "Gamma 2.6 EOTF", + [AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF]= "sRGB inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_BT709_INV_EOTF] = "BT.709 inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF] = "PQ inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF] = "Gamma 2.2 inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF] = "Gamma 2.4 inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF] = "Gamma 2.6 inv_EOTF", }; +static const u32 amdgpu_eotf = + BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_BT709_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_PQ_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF); + +static struct drm_property * +amdgpu_create_tf_property(struct drm_device *dev, + const char *name, + u32 supported_tf) +{ + u32 transfer_functions = supported_tf | +BIT(AMDGPU_TRANSFER_FUNCTION_DEFAULT) | +BIT(AMDGPU_TRANSFER_FUNCTION_LINEAR) | +BIT(AMDGPU_TRANSFER_FUNCTION_UNITY); + struct drm_prop_enum_list enum_list[AMDGPU_TRANSFER_FUNCTION_COUNT]; + int i, len; + + len = 0; + for (i = 0; i < AMDGPU_TRANSFER_FUNCTION_COUNT;
[PATCH v2 08/34] drm/amd/display: document AMDGPU pre-defined transfer functions
Brief documentation about pre-defined transfer function usage on AMD display driver and standardized EOTFs and inverse EOTFs. Co-developed-by: Harry Wentland Signed-off-by: Harry Wentland Signed-off-by: Melissa Wen --- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 39 +++ 1 file changed, 39 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index cc2187c0879a..7f13bcdaf016 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -85,6 +85,45 @@ void amdgpu_dm_init_color_mod(void) } #ifdef AMD_PRIVATE_COLOR +/* Pre-defined Transfer Functions (TF) + * + * AMD driver supports pre-defined mathematical functions for transferring + * between encoded values and optical/linear space. Depending on HW color caps, + * ROMs and curves built by the AMD color module support these transforms. + * + * The driver-specific color implementation exposes properties for pre-blending + * degamma TF, shaper TF (before 3D LUT), and blend(dpp.ogam) TF and + * post-blending regamma (mpc.ogam) TF. However, only pre-blending degamma + * supports ROM curves. AMD color module uses pre-defined coefficients to build + * curves for the other blocks. What can be done by each color block is + * described by struct dpp_color_capsand struct mpc_color_caps. + * + * AMD driver-specific color API exposes the following pre-defined transfer + * functions: + * + * - Linear/Unity: linear/identity relationship between pixel value and + * luminance value; + * - Gamma 2.2, Gamma 2.4, Gamma 2.6: pure gamma functions; + * - sRGB: 2.4 gamma with small initial linear section as standardized by IEC + * 61966-2-1:1999; + * - BT.709 (BT.1886): 2.4 gamma with differences in the dark end of the scale. + * Used in HD-TV and standardized by ITU-R BT.1886; + * - PQ (Perceptual Quantizer): used for HDR display, allows luminance range + * capability of 0 to 10,000 nits; standardized by SMPTE ST 2084. + * + * In the driver-specific API, color block names attached to TF properties + * suggest the intention regarding non-linear encoding pixel's luminance + * values. As some newer encodings don't use gamma curve, we make encoding and + * decoding explicit by defining an enum list of transfer functions supported + * in terms of EOTF and inverse EOTF, where: + * + * - EOTF (electro-optical transfer function): is the transfer function to go + * from the encoded value to an optical (linear) value. De-gamma functions + * traditionally do this. + * - Inverse EOTF (simply the inverse of the EOTF): is usually intended to go + * from an optical/linear space (which might have been used for blending) + * back to the encoded values. Gamma functions traditionally do this. + */ static const char * const amdgpu_transfer_function_names[] = { [AMDGPU_TRANSFER_FUNCTION_DEFAULT] = "Default", -- 2.40.1
[PATCH v2 06/34] drm/amd/display: add plane degamma TF driver-specific property
From: Joshua Ashton Allow userspace to tell the kernel driver the input space and, therefore, uses correct predefined transfer function (TF) to delinearize content with or without LUT. v2: - rename TF enum prefix from DRM_ to AMDGPU_ (Harry) - remove HLG TF Signed-off-by: Joshua Ashton Co-developed-by: Melissa Wen Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 5 + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 19 + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 21 +++ .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 19 +++-- 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index ec4621deac8c..6ef958a14e16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -354,6 +354,11 @@ struct amdgpu_mode_info { * size of degamma LUT as supported by the driver (read-only). */ struct drm_property *plane_degamma_lut_size_property; + /** +* @plane_degamma_tf_property: Plane pre-defined transfer function to +* to go from scanout/encoded values to linear values. +*/ + struct drm_property *plane_degamma_tf_property; }; #define AMDGPU_MAX_BL_LEVEL 0xFF 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 f0343bbf0fe1..c749c9cb3d94 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -716,6 +716,18 @@ static inline void amdgpu_dm_set_mst_status(uint8_t *status, extern const struct amdgpu_ip_block_version dm_ip_block; +enum amdgpu_transfer_function { + AMDGPU_TRANSFER_FUNCTION_DEFAULT, + AMDGPU_TRANSFER_FUNCTION_SRGB, + AMDGPU_TRANSFER_FUNCTION_BT709, + AMDGPU_TRANSFER_FUNCTION_PQ, + AMDGPU_TRANSFER_FUNCTION_LINEAR, + AMDGPU_TRANSFER_FUNCTION_UNITY, + AMDGPU_TRANSFER_FUNCTION_GAMMA22, + AMDGPU_TRANSFER_FUNCTION_GAMMA24, + AMDGPU_TRANSFER_FUNCTION_GAMMA26, +}; + struct dm_plane_state { struct drm_plane_state base; struct dc_plane_state *dc_state; @@ -729,6 +741,13 @@ struct dm_plane_state { * The blob (if not NULL) is an array of drm_color_lut. */ struct drm_property_blob *degamma_lut; + /** +* @degamma_tf: +* +* Predefined transfer function to tell DC driver the input space to +* linearize. +*/ + enum amdgpu_transfer_function degamma_tf; }; struct dm_crtc_state { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index cf175b86ba80..56ce008b9095 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -85,6 +85,18 @@ void amdgpu_dm_init_color_mod(void) } #ifdef AMD_PRIVATE_COLOR +static const struct drm_prop_enum_list amdgpu_transfer_function_enum_list[] = { + { AMDGPU_TRANSFER_FUNCTION_DEFAULT, "Default" }, + { AMDGPU_TRANSFER_FUNCTION_SRGB, "sRGB" }, + { AMDGPU_TRANSFER_FUNCTION_BT709, "BT.709" }, + { AMDGPU_TRANSFER_FUNCTION_PQ, "PQ (Perceptual Quantizer)" }, + { AMDGPU_TRANSFER_FUNCTION_LINEAR, "Linear" }, + { AMDGPU_TRANSFER_FUNCTION_UNITY, "Unity" }, + { AMDGPU_TRANSFER_FUNCTION_GAMMA22, "Gamma 2.2" }, + { AMDGPU_TRANSFER_FUNCTION_GAMMA24, "Gamma 2.4" }, + { AMDGPU_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" }, +}; + int amdgpu_dm_create_color_properties(struct amdgpu_device *adev) { @@ -104,6 +116,15 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) return -ENOMEM; adev->mode_info.plane_degamma_lut_size_property = prop; + prop = drm_property_create_enum(adev_to_drm(adev), + DRM_MODE_PROP_ENUM, + "AMD_PLANE_DEGAMMA_TF", + amdgpu_transfer_function_enum_list, + ARRAY_SIZE(amdgpu_transfer_function_enum_list)); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_degamma_tf_property = prop; + return 0; } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 488012d1558d..0a955abb1abf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1326,8 +1326,11 @@ static void dm_drm_plane_reset(struct drm_plane *plane) amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL); WARN_ON(amdgpu_state == NULL); - if (amdgpu_state) - __drm_atomic_helper_plane_reset(plane, _state->base); + if
[PATCH v2 04/34] drm/drm_plane: track color mgmt changes per plane
We will add color mgmt properties to DRM planes in the next patches and we want to track when one of this properties change to define atomic commit behaviors. Using a similar approach from CRTC color props, we set a color_mgmt_changed boolean whenever a plane color prop changes. Reviewed-by: Harry Wentland Signed-off-by: Melissa Wen --- drivers/gpu/drm/drm_atomic.c | 1 + drivers/gpu/drm/drm_atomic_state_helper.c | 1 + include/drm/drm_plane.h | 7 +++ 3 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 11f3a130f6f4..30aa3248bb0d 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -724,6 +724,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_get_color_encoding_name(state->color_encoding)); drm_printf(p, "\tcolor-range=%s\n", drm_get_color_range_name(state->color_range)); + drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); if (plane->funcs->atomic_print_state) plane->funcs->atomic_print_state(p, state); diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 784e63d70a42..25bb0859fda7 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -338,6 +338,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, state->fence = NULL; state->commit = NULL; state->fb_damage_clips = NULL; + state->color_mgmt_changed = false; } EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 51291983ea44..52c3287da0da 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -237,6 +237,13 @@ struct drm_plane_state { /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; + + /** +* @color_mgmt_changed: Color management properties have changed. Used +* by the atomic helpers and drivers to steer the atomic commit control +* flow. +*/ + bool color_mgmt_changed : 1; }; static inline struct drm_rect -- 2.40.1
[PATCH v2 05/34] drm/amd/display: add driver-specific property for plane degamma LUT
Hook up driver-specific atomic operations for managing AMD color properties. Create AMD driver-specific color management properties and attach them according to HW capabilities defined by `struct dc_color_caps`. First add plane degamma LUT properties that means user-blob and its size. We will add more plane color properties in the next patches. In addition, we define AMD_PRIVATE_COLOR to guard these driver-specific plane properties. Plane degamma can be used to linearize input space for arithmetical operations that are more accurate when applied in linear color. v2: - update degamma LUT prop description - move private color operations from amdgpu_display to amdgpu_dm_color Co-developed-by: Joshua Ashton Signed-off-by: Joshua Ashton Signed-off-by: Melissa Wen --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 11 +++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +++ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 24 ++ .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 81 +++ 5 files changed, 132 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 32fe05c810c6..ec4621deac8c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -343,6 +343,17 @@ struct amdgpu_mode_info { int disp_priority; const struct amdgpu_display_funcs *funcs; const enum drm_plane_type *plane_type; + + /* Driver-private color mgmt props */ + + /* @plane_degamma_lut_property: Plane property to set a degamma LUT to +* convert input space before blending. +*/ + struct drm_property *plane_degamma_lut_property; + /* @plane_degamma_lut_size_property: Plane property to define the max +* size of degamma LUT as supported by the driver (read-only). +*/ + struct drm_property *plane_degamma_lut_size_property; }; #define AMDGPU_MAX_BL_LEVEL 0xFF 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 dffa584410a5..77b4d671a9e0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3949,6 +3949,11 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) return r; } +#ifdef AMD_PRIVATE_COLOR + if (amdgpu_dm_create_color_properties(adev)) + return -ENOMEM; +#endif + r = amdgpu_dm_audio_init(adev); if (r) { dc_release_state(state->context); 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 a2d34be82613..f0343bbf0fe1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -719,6 +719,16 @@ extern const struct amdgpu_ip_block_version dm_ip_block; struct dm_plane_state { struct drm_plane_state base; struct dc_plane_state *dc_state; + + /* Plane color mgmt */ + /** +* @degamma_lut: +* +* 1D LUT for mapping framebuffer/plane pixel data before sampling or +* blending operations. It's usually applied to linearize input space. +* The blob (if not NULL) is an array of drm_color_lut. +*/ + struct drm_property_blob *degamma_lut; }; struct dm_crtc_state { @@ -809,6 +819,7 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 void amdgpu_dm_init_color_mod(void); +int amdgpu_dm_create_color_properties(struct amdgpu_device *adev); int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state); int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc); int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index a4cb23d059bd..cf175b86ba80 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -84,6 +84,30 @@ void amdgpu_dm_init_color_mod(void) setup_x_points_distribution(); } +#ifdef AMD_PRIVATE_COLOR +int +amdgpu_dm_create_color_properties(struct amdgpu_device *adev) +{ + struct drm_property *prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_DEGAMMA_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_degamma_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), +DRM_MODE_PROP_IMMUTABLE, +"AMD_PLANE_DEGAMMA_LUT_SIZE", 0, UINT_MAX); + if (!prop) +
[PATCH v2 03/34] drm/drm_property: make replace_property_blob_from_id a DRM helper
Place it in drm_property where drm_property_replace_blob and drm_property_lookup_blob live. Then we can use the DRM helper for driver-specific KMS properties too. Reviewed-by: Harry Wentland Reviewed-by: Liviu Dudau Signed-off-by: Melissa Wen --- drivers/gpu/drm/arm/malidp_crtc.c | 2 +- drivers/gpu/drm/drm_atomic_uapi.c | 43 --- drivers/gpu/drm/drm_property.c| 49 +++ include/drm/drm_property.h| 6 4 files changed, 61 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index dc01c43f6193..d72c22dcf685 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -221,7 +221,7 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, /* * The size of the ctm is checked in -* drm_atomic_replace_property_blob_from_id. +* drm_property_replace_blob_from_id. */ ctm = (struct drm_color_ctm *)state->ctm->data; for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) { diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index d867e7f9f2cd..a6a9ee5086dd 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -362,39 +362,6 @@ static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, return fence_ptr; } -static int -drm_atomic_replace_property_blob_from_id(struct drm_device *dev, -struct drm_property_blob **blob, -uint64_t blob_id, -ssize_t expected_size, -ssize_t expected_elem_size, -bool *replaced) -{ - struct drm_property_blob *new_blob = NULL; - - if (blob_id != 0) { - new_blob = drm_property_lookup_blob(dev, blob_id); - if (new_blob == NULL) - return -EINVAL; - - if (expected_size > 0 && - new_blob->length != expected_size) { - drm_property_blob_put(new_blob); - return -EINVAL; - } - if (expected_elem_size > 0 && - new_blob->length % expected_elem_size != 0) { - drm_property_blob_put(new_blob); - return -EINVAL; - } - } - - *replaced |= drm_property_replace_blob(blob, new_blob); - drm_property_blob_put(new_blob); - - return 0; -} - static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) @@ -415,7 +382,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, } else if (property == config->prop_vrr_enabled) { state->vrr_enabled = val; } else if (property == config->degamma_lut_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, >degamma_lut, val, -1, sizeof(struct drm_color_lut), @@ -423,7 +390,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, state->color_mgmt_changed |= replaced; return ret; } else if (property == config->ctm_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, >ctm, val, sizeof(struct drm_color_ctm), -1, @@ -431,7 +398,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, state->color_mgmt_changed |= replaced; return ret; } else if (property == config->gamma_lut_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, >gamma_lut, val, -1, sizeof(struct drm_color_lut), @@ -563,7 +530,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, } else if (property == plane->color_range_property) { state->color_range = val; } else if (property == config->prop_fb_damage_clips) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, >fb_damage_clips, val, -1, @@ -729,7 +696,7 @@ static int
[PATCH v2 02/34] drm/drm_mode_object: increase max objects to accommodate new color props
DRM_OBJECT_MAX_PROPERTY limits the number of properties to be attached and we are increasing that value all time we add a new property (generic or driver-specific). In this series, we are adding 13 new KMS driver-specific properties for AMD color manage: - CRTC Gamma enumerated Transfer Function - Plane: Degamma LUT+size+TF, HDR multiplier, shaper LUT+size+TF, 3D LUT+size, blend LUT+size+TF (12) Therefore, just increase DRM_OBJECT_MAX_PROPERTY to a number (64) that accomodates these new properties and gives some room for others, avoiding change this number everytime we add a new KMS property. Reviewed-by: Harry Wentland Reviewed-by: Simon Ser Signed-off-by: Melissa Wen --- include/drm/drm_mode_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h index 912f1e415685..08d7a7f0188f 100644 --- a/include/drm/drm_mode_object.h +++ b/include/drm/drm_mode_object.h @@ -60,7 +60,7 @@ struct drm_mode_object { void (*free_cb)(struct kref *kref); }; -#define DRM_OBJECT_MAX_PROPERTY 24 +#define DRM_OBJECT_MAX_PROPERTY 64 /** * struct drm_object_properties - property tracking for _mode_object */ -- 2.40.1
[PATCH v2 00/34] drm/amd/display: add AMD driver-specific properties for color mgmt
Hi all, Here is the next version of our work to enable AMD driver-specific color management properties [1][2]. This series is a collection of contributions from Joshua, Harry, and me to enhance the AMD KMS color pipeline for Steam Deck/SteamOS by exposing additional pre-blending and post-blending color capabilities from those available in the current DRM KMS API[3]. The userspace case here is Gamescope which is the compositor for SteamOS. Gamescope is already using these features to implement its color management pipeline [4]. In this version, I try to address all concerns shared in the previous one, i.e.: - Replace DRM_ by AMDGPU_ prefix for transfer function enumeration; - Explicitly define EOTFs and inverse EOTFs and set props accordingly; - Document pre-defined transfer functions; - Remove misleading comments; - Remove post-blending/MPC shaper and 3D LUT support; - Move driver-specific property operations from amdgpu_display.c to amdgpu_dm_color.c; - Reset planes if any color props change; - Nits/small fixes; Bearing in mind the complexity of color concepts, I believe there is a high chance of some misunderstanding from my side when defining EOTFs and documenting pre-defined TFs. So, reviews are very important and welcome (thanks in advance). FWIW, I added Harry as a co-developer of this TF documentation since I based on his description of EOTF/inv_EOTF and previous documentation work [5]. Let me know if there is a better way for credits. Two DC patches were already applied and, therefore, removed from the series. I added r-b according to previous feedback. We also add plane CTM to driver-specific properties. As a result, this is the updated list of all driver-specific color properties exposed by this series: - plane degamma LUT and pre-defined TF; - plane HDR multiplier; - plane CTM 3x4; - plane shaper LUT and pre-defined TF; - plane 3D LUT; - plane blend LUT and pre-defined TF; - CRTC gamma pre-defined TF; Remember you can find the AMD HW color capabilities documented here: https://dri.freedesktop.org/docs/drm/gpu/amdgpu/display/display-manager.html#color-management-properties Worth mentioning that the pre-blending degamma block can use ROM curves for some pre-defined TFs, but the other blocks use the AMD color module to calculate this curve considering pre-defined coefficients. We need changes on DC gamut remap matrix to support the plane and CRTC CTM on drivers that support both. I've sent a previous patch to apply these changes to all DCN3+ families [6]. Here I use the same changes but limited to DCN301. Just let me know if you prefer the previous/expanded version. Finally, this is the Linux/AMD color management API before and after blending with the driver-specific properties: +--+ | PLANE | | | | ++ | | | AMD Degamma| | | || | | | EOTF | 1D LUT | | | ++---+ | | | | | +v---+ | | |AMD HDR | | | |Multiply| | | ++---+ | | | | | +v---+ | | | AMD CTM (3x4) | | | ++---+ | | | | | +v---+ | | | AMD Shaper | | | || | | | inv_EOTF | | | | | Custom 1D LUT | | | ++---+ | | | | | +v---+ | | | AMD 3D LUT | | | | 17^3/12-bit | | | ++---+ | | | | | +v---+ | | | AMD Blend | | | || | | | EOTF | 1D LUT | | | ++---+ | | | | ++--v-++ || Blending || ++--+-++ |CRTC | | | | | | +---v---+ | | | DRM Degamma | | | | | | | | Custom 1D LUT | | | +---+---+ | | | | | +---v---+ | | | DRM CTM (3x3) | | | +---+---+ | | | | | +---v---+ | | | DRM Gamma | | | | | | | | Custom 1D LUT | | | +---+ | | | *AMD Gamma| | | | inv_EOTF| | | +---+ | | | +--+ Let me know your thoughts. Best Regards, Melissa Wen [1] https://lore.kernel.org/dri-devel/20230423141051.702990-1-m...@igalia.com [2] https://lore.kernel.org/dri-devel/20230523221520.3115570-1-m...@igalia.com [3] https://github.com/ValveSoftware/gamescope/blob/master/src/docs/Steam%20Deck%20Display%20Pipeline.png [4] https://github.com/ValveSoftware/gamescope [5] https://lore.kernel.org/dri-devel/20210730204134.21769-1-harry.wentl...@amd.com [6] https://lore.kernel.org/dri-devel/20230721132431.692158-1-m...@igalia.com Harry Wentland (1): drm/amd/display: fix segment distribution for linear LUTs Joshua Ashton (14): drm/amd/display: add plane degamma TF driver-specific property drm/amd/display: add
[PATCH v2 01/34] drm/amd/display: fix segment distribution for linear LUTs
From: Harry Wentland The region and segment calculation was incapable of dealing with regions of more than 16 segments. We first fix this. Now that we can support regions up to 256 elements we can define a better segment distribution for near-linear LUTs for our maximum of 256 HW-supported points. With these changes an "identity" LUT looks visually indistinguishable from bypass and allows us to use our 3DLUT. Signed-off-by: Harry Wentland Signed-off-by: Melissa Wen --- .../amd/display/dc/dcn10/dcn10_cm_common.c| 93 +++ 1 file changed, 75 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index 3538973bd0c6..04b2e04b68f3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -349,20 +349,37 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx, * segment is from 2^-10 to 2^1 * There are less than 256 points, for optimization */ - seg_distr[0] = 3; - seg_distr[1] = 4; - seg_distr[2] = 4; - seg_distr[3] = 4; - seg_distr[4] = 4; - seg_distr[5] = 4; - seg_distr[6] = 4; - seg_distr[7] = 4; - seg_distr[8] = 4; - seg_distr[9] = 4; - seg_distr[10] = 1; + if (output_tf->tf == TRANSFER_FUNCTION_LINEAR) { + seg_distr[0] = 0; /* 2 */ + seg_distr[1] = 1; /* 4 */ + seg_distr[2] = 2; /* 4 */ + seg_distr[3] = 3; /* 8 */ + seg_distr[4] = 4; /* 16 */ + seg_distr[5] = 5; /* 32 */ + seg_distr[6] = 6; /* 64 */ + seg_distr[7] = 7; /* 128 */ + + region_start = -8; + region_end = 1; + } else { + seg_distr[0] = 3; /* 8 */ + seg_distr[1] = 4; /* 16 */ + seg_distr[2] = 4; + seg_distr[3] = 4; + seg_distr[4] = 4; + seg_distr[5] = 4; + seg_distr[6] = 4; + seg_distr[7] = 4; + seg_distr[8] = 4; + seg_distr[9] = 4; + seg_distr[10] = 1; /* 2 */ + /* total = 8*16 + 8 + 64 + 2 = */ + + region_start = -10; + region_end = 1; + } + - region_start = -10; - region_end = 1; } for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) @@ -375,16 +392,56 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx, j = 0; for (k = 0; k < (region_end - region_start); k++) { - increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); + /* +* We're using an ugly-ish hack here. Our HW allows for +* 256 segments per region but SW_SEGMENTS is 16. +* SW_SEGMENTS has some undocumented relationship to +* the number of points in the tf_pts struct, which +* is 512, unlike what's suggested TRANSFER_FUNC_POINTS. +* +* In order to work past this dilemma we'll scale our +* increment by (1 << 4) and then do the inverse (1 >> 4) +* when accessing the elements in tf_pts. +* +* TODO: find a better way using SW_SEGMENTS and +* TRANSFER_FUNC_POINTS definitions +*/ + increment = (NUMBER_SW_SEGMENTS << 4) / (1 << seg_distr[k]); start_index = (region_start + k + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; - for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; + for (i = (start_index << 4); i < (start_index << 4) + (NUMBER_SW_SEGMENTS << 4); i += increment) { + struct fixed31_32 in_plus_one, in; + struct fixed31_32 value, red_value, green_value, blue_value; + uint32_t t = i & 0xf; + if (j == hw_points - 1) break; - rgb_resulted[j].red = output_tf->tf_pts.red[i]; - rgb_resulted[j].green = output_tf->tf_pts.green[i]; - rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; + + in_plus_one = output_tf->tf_pts.red[(i >> 4) + 1]; + in = output_tf->tf_pts.red[i >> 4]; + value = dc_fixpt_sub(in_plus_one, in); +
Re: [PATCH V8 1/9] drivers core: Add support for Wifi band RF mitigations
On 8/10/23 00:37, Evan Quan wrote: > diff --git a/Documentation/admin-guide/kernel-parameters.txt > b/Documentation/admin-guide/kernel-parameters.txt > index a1457995fd41..21f73a0bbd0b 100644 > --- a/Documentation/admin-guide/kernel-parameters.txt > +++ b/Documentation/admin-guide/kernel-parameters.txt > @@ -7152,3 +7152,12 @@ > xmon commands. > off xmon is disabled. > > + wbrf= [KNL] > + Format: { on | auto | off } > + Controls if WBRF features should be enabled or disabled > + forcely. Default is auto. "forcely" is not a word. "forcedly" is a word, but it's not used very much AFAIK. I would probably write "Controls if WBRF features should be forced on or off." > + on Force enable the WBRF features. > + autoUp to the system to do proper checks to > + determine the WBRF features should be enabled > + or not. > + off Force disable the WBRF features. -- ~Randy
Re: [PATCH] drm/amdgpu: don't allow userspace to create a doorbell BO
Ping? On Wed, Aug 9, 2023 at 3:10 PM Alex Deucher wrote: > > We need the domains in amdgpu_drm.h for the kernel driver to manage > the pool, but we don't want userspace using it until the code > is ready. So reject for now. > > Signed-off-by: Alex Deucher > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 4 > 1 file changed, 4 insertions(+) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > index 693b1fd1191a..ca4d2d430e28 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > @@ -289,6 +289,10 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void > *data, > uint32_t handle, initial_domain; > int r; > > + /* reject DOORBELLs until userspace code to use it is available */ > + if (args->in.domains & AMDGPU_GEM_DOMAIN_DOORBELL) > + return -EINVAL; > + > /* reject invalid gem flags */ > if (flags & ~(AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | > AMDGPU_GEM_CREATE_NO_CPU_ACCESS | > -- > 2.41.0 >
Re: [PATCH] drm/amdgpu: Keep reset handlers shared
Am 10.08.23 um 13:44 schrieb Lijo Lazar: Instead of maintaining a list per device, keep the reset handlers common per ASIC family. A pointer to the list of handlers is maintained in reset control. Why should this be beneficial? Christian. Signed-off-by: Lijo Lazar --- drivers/gpu/drm/amd/amdgpu/aldebaran.c | 19 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 8 drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h | 16 drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c | 20 +++- drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c | 19 +++ 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 2b97b8a96fb4..82e1c83a7ccc 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -48,20 +48,19 @@ aldebaran_get_reset_handler(struct amdgpu_reset_control *reset_ctl, { struct amdgpu_reset_handler *handler; struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + int i; if (reset_context->method != AMD_RESET_METHOD_NONE) { dev_dbg(adev->dev, "Getting reset handler for method %d\n", reset_context->method); - list_for_each_entry(handler, _ctl->reset_handlers, -handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == reset_context->method) return handler; } } if (aldebaran_is_mode2_default(reset_ctl)) { - list_for_each_entry(handler, _ctl->reset_handlers, -handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == AMD_RESET_METHOD_MODE2) { reset_context->method = AMD_RESET_METHOD_MODE2; return handler; @@ -124,9 +123,9 @@ static void aldebaran_async_reset(struct work_struct *work) struct amdgpu_reset_control *reset_ctl = container_of(work, struct amdgpu_reset_control, reset_work); struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + int i; - list_for_each_entry(handler, _ctl->reset_handlers, -handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == reset_ctl->active_reset) { dev_dbg(adev->dev, "Resetting device\n"); handler->do_reset(adev); @@ -395,6 +394,11 @@ static struct amdgpu_reset_handler aldebaran_mode2_handler = { .do_reset = aldebaran_mode2_reset, }; +static struct amdgpu_reset_handler + *aldebaran_rst_handlers[AMDGPU_RESET_MAX_HANDLERS] = { + _mode2_handler, + }; + int aldebaran_reset_init(struct amdgpu_device *adev) { struct amdgpu_reset_control *reset_ctl; @@ -408,10 +412,9 @@ int aldebaran_reset_init(struct amdgpu_device *adev) reset_ctl->active_reset = AMD_RESET_METHOD_NONE; reset_ctl->get_reset_handler = aldebaran_get_reset_handler; - INIT_LIST_HEAD(_ctl->reset_handlers); INIT_WORK(_ctl->reset_work, reset_ctl->async_reset); /* Only mode2 is handled through reset control now */ - amdgpu_reset_add_handler(reset_ctl, _mode2_handler); + reset_ctl->reset_handlers = _rst_handlers; adev->reset_cntl = reset_ctl; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 5fed06ffcc6b..02d874799c16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -26,14 +26,6 @@ #include "sienna_cichlid.h" #include "smu_v13_0_10.h" -int amdgpu_reset_add_handler(struct amdgpu_reset_control *reset_ctl, -struct amdgpu_reset_handler *handler) -{ - /* TODO: Check if handler exists? */ - list_add_tail(>handler_list, _ctl->reset_handlers); - return 0; -} - int amdgpu_reset_init(struct amdgpu_device *adev) { int ret = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index f4a501ff87d9..471d789b33a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -26,6 +26,8 @@ #include "amdgpu.h" +#define AMDGPU_RESET_MAX_HANDLERS 5 + enum AMDGPU_RESET_FLAGS { AMDGPU_NEED_FULL_RESET = 0, @@ -44,7 +46,6 @@ struct amdgpu_reset_context { struct amdgpu_reset_handler { enum amd_reset_method reset_method; - struct list_head handler_list; int (*prepare_env)(struct amdgpu_reset_control *reset_ctl, struct amdgpu_reset_context *context);
Re: [PATCH V8 3/9] cfg80211: expose nl80211_chan_width_to_mhz for wide sharing
On 8/10/2023 12:37 AM, Evan Quan wrote: The newly added WBRF feature needs this interface for channel width calculation. Signed-off-by: Evan Quan --- include/net/cfg80211.h | 8 net/wireless/chan.c| 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7c7d03aa9d06..f50508e295db 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -920,6 +920,14 @@ const struct cfg80211_chan_def * cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1, const struct cfg80211_chan_def *chandef2); +/** + * nl80211_chan_width_to_mhz - get the channel width in Mhz + * @chan_width: the channel width from nl80211_chan_width + * Return: channel width in Mhz if the chan_width from nl80211_chan_width + * is valid. -1 otherwise. SI nit: s/Mhz/MHz/ in both places + */ +int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width); + /** * cfg80211_chandef_valid - check if a channel definition is valid * @chandef: the channel definition to check diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 0b7e81db383d..227db04eac42 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -141,7 +141,7 @@ static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef) return true; } -static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width) +int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width) { int mhz; @@ -190,6 +190,7 @@ static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width) } return mhz; } +EXPORT_SYMBOL(nl80211_chan_width_to_mhz); static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) {
RE: [PATCH] drm/amd/pm: Fix temperature unit of SMU v13.0.6
[AMD Official Use Only - General] Reviewed-by: Yang Wang Best Regards, Kevin -Original Message- From: amd-gfx On Behalf Of Lijo Lazar Sent: Thursday, August 10, 2023 6:46 PM To: amd-gfx@lists.freedesktop.org Cc: Deucher, Alexander ; Ma, Le ; Kamal, Asad ; Zhang, Hawking Subject: [PATCH] drm/amd/pm: Fix temperature unit of SMU v13.0.6 Temperature needs to be reported in millidegree Celsius. Signed-off-by: Lijo Lazar --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 244e6d31560d..da8ba1aa57eb 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 @@ -708,16 +708,19 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_TO_UINT(metrics->SocketPower) << 8; break; case METRICS_TEMPERATURE_HOTSPOT: - *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature); + *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature) * +SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; case METRICS_TEMPERATURE_MEM: - *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature); + *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature) * +SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; /* This is the max of all VRs and not just SOC VR. * No need to define another data type for the same. */ case METRICS_TEMPERATURE_VRSOC: - *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature); + *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature) * +SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; default: *value = UINT_MAX; -- 2.25.1
Re: next-20230726 and later - crash in radeon module during init
On Thu, 10 Aug 2023 05:35:02 -0400, "Valdis KlÄtnieks" said: > I am seeing the following consistent crash at boot: > Some quick digging indicates the most likely culprit is: > > commit cbd0606e6a776bf2ba10d4a6957bb7628c0da947 > Author: Srinivasan Shanmugam > Date: Thu Jul 20 15:39:24 2023 +0530 > > drm/radeon: Prefer dev_* variant over printk Nevermind - I see it was already reverted... pgpEGB0i_V8uk.pgp Description: PGP signature
Re: [PATCH] video/hdmi: convert *_infoframe_init() functions to void
Hello, On 8/10/23 01:13, Maxime Ripard wrote: > Hi, > > On Tue, Aug 08, 2023 at 11:02:45AM -0700, Nikita Zhandarovich wrote: >> Four hdmi_*_infoframe_init() functions that initialize different >> types of hdmi infoframes only return the default 0 value, contrary to >> their descriptions. Yet these functions are still unnecessarily checked >> against possible errors in case of failure. >> >> Remove redundant error checks in calls to following functions: >> - hdmi_spd_infoframe_init >> - hdmi_audio_infoframe_init >> - hdmi_vendor_infoframe_init >> - hdmi_drm_infoframe_init >> Also, convert these functions to 'void' and fix their descriptions. > > I'm not sure what value it actually adds. None of them return any > errors, but very well might if we started to be a bit serious about it. > > Since the error handling is already there, then I'd rather leave it > there. There is definitely no particular urgency to this change. Since these functions don't perform anything complex and aren't updated regularly, my main goal was to remove unnecessary (at the moment) checks and fix up their somewhat misleading descriptions. Cleaning up, in other words. But I understand your point of view. If you don't think this patch is warranted at this point, I totally understand. > >> Fixes: 2c676f378edb ("[media] hdmi: added unpack and logging functions for >> InfoFrames") > > I'm confused about that part. What does it fix exactly? > > Maxime I added the 'Fixes:' tag mostly as a requirement for patch's description. Once again, it doesn't "fix" anything broken as much as it cleans up stuff. Best regards, Nikita
[PATCH -next] drm/amdgpu: Remove duplicated includes
Remove duplicated includes in amdgpu_amdkfd_gpuvm.c and amdgpu_ttm.c. Resolves checkincludes message. Signed-off-by: GUO Zihua --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index a136fba9f29b..7d6daf8d2bfa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -39,7 +39,6 @@ #include "amdgpu_xgmi.h" #include "kfd_priv.h" #include "kfd_smi_events.h" -#include /* Userptr restore delay, just long enough to allow consecutive VM * changes to accumulate diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dea848bb55c1..f5aa1362c818 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -49,7 +49,6 @@ #include #include -#include #include "amdgpu.h" #include "amdgpu_object.h" -- 2.17.1
next-20230726 and later - crash in radeon module during init
I am seeing the following consistent crash at boot: [ 61.211213][ T819] [drm] radeon kernel modesetting enabled. [ 61.584870][ T819] vga_switcheroo: detected switching method \_SB_.PCI0.GFX0.ATPX handle [ 61.667507][ T819] ATPX version 1, functions 0x0033 [ 61.748228][ T819] general protection fault, probably for non-canonical address 0x54080068930549a0: [#1] PREEMPT SMP [ 61.829840][ T819] CPU: 3 PID: 819 Comm: (udev-worker) Tainted: G I T 6.5.0-rc4-next-20230804 #58 5cce04b101a5bb4a6c0368bfff037f6f096b3d3e [ 61.911411][ T819] Hardware name: Dell Inc. Inspiron 5559/052K07, BIOS 1.9.0 09/07/2020 [ 61.993285][ T819] RIP: 0010:strnlen+0x21/0x40 [ 62.074885][ T819] Code: 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 55 48 89 e5 48 8d 14 37 31 c0 48 85 f6 74 16 48 89 f8 eb 09 48 83 c0 01 48 39 c2 74 0e <80> 38 00 75 f2 48 29 f8 5d c3 cc cc cc cc 48 89 d0 5d 48 29 f8 c3 [ 62.156529][ T819] RSP: 0018:a310419979b8 EFLAGS: 00010202 [ 62.318407][ T819] RAX: 54080068930549a0 RBX: a31041997a20 RCX: [ 62.400015][ T819] RDX: 54080068930549b0 RSI: 0010 RDI: 54080068930549a0 [ 62.481624][ T819] RBP: a310419979b8 R08: 937b85579990 R09: a31041997ad8 [ 62.563644][ T819] R10: 937b86ddae00 R11: R12: 54080068930549a0 [ 62.645194][ T819] R13: 937b814291b8 R14: 0001 R15: a31041997b81 [ 62.726753][ T819] FS: 7efd50479600() GS:937ef2e0() knlGS: [ 62.808312][ T819] CS: 0010 DS: ES: CR0: 80050033 [ 62.889830][ T819] CR2: 7f125d30ee70 CR3: 000105644002 CR4: 003706e0 [ 62.971390][ T819] Call Trace: [ 63.052954][ T819] [ 63.134501][ T819] ? show_regs+0x64/0x70 [ 63.216058][ T819] ? die_addr+0x36/0x90 [ 63.297594][ T819] ? exc_general_protection+0x1c1/0x440 [ 63.379112][ T819] ? asm_exc_general_protection+0x2b/0x30 [ 63.460650][ T819] ? strnlen+0x21/0x40 [ 63.542209][ T819] set_dev_info+0x40/0x170 [ 63.623762][ T819] dev_printk_emit+0xa8/0xe0 [ 63.705308][ T819] __dev_printk+0x34/0x80 [ 63.786806][ T819] _dev_info+0x7a/0xa0 [ 63.868304][ T819] radeon_atpx_validate.constprop.0.isra.0+0xbc/0x100 [radeon f030e9a708043a486415a94978106b28cd7cb9a2] [ 63.949952][ T819] radeon_atpx_detect+0x17b/0x190 [radeon f030e9a708043a486415a94978106b28cd7cb9a2] [ 64.031547][ T819] ? __pfx_radeon_module_init+0x10/0x10 [radeon f030e9a708043a486415a94978106b28cd7cb9a2] [ 64.113102][ T819] radeon_register_atpx_handler+0xd/0x30 [radeon f030e9a708043a486415a94978106b28cd7cb9a2] [ 64.194721][ T819] radeon_module_init+0x84/0xff0 [radeon f030e9a708043a486415a94978106b28cd7cb9a2] [ 64.276365][ T819] do_one_initcall+0x86/0x380 [ 64.357865][ T819] do_init_module+0x63/0x220 [ 64.439342][ T819] load_module+0x99d/0xa90 Some quick digging indicates the most likely culprit is: commit cbd0606e6a776bf2ba10d4a6957bb7628c0da947 Author: Srinivasan Shanmugam Date: Thu Jul 20 15:39:24 2023 +0530 drm/radeon: Prefer dev_* variant over printk Changed from pr_err/info to dev_* variants so that we get better debug info when there are multiple GPUs in the system. Looks like this is the failure point because 'dev' is trashed: + dev_info(dev, "ATPX Hybrid Graphics\n"); But I admit I don't know the APCI stuff well enough to see what, if anything, is wrong with this: + struct acpi_device *adev = container_of(atpx->handle, struct acpi_device, handle); + struct device *dev = >dev; Any ideas? pgpggeCbCBvoT.pgp Description: PGP signature
[PATCH] drm/amdgpu: Keep reset handlers shared
Instead of maintaining a list per device, keep the reset handlers common per ASIC family. A pointer to the list of handlers is maintained in reset control. Signed-off-by: Lijo Lazar --- drivers/gpu/drm/amd/amdgpu/aldebaran.c | 19 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 8 drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h | 16 drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c | 20 +++- drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c | 19 +++ 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 2b97b8a96fb4..82e1c83a7ccc 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -48,20 +48,19 @@ aldebaran_get_reset_handler(struct amdgpu_reset_control *reset_ctl, { struct amdgpu_reset_handler *handler; struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + int i; if (reset_context->method != AMD_RESET_METHOD_NONE) { dev_dbg(adev->dev, "Getting reset handler for method %d\n", reset_context->method); - list_for_each_entry(handler, _ctl->reset_handlers, -handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == reset_context->method) return handler; } } if (aldebaran_is_mode2_default(reset_ctl)) { - list_for_each_entry(handler, _ctl->reset_handlers, -handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == AMD_RESET_METHOD_MODE2) { reset_context->method = AMD_RESET_METHOD_MODE2; return handler; @@ -124,9 +123,9 @@ static void aldebaran_async_reset(struct work_struct *work) struct amdgpu_reset_control *reset_ctl = container_of(work, struct amdgpu_reset_control, reset_work); struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + int i; - list_for_each_entry(handler, _ctl->reset_handlers, -handler_list) { + for_each_handler(i, handler, reset_ctl) { if (handler->reset_method == reset_ctl->active_reset) { dev_dbg(adev->dev, "Resetting device\n"); handler->do_reset(adev); @@ -395,6 +394,11 @@ static struct amdgpu_reset_handler aldebaran_mode2_handler = { .do_reset = aldebaran_mode2_reset, }; +static struct amdgpu_reset_handler + *aldebaran_rst_handlers[AMDGPU_RESET_MAX_HANDLERS] = { + _mode2_handler, + }; + int aldebaran_reset_init(struct amdgpu_device *adev) { struct amdgpu_reset_control *reset_ctl; @@ -408,10 +412,9 @@ int aldebaran_reset_init(struct amdgpu_device *adev) reset_ctl->active_reset = AMD_RESET_METHOD_NONE; reset_ctl->get_reset_handler = aldebaran_get_reset_handler; - INIT_LIST_HEAD(_ctl->reset_handlers); INIT_WORK(_ctl->reset_work, reset_ctl->async_reset); /* Only mode2 is handled through reset control now */ - amdgpu_reset_add_handler(reset_ctl, _mode2_handler); + reset_ctl->reset_handlers = _rst_handlers; adev->reset_cntl = reset_ctl; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 5fed06ffcc6b..02d874799c16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -26,14 +26,6 @@ #include "sienna_cichlid.h" #include "smu_v13_0_10.h" -int amdgpu_reset_add_handler(struct amdgpu_reset_control *reset_ctl, -struct amdgpu_reset_handler *handler) -{ - /* TODO: Check if handler exists? */ - list_add_tail(>handler_list, _ctl->reset_handlers); - return 0; -} - int amdgpu_reset_init(struct amdgpu_device *adev) { int ret = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index f4a501ff87d9..471d789b33a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -26,6 +26,8 @@ #include "amdgpu.h" +#define AMDGPU_RESET_MAX_HANDLERS 5 + enum AMDGPU_RESET_FLAGS { AMDGPU_NEED_FULL_RESET = 0, @@ -44,7 +46,6 @@ struct amdgpu_reset_context { struct amdgpu_reset_handler { enum amd_reset_method reset_method; - struct list_head handler_list; int (*prepare_env)(struct amdgpu_reset_control *reset_ctl, struct amdgpu_reset_context *context); int (*prepare_hwcontext)(struct amdgpu_reset_control *reset_ctl, @@ -63,7 +64,8 @@ struct
[PATCH] drm/amd/pm: Fix temperature unit of SMU v13.0.6
Temperature needs to be reported in millidegree Celsius. Signed-off-by: Lijo Lazar --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 244e6d31560d..da8ba1aa57eb 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 @@ -708,16 +708,19 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, *value = SMUQ10_TO_UINT(metrics->SocketPower) << 8; break; case METRICS_TEMPERATURE_HOTSPOT: - *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature); + *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature) * +SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; case METRICS_TEMPERATURE_MEM: - *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature); + *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature) * +SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; /* This is the max of all VRs and not just SOC VR. * No need to define another data type for the same. */ case METRICS_TEMPERATURE_VRSOC: - *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature); + *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature) * +SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; default: *value = UINT_MAX; -- 2.25.1
RE: [PATCH] drm/amdgpu: Add I2C EEPROM support on smu v13_0_6
[AMD Official Use Only - General] Reviewed-by: Yang Wang Best Regards, Kevin -Original Message- From: amd-gfx On Behalf Of Candice Li Sent: Thursday, August 10, 2023 4:23 PM To: amd-gfx@lists.freedesktop.org Cc: Li, Candice Subject: [PATCH] drm/amdgpu: Add I2C EEPROM support on smu v13_0_6 Support I2C EEPROM on smu v13_0_6. Signed-off-by: Candice Li --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 4287743e121245..27fb9b640011c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -159,6 +159,7 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 2): /* Aldebaran */ case IP_VERSION(13, 0, 10): + case IP_VERSION(13, 0, 6): return true; default: return false; @@ -213,6 +214,7 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, return true; case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 10): + case IP_VERSION(13, 0, 6): control->i2c_address = EEPROM_I2C_MADDR_4; return true; default: -- 2.25.1
[PATCH v2] drm/amdgpu: Add I2C EEPROM support on smu v13_0_6
Support I2C EEPROM on smu v13_0_6. v2: Move IP_VERSION(13, 0, 6) ahead of IP_VERSION(13, 0, 10). Signed-off-by: Candice Li --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 4287743e121245..4764d2171f92e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -158,6 +158,7 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) case IP_VERSION(11, 0, 7): /* Sienna cichlid */ case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 2): /* Aldebaran */ + case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 10): return true; default: @@ -212,6 +213,7 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, control->i2c_address = EEPROM_I2C_MADDR_0; return true; case IP_VERSION(13, 0, 0): + case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 10): control->i2c_address = EEPROM_I2C_MADDR_4; return true; -- 2.25.1
RE: [PATCH] drm/amd/pm: Add vclk and dclk sysnode for GC 9.4.3
[Public] > -Original Message- > From: amd-gfx On Behalf Of Asad > Kamal > Sent: Wednesday, August 9, 2023 5:10 PM > To: amd-gfx@lists.freedesktop.org > Cc: Lazar, Lijo ; Kamal, Asad ; > Zhang, Hawking > Subject: [PATCH] drm/amd/pm: Add vclk and dclk sysnode for GC 9.4.3 > > Expose sysfs vclck and dclk entries for GC version 9.4.3 > > Signed-off-by: Asad Kamal > Reviewed-by: Lijo Lazar > --- > drivers/gpu/drm/amd/pm/amdgpu_pm.c | 6 -- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c > b/drivers/gpu/drm/amd/pm/amdgpu_pm.c > index 3922dd274f30..e4183d6d7f39 100644 > --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c > +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c > @@ -2095,7 +2095,8 @@ static int default_attr_update(struct > amdgpu_device *adev, struct amdgpu_device_ > gc_ver == IP_VERSION(10, 1, 2) || > gc_ver == IP_VERSION(11, 0, 0) || > gc_ver == IP_VERSION(11, 0, 2) || > - gc_ver == IP_VERSION(11, 0, 3))) > + gc_ver == IP_VERSION(11, 0, 3) || > + gc_ver == IP_VERSION(9, 4, 3))) I suggest to put IP_VERSION(9, 4, 3) prior to IP_VERSION(10...) to maintain it numerically. > *states = ATTR_STATE_UNSUPPORTED; > } else if (DEVICE_ATTR_IS(pp_dpm_vclk1)) { > if (!((gc_ver == IP_VERSION(10, 3, 1) || @@ -2109,7 +2110,8 > @@ static int default_attr_update(struct amdgpu_device *adev, struct > amdgpu_device_ > gc_ver == IP_VERSION(10, 1, 2) || > gc_ver == IP_VERSION(11, 0, 0) || > gc_ver == IP_VERSION(11, 0, 2) || > - gc_ver == IP_VERSION(11, 0, 3))) > + gc_ver == IP_VERSION(11, 0, 3) || > + gc_ver == IP_VERSION(9, 4, 3))) Same as above. Regards, Guchun > *states = ATTR_STATE_UNSUPPORTED; > } else if (DEVICE_ATTR_IS(pp_dpm_dclk1)) { > if (!((gc_ver == IP_VERSION(10, 3, 1) || > -- > 2.34.1
[PATCH] drm/amdgpu: Add I2C EEPROM support on smu v13_0_6
Support I2C EEPROM on smu v13_0_6. Signed-off-by: Candice Li --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 4287743e121245..27fb9b640011c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -159,6 +159,7 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 2): /* Aldebaran */ case IP_VERSION(13, 0, 10): + case IP_VERSION(13, 0, 6): return true; default: return false; @@ -213,6 +214,7 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, return true; case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 10): + case IP_VERSION(13, 0, 6): control->i2c_address = EEPROM_I2C_MADDR_4; return true; default: -- 2.25.1
Re: [PATCH] video/hdmi: convert *_infoframe_init() functions to void
Hi, On Tue, Aug 08, 2023 at 11:02:45AM -0700, Nikita Zhandarovich wrote: > Four hdmi_*_infoframe_init() functions that initialize different > types of hdmi infoframes only return the default 0 value, contrary to > their descriptions. Yet these functions are still unnecessarily checked > against possible errors in case of failure. > > Remove redundant error checks in calls to following functions: > - hdmi_spd_infoframe_init > - hdmi_audio_infoframe_init > - hdmi_vendor_infoframe_init > - hdmi_drm_infoframe_init > Also, convert these functions to 'void' and fix their descriptions. I'm not sure what value it actually adds. None of them return any errors, but very well might if we started to be a bit serious about it. Since the error handling is already there, then I'd rather leave it there. > Fixes: 2c676f378edb ("[media] hdmi: added unpack and logging functions for > InfoFrames") I'm confused about that part. What does it fix exactly? Maxime signature.asc Description: PGP signature
[PATCH V8 9/9] drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.7
Fulfill the SMU13.0.7 support for Wifi RFI mitigation feature. Signed-off-by: Evan Quan Reviewed-by: Mario Limonciello --- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 59 +++ 1 file changed, 59 insertions(+) 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 b1f0937ccade..d02fe284b05d 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 @@ -126,6 +126,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0), MSG_MAP(GetPptLimit,PPSMC_MSG_GetPptLimit, 0), MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0), + MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0), }; static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = { @@ -207,6 +208,7 @@ static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = { TAB_MAP(ACTIVITY_MONITOR_COEFF), [SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE}, TAB_MAP(OVERDRIVE), + TAB_MAP(WIFIBAND), }; static struct cmn2asic_mapping smu_v13_0_7_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { @@ -497,6 +499,9 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu) AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_COMBO_PPTABLE, MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND, + sizeof(WifiBandEntryTable_t), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM); smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); if (!smu_table->metrics_table) @@ -2173,6 +2178,57 @@ static int smu_v13_0_7_set_df_cstate(struct smu_context *smu, NULL); } +static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu) +{ + return smu->smc_fw_version > 0x00524600; +} + +static int smu_v13_0_7_set_wbrf_exclusion_ranges(struct smu_context *smu, +struct exclusion_range *exclusion_ranges) +{ + WifiBandEntryTable_t wifi_bands; + int valid_entries = 0; + int ret, i; + + memset(_bands, 0, sizeof(wifi_bands)); + for (i = 0; i < ARRAY_SIZE(wifi_bands.WifiBandEntry); i++) { + if (!exclusion_ranges[i].start && + !exclusion_ranges[i].end) + break; + + /* PMFW expects the inputs to be in Mhz unit */ + wifi_bands.WifiBandEntry[valid_entries].LowFreq = + DIV_ROUND_DOWN_ULL(exclusion_ranges[i].start, HZ_IN_MHZ); + wifi_bands.WifiBandEntry[valid_entries++].HighFreq = + DIV_ROUND_UP_ULL(exclusion_ranges[i].end, HZ_IN_MHZ); + } + wifi_bands.WifiBandEntryNum = valid_entries; + + /* +* Per confirm with PMFW team, WifiBandEntryNum = 0 is a valid setting. +* Considering the scenarios below: +* - At first the wifi device adds an exclusion range e.g. (2400,2500) to +* BIOS and our driver gets notified. We will set WifiBandEntryNum = 1 +* and pass the WifiBandEntry (2400, 2500) to PMFW. +* +* - Later the wifi device removes the wifiband list added above and +* our driver gets notified again. At this time, driver will set +* WifiBandEntryNum = 0 and pass an empty WifiBandEntry list to PMFW. +* - PMFW may still need to do some uclk shadow update(e.g. switching +* from shadow clock back to primary clock) on receiving this. +*/ + + ret = smu_cmn_update_table(smu, + SMU_TABLE_WIFIBAND, + 0, + (void *)(_bands), + true); + if (ret) + dev_err(smu->adev->dev, "Failed to set wifiband!"); + + return ret; +} + static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table, @@ -2241,6 +2297,9 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .set_mp1_state = smu_v13_0_7_set_mp1_state, .set_df_cstate = smu_v13_0_7_set_df_cstate, .gpo_control = smu_v13_0_gpo_control, + .is_asic_wbrf_supported = smu_v13_0_7_wbrf_support_check, + .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow, + .set_wbrf_exclusion_ranges = smu_v13_0_7_set_wbrf_exclusion_ranges, }; void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) --
[PATCH V8 8/9] drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.0
Fulfill the SMU13.0.0 support for Wifi RFI mitigation feature. Signed-off-by: Evan Quan Reviewed-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 3 + drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 +- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 + .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c| 9 +++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 60 +++ 5 files changed, 77 insertions(+), 1 deletion(-) 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 4d5cb1b511e5..54e76d6e66ce 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -325,6 +325,7 @@ enum smu_table_id SMU_TABLE_PACE, SMU_TABLE_ECCINFO, SMU_TABLE_COMBO_PPTABLE, + SMU_TABLE_WIFIBAND, SMU_TABLE_COUNT, }; @@ -1501,6 +1502,8 @@ enum smu_baco_seq { __dst_size); \ }) +#define HZ_IN_MHZ 100U + #if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4) int smu_get_power_limit(void *handle, uint32_t *limit, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index 297b70b9388f..5bbb60289a79 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -245,7 +245,8 @@ __SMU_DUMMY_MAP(AllowGpo), \ __SMU_DUMMY_MAP(Mode2Reset),\ __SMU_DUMMY_MAP(RequestI2cTransaction), \ - __SMU_DUMMY_MAP(GetMetricsTable), + __SMU_DUMMY_MAP(GetMetricsTable), \ + __SMU_DUMMY_MAP(EnableUCLKShadow), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(type) SMU_MSG_##type diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 355c156d871a..dd70b56aa71e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -299,5 +299,8 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap); +int smu_v13_0_enable_uclk_shadow(struct smu_context *smu, +bool enablement); + #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 9b62b45ebb7f..6a5cb582aa92 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -2472,3 +2472,12 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu, return 0; } + +int smu_v13_0_enable_uclk_shadow(struct smu_context *smu, +bool enablement) +{ + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_EnableUCLKShadow, + enablement, + NULL); +} 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 3d188616ba24..fd3ac18653ed 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 @@ -154,6 +154,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0), MSG_MAP(AllowIHHostInterrupt, PPSMC_MSG_AllowIHHostInterrupt, 0), MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0), + MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0), }; static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = { @@ -237,6 +238,7 @@ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = { TAB_MAP(I2C_COMMANDS), TAB_MAP(ECCINFO), TAB_MAP(OVERDRIVE), + TAB_MAP(WIFIBAND), }; static struct cmn2asic_mapping smu_v13_0_0_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { @@ -481,6 +483,9 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu) PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND, + sizeof(WifiBandEntryTable_t), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM); smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); if (!smu_table->metrics_table) @@ -2593,6 +2598,58 @@ static ssize_t smu_v13_0_0_get_ecc_info(struct smu_context *smu, return ret; } +static bool
[PATCH V8 6/9] drm/amd/pm: setup the framework to support Wifi RFI mitigation feature
With WBRF feature supported, as a driver responding to the frequencies, amdgpu driver is able to do shadow pstate switching to mitigate possible interference(between its (G-)DDR memory clocks and local radio module frequency bands used by Wifi 6/6e/7). Signed-off-by: Evan Quan Reviewed-by: Mario Limonciello -- v1->v2: - update the prompt for feature support(Lijo) --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 17 ++ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 194 ++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 23 +++ drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 3 + 5 files changed, 239 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index a3b86b86dc47..2bfc9111ab00 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -247,6 +247,8 @@ extern int amdgpu_sg_display; extern int amdgpu_user_partt_mode; +extern int amdgpu_wbrf; + #define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD(256*1024*1024) #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 0593ef8fe0a6..1c574bd3b60d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -195,6 +195,7 @@ int amdgpu_use_xgmi_p2p = 1; int amdgpu_vcnfw_log; int amdgpu_sg_display = -1; /* auto */ int amdgpu_user_partt_mode = AMDGPU_AUTO_COMPUTE_PARTITION_MODE; +int amdgpu_wbrf = -1; static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); @@ -981,6 +982,22 @@ module_param_named(user_partt_mode, amdgpu_user_partt_mode, uint, 0444); module_param(enforce_isolation, bool, 0444); MODULE_PARM_DESC(enforce_isolation, "enforce process isolation between graphics and compute . enforce_isolation = on"); +/** + * DOC: wbrf (int) + * Enable Wifi RFI interference mitigation feature. + * Due to electrical and mechanical constraints there may be likely interference of + * relatively high-powered harmonics of the (G-)DDR memory clocks with local radio + * module frequency bands used by Wifi 6/6e/7. To mitigate the possible RFI interference, + * with this feature enabled, PMFW will use either “shadowed P-State” or “P-State” based + * on active list of frequencies in-use (to be avoided) as part of initial setting or + * P-state transition. However, there may be potential performance impact with this + * feature enabled. + * (0 = disabled, 1 = enabled, -1 = auto (default setting, will be enabled if supported)) + */ +MODULE_PARM_DESC(wbrf, + "Enable Wifi RFI interference mitigation (0 = disabled, 1 = enabled, -1 = auto(default)"); +module_param_named(wbrf, amdgpu_wbrf, int, 0444); + /* These devices are not supported by amdgpu. * They are supported by the mach64, r128, radeon drivers */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ce41a8309582..163037bd6d16 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1228,6 +1228,173 @@ static int smu_get_thermal_temperature_range(struct smu_context *smu) return ret; } +/** + * smu_wbrf_handle_exclusion_ranges - consume the wbrf exclusion ranges + * + * @smu: smu_context pointer + * + * Retrieve the wbrf exclusion ranges and send them to PMFW for proper handling. + * Returns 0 on success, error on failure. + */ +static int smu_wbrf_handle_exclusion_ranges(struct smu_context *smu) +{ + struct wbrf_ranges_out wbrf_exclusion = {0}; + struct exclusion_range *wifi_bands = wbrf_exclusion.band_list; + struct amdgpu_device *adev = smu->adev; + uint64_t start, end; + int ret, i, j; + + ret = wbrf_retrieve_exclusions(adev->dev, _exclusion); + if (ret) { + dev_err(adev->dev, "Failed to retrieve exclusion ranges!\n"); + return ret; + } + + /* +* The exclusion ranges array we got might be filled with holes and duplicate +* entries. For example: +* {(2400, 2500), (0, 0), (6882, 6962), (2400, 2500), (0, 0), (6117, 6189), (0, 0)...} +* We need to do some sortups to eliminate those holes and duplicate entries. +* Expected output: {(2400, 2500), (6117, 6189), (6882, 6962), (0, 0)...} +*/ + for (i = 0; i < MAX_NUM_OF_WBRF_RANGES; i++) { + start = wifi_bands[i].start; + end = wifi_bands[i].end; + + /* get the last valid entry to fill the intermediate hole */ + if (!start && !end) { + for (j = MAX_NUM_OF_WBRF_RANGES - 1; j > i; j--) + if (wifi_bands[j].start && + wifi_bands[j].end) + break;
[PATCH V8 7/9] drm/amd/pm: add flood detection for wbrf events
To protect PMFW from being overloaded. Signed-off-by: Evan Quan Reviewed-by: Mario Limonciello --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 31 +++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 7 + 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 163037bd6d16..aa5e1123ac0a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1318,7 +1318,8 @@ static int smu_wbrf_event_handler(struct notifier_block *nb, switch (action) { case WBRF_CHANGED: - smu_wbrf_handle_exclusion_ranges(smu); + schedule_delayed_work(>wbrf_delayed_work, + msecs_to_jiffies(SMU_WBRF_EVENT_HANDLING_PACE)); break; default: return NOTIFY_DONE; @@ -1327,6 +1328,21 @@ static int smu_wbrf_event_handler(struct notifier_block *nb, return NOTIFY_OK; } +/** + * smu_wbrf_delayed_work_handler - callback on delayed work timer expired + * + * @work: struct work_struct pointer + * + * Flood is over and driver will consume the latest exclusion ranges. + */ +static void smu_wbrf_delayed_work_handler(struct work_struct *work) +{ + struct smu_context *smu = + container_of(work, struct smu_context, wbrf_delayed_work.work); + + smu_wbrf_handle_exclusion_ranges(smu); +} + /** * smu_wbrf_support_check - check wbrf support * @@ -1357,12 +1373,14 @@ static void smu_wbrf_support_check(struct smu_context *smu) */ static int smu_wbrf_init(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; int ret; if (!smu->wbrf_supported) return 0; + INIT_DELAYED_WORK(>wbrf_delayed_work, + smu_wbrf_delayed_work_handler); + smu->wbrf_notifier.notifier_call = smu_wbrf_event_handler; ret = wbrf_register_notifier(>wbrf_notifier); if (ret) @@ -1373,11 +1391,10 @@ static int smu_wbrf_init(struct smu_context *smu) * before our driver loaded. To make sure our driver * is awared of those exclusion ranges. */ - ret = smu_wbrf_handle_exclusion_ranges(smu); - if (ret) - dev_err(adev->dev, "Failed to handle wbrf exclusion ranges\n"); + schedule_delayed_work(>wbrf_delayed_work, + msecs_to_jiffies(SMU_WBRF_EVENT_HANDLING_PACE)); - return ret; + return 0; } /** @@ -1393,6 +1410,8 @@ static void smu_wbrf_fini(struct smu_context *smu) return; wbrf_unregister_notifier(>wbrf_notifier); + + cancel_delayed_work_sync(>wbrf_delayed_work); } static int smu_smc_hw_setup(struct smu_context *smu) 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 244297979f92..4d5cb1b511e5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -480,6 +480,12 @@ struct stb_context { #define WORKLOAD_POLICY_MAX 7 +/* + * Configure wbrf event handling pace as there can be only one + * event processed every SMU_WBRF_EVENT_HANDLING_PACE ms. + */ +#define SMU_WBRF_EVENT_HANDLING_PACE 10 + struct smu_context { struct amdgpu_device*adev; @@ -581,6 +587,7 @@ struct smu_context /* data structures for wbrf feature support */ boolwbrf_supported; struct notifier_block wbrf_notifier; + struct delayed_work wbrf_delayed_work; }; struct i2c_adapter; -- 2.34.1
[PATCH V8 5/9] drm/amd/pm: update driver_if and ppsmc headers for coming wbrf feature
Add those data structures to support Wifi RFI mitigation feature. Signed-off-by: Evan Quan Reviewed-by: Mario Limonciello --- .../pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h | 14 +- .../pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h | 14 +- .../amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h | 3 ++- .../amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h | 3 ++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h index 9dd1ed5b8940..e481407b6584 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h @@ -391,6 +391,17 @@ typedef struct { EccInfo_t EccInfo[24]; } EccInfoTable_t; +typedef struct { + uint16_t LowFreq; + uint16_t HighFreq; +} WifiOneBand_t; + +typedef struct { + uint32_t WifiBandEntryNum; + WifiOneBand_tWifiBandEntry[11]; + uint32_t MmHubPadding[8]; +} WifiBandEntryTable_t; + //D3HOT sequences typedef enum { BACO_SEQUENCE, @@ -1615,7 +1626,8 @@ typedef struct { #define TABLE_I2C_COMMANDS9 #define TABLE_DRIVER_INFO 10 #define TABLE_ECCINFO 11 -#define TABLE_COUNT 12 +#define TABLE_WIFIBAND12 +#define TABLE_COUNT 13 //IH Interupt ID #define IH_INTERRUPT_ID_TO_DRIVER 0xFE diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h index 62b7c0daff68..1530ca002c6c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h @@ -392,6 +392,17 @@ typedef struct { EccInfo_t EccInfo[24]; } EccInfoTable_t; +typedef struct { + uint16_t LowFreq; + uint16_t HighFreq; +} WifiOneBand_t; + +typedef struct { + uint32_t WifiBandEntryNum; + WifiOneBand_tWifiBandEntry[11]; + uint32_t MmHubPadding[8]; +} WifiBandEntryTable_t; + //D3HOT sequences typedef enum { BACO_SEQUENCE, @@ -1605,7 +1616,8 @@ typedef struct { #define TABLE_I2C_COMMANDS9 #define TABLE_DRIVER_INFO 10 #define TABLE_ECCINFO 11 -#define TABLE_COUNT 12 +#define TABLE_WIFIBAND12 +#define TABLE_COUNT 13 //IH Interupt ID #define IH_INTERRUPT_ID_TO_DRIVER 0xFE diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h index 10cff75b44d5..c98cc32d11bd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h @@ -138,7 +138,8 @@ #define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A #define PPSMC_MSG_SetPriorityDeltaGain 0x4B #define PPSMC_MSG_AllowIHHostInterrupt 0x4C -#define PPSMC_Message_Count 0x4D +#define PPSMC_MSG_EnableUCLKShadow 0x51 +#define PPSMC_Message_Count 0x52 //Debug Dump Message #define DEBUGSMC_MSG_TestMessage0x1 diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h index 6aaefca9b595..a6bf9cdd130e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h @@ -134,6 +134,7 @@ #define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A #define PPSMC_MSG_SetPriorityDeltaGain 0x4B #define PPSMC_MSG_AllowIHHostInterrupt 0x4C -#define PPSMC_Message_Count 0x4D +#define PPSMC_MSG_EnableUCLKShadow 0x51 +#define PPSMC_Message_Count 0x52 #endif -- 2.34.1
[PATCH V8 4/9] wifi: mac80211: Add support for WBRF features
To support the WBRF mechanism, Wifi adapters utilized in the system must register the frequencies in use(or unregister those frequencies no longer used) via the dedicated calls. So that, other drivers responding to the frequencies can take proper actions to mitigate possible interference. Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Co-developed-by: Evan Quan Signed-off-by: Evan Quan -- v1->v2: - place the new added member(`wbrf_supported`) in ieee80211_local(Johannes) - handle chandefs change scenario properly(Johannes) - some minor fixes around code sharing and possible invalid input checks(Johannes) v2->v3: - drop unnecessary input checks and intermediate APIs(Mario) - Separate some mac80211 common code(Mario, Johannes) v3->v4: - some minor fixes around return values(Johannes) --- include/linux/ieee80211.h | 1 + net/mac80211/Makefile | 2 + net/mac80211/chan.c| 9 net/mac80211/ieee80211_i.h | 9 net/mac80211/main.c| 2 + net/mac80211/wbrf.c| 103 + 6 files changed, 126 insertions(+) create mode 100644 net/mac80211/wbrf.c diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 4b998090898e..f995d06da87f 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4335,6 +4335,7 @@ static inline int ieee80211_get_tdls_action(struct sk_buff *skb, u32 hdr_size) /* convert frequencies */ #define MHZ_TO_KHZ(freq) ((freq) * 1000) #define KHZ_TO_MHZ(freq) ((freq) / 1000) +#define KHZ_TO_HZ(freq) ((freq) * 1000) #define PR_KHZ(f) KHZ_TO_MHZ(f), f % 1000 #define KHZ_F "%d.%03d" diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index b8de44da1fb8..d46c36f55fd3 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -65,4 +65,6 @@ rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += \ mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) +mac80211-y += wbrf.o + ccflags-y += -DDEBUG diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 68952752b599..458469c224ae 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -506,11 +506,16 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local, WARN_ON(!cfg80211_chandef_compatible(>conf.def, chandef)); + ieee80211_remove_wbrf(local, >conf.def); + ctx->conf.def = *chandef; /* check if min chanctx also changed */ changed = IEEE80211_CHANCTX_CHANGE_WIDTH | _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for); + + ieee80211_add_wbrf(local, >conf.def); + drv_change_chanctx(local, ctx, changed); if (!local->use_chanctx) { @@ -668,6 +673,8 @@ static int ieee80211_add_chanctx(struct ieee80211_local *local, lockdep_assert_held(>mtx); lockdep_assert_held(>chanctx_mtx); + ieee80211_add_wbrf(local, >conf.def); + if (!local->use_chanctx) local->hw.conf.radar_enabled = ctx->conf.radar_enabled; @@ -748,6 +755,8 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local, } ieee80211_recalc_idle(local); + + ieee80211_remove_wbrf(local, >conf.def); } static void ieee80211_free_chanctx(struct ieee80211_local *local, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 91633a0b723e..719f2c892132 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1600,6 +1600,8 @@ struct ieee80211_local { /* extended capabilities provided by mac80211 */ u8 ext_capa[8]; + + bool wbrf_supported; }; static inline struct ieee80211_sub_if_data * @@ -2638,4 +2640,11 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, const struct ieee80211_eht_cap_elem *eht_cap_ie_elem, u8 eht_cap_len, struct link_sta_info *link_sta); + +void ieee80211_check_wbrf_support(struct ieee80211_local *local); +void ieee80211_add_wbrf(struct ieee80211_local *local, + struct cfg80211_chan_def *chandef); +void ieee80211_remove_wbrf(struct ieee80211_local *local, + struct cfg80211_chan_def *chandef); + #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 24315d7b3126..b20bdaac84db 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1396,6 +1396,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) debugfs_hw_add(local); rate_control_add_debugfs(local); + ieee80211_check_wbrf_support(local); + rtnl_lock(); wiphy_lock(hw->wiphy); diff --git a/net/mac80211/wbrf.c b/net/mac80211/wbrf.c new file mode 100644 index ..7ddb29d128b1 --- /dev/null +++ b/net/mac80211/wbrf.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Wifi Band Exclusion Interface for WWAN + * Copyright (C)
[PATCH V8 3/9] cfg80211: expose nl80211_chan_width_to_mhz for wide sharing
The newly added WBRF feature needs this interface for channel width calculation. Signed-off-by: Evan Quan --- include/net/cfg80211.h | 8 net/wireless/chan.c| 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7c7d03aa9d06..f50508e295db 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -920,6 +920,14 @@ const struct cfg80211_chan_def * cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1, const struct cfg80211_chan_def *chandef2); +/** + * nl80211_chan_width_to_mhz - get the channel width in Mhz + * @chan_width: the channel width from nl80211_chan_width + * Return: channel width in Mhz if the chan_width from nl80211_chan_width + * is valid. -1 otherwise. + */ +int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width); + /** * cfg80211_chandef_valid - check if a channel definition is valid * @chandef: the channel definition to check diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 0b7e81db383d..227db04eac42 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -141,7 +141,7 @@ static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef) return true; } -static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width) +int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width) { int mhz; @@ -190,6 +190,7 @@ static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width) } return mhz; } +EXPORT_SYMBOL(nl80211_chan_width_to_mhz); static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) { -- 2.34.1
[PATCH V8 2/9] drivers core: add ACPI based WBRF mechanism introduced by AMD
AMD has introduced an ACPI based mechanism to support WBRF for some platforms with AMD dGPU + WLAN. This needs support from BIOS equipped with necessary AML implementations and dGPU firmwares. For those systems without the ACPI mechanism and developing solutions, user can use/fall-back the generic WBRF solution for diagnosing potential interference issues. And for the platform which does not equip with the necessary AMD ACPI implementations but with CONFIG_WBRF_AMD_ACPI built as 'y', it will fall back to generic WBRF solution if the `wbrf` is set as "on". Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Co-developed-by: Evan Quan Signed-off-by: Evan Quan -- v4->v5: - promote this to be a more generic solution with input argument taking `struct device` and provide better scalability to support non-ACPI scenarios(Andrew) - update the APIs naming and some other minor fixes(Rafael) v5->v6: - make the code more readable and some other fixes(Andrew) v6->v8: - drop CONFIG_WBRF_GENERIC(Mario) - add `wbrf` kernel parameter for policy control(Mario) --- drivers/acpi/Makefile | 2 + drivers/acpi/amd_wbrf.c | 294 ++ drivers/base/Kconfig | 20 +++ drivers/base/wbrf.c | 135 +--- include/linux/acpi_amd_wbrf.h | 25 +++ 5 files changed, 452 insertions(+), 24 deletions(-) create mode 100644 drivers/acpi/amd_wbrf.c create mode 100644 include/linux/acpi_amd_wbrf.h diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3fc5a0d54f6e..9185d16e4495 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -133,3 +133,5 @@ obj-$(CONFIG_ARM64) += arm64/ obj-$(CONFIG_ACPI_VIOT)+= viot.o obj-$(CONFIG_RISCV)+= riscv/ + +obj-$(CONFIG_WBRF_AMD_ACPI)+= amd_wbrf.o diff --git a/drivers/acpi/amd_wbrf.c b/drivers/acpi/amd_wbrf.c new file mode 100644 index ..a3390d91cbea --- /dev/null +++ b/drivers/acpi/amd_wbrf.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Wifi Band Exclusion Interface (AMD ACPI Implementation) + * Copyright (C) 2023 Advanced Micro Devices + * + */ + +#include +#include + +#define ACPI_AMD_WBRF_METHOD "\\WBRF" + +/* + * Functions bit vector for WBRF method + * + * Bit 0: Supported for any functions other than function 0. + * Bit 1: Function 1 (Add / Remove frequency) is supported. + * Bit 2: Function 2 (Get frequency list) is supported. + */ +#define WBRF_ENABLED 0x0 +#define WBRF_RECORD0x1 +#define WBRF_RETRIEVE 0x2 + +/* record actions */ +#define WBRF_RECORD_ADD0x0 +#define WBRF_RECORD_REMOVE 0x1 + +#define WBRF_REVISION 0x1 + +/* + * The data structure used for WBRF_RETRIEVE is not natually aligned. + * And unfortunately the design has been settled down. + */ +struct amd_wbrf_ranges_out { + u32 num_of_ranges; + struct exclusion_range band_list[MAX_NUM_OF_WBRF_RANGES]; +} __packed; + +static const guid_t wifi_acpi_dsm_guid = + GUID_INIT(0x7b7656cf, 0xdc3d, 0x4c1c, + 0x83, 0xe9, 0x66, 0xe7, 0x21, 0xde, 0x30, 0x70); + +static int wbrf_dsm(struct acpi_device *adev, u8 fn, + union acpi_object *argv4, + union acpi_object **out) +{ + union acpi_object *obj; + int rc; + + obj = acpi_evaluate_dsm(adev->handle, _acpi_dsm_guid, + WBRF_REVISION, fn, argv4); + if (!obj) + return -ENXIO; + + switch (obj->type) { + case ACPI_TYPE_BUFFER: + *out = obj; + return 0; + + case ACPI_TYPE_INTEGER: + rc = obj->integer.value ? -EINVAL : 0; + break; + + default: + rc = -EOPNOTSUPP; + } + + ACPI_FREE(obj); + + return rc; +} + +static int wbrf_record(struct acpi_device *adev, uint8_t action, + struct wbrf_ranges_in *in) +{ + union acpi_object argv4; + union acpi_object *tmp; + u32 num_of_ranges = 0; + u32 num_of_elements; + u32 arg_idx = 0; + u32 loop_idx; + int ret; + + if (!in) + return -EINVAL; + + for (loop_idx = 0; loop_idx < ARRAY_SIZE(in->band_list); +loop_idx++) + if (in->band_list[loop_idx].start && + in->band_list[loop_idx].end) + num_of_ranges++; + + /* +* Every range comes with two end points(start and end) and +* each of them is accounted as an element. Meanwhile the range +* count and action type are accounted as an element each. +* So, the total element count = 2 * num_of_ranges + 1 + 1. +*/ + num_of_elements = 2 * num_of_ranges + 1 + 1; + + tmp = kcalloc(num_of_elements, sizeof(*tmp), GFP_KERNEL); + if (!tmp) +
[PATCH V8 1/9] drivers core: Add support for Wifi band RF mitigations
Due to electrical and mechanical constraints in certain platform designs there may be likely interference of relatively high-powered harmonics of the (G-)DDR memory clocks with local radio module frequency bands used by Wifi 6/6e/7. To mitigate this, AMD has introduced a mechanism that devices can use to notify active use of particular frequencies so that other devices can make relative internal adjustments as necessary to avoid this resonance. In order for a device to support this, the expected flow for device driver or subsystems: Drivers/subsystems contributing frequencies: 1) During probe, check `wbrf_supported_producer` to see if WBRF supported for the device. 2) If adding frequencies, then call `wbrf_add_exclusion` with the start and end ranges of the frequencies. 3) If removing frequencies, then call `wbrf_remove_exclusion` with start and end ranges of the frequencies. Drivers/subsystems responding to frequencies: 1) During probe, check `wbrf_supported_consumer` to see if WBRF is supported for the device. 2) Call the `wbrf_register_notifier` to register for notifications of frequency changes from other devices. 3) Call the `wbrf_retrieve_exclusions` to retrieve the current exclusions range on receiving a notification and response correspondingly. Meanwhile a kernel parameter `wbrf` with default setting as "auto" is introduced to specify what the policy is. - With `wbrf=on`, the WBRF features will be enabled forcely. - With `wbrf=off`, the WBRF features will be disabled forcely. - With `wbrf=auto`, it will be up to the system to do proper checks to determine the WBRF features should be enabled or not. Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Co-developed-by: Evan Quan Signed-off-by: Evan Quan -- v4->v5: - promote this to be a more generic solution with input argument taking `struct device` and provide better scalability to support non-ACPI scenarios(Andrew) - update the APIs naming and some other minor fixes(Rafael) v6->v7: - revised the `struct wbrf_ranges_out` to be naturally aligned(Andrew) - revised some code comments(Andrew) --- .../admin-guide/kernel-parameters.txt | 9 + drivers/base/Makefile | 1 + drivers/base/wbrf.c | 280 ++ include/linux/wbrf.h | 47 +++ 4 files changed, 337 insertions(+) create mode 100644 drivers/base/wbrf.c create mode 100644 include/linux/wbrf.h diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a1457995fd41..21f73a0bbd0b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7152,3 +7152,12 @@ xmon commands. off xmon is disabled. + wbrf= [KNL] + Format: { on | auto | off } + Controls if WBRF features should be enabled or disabled + forcely. Default is auto. + on Force enable the WBRF features. + autoUp to the system to do proper checks to + determine the WBRF features should be enabled + or not. + off Force disable the WBRF features. diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 3079bfe53d04..7b3cef898c19 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_GENERIC_MSI_IRQ) += platform-msi.o obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o obj-$(CONFIG_ACPI) += physical_location.o +obj-y += wbrf.o obj-y += test/ diff --git a/drivers/base/wbrf.c b/drivers/base/wbrf.c new file mode 100644 index ..678f245c12c6 --- /dev/null +++ b/drivers/base/wbrf.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Wifi Band Exclusion Interface + * Copyright (C) 2023 Advanced Micro Devices + * + */ + +#include + +static BLOCKING_NOTIFIER_HEAD(wbrf_chain_head); +static DEFINE_MUTEX(wbrf_mutex); +static enum WBRF_POLICY_MODE { + WBRF_POLICY_FORCE_DISABLE, + WBRF_POLICY_AUTO, + WBRF_POLICY_FORCE_ENABLE, +} wbrf_policy = WBRF_POLICY_AUTO; + +static int __init parse_wbrf_policy_mode(char *p) +{ + if (!strncmp(p, "auto", 4)) + wbrf_policy = WBRF_POLICY_AUTO; + else if (!strncmp(p, "on", 2)) + wbrf_policy = WBRF_POLICY_FORCE_ENABLE; + else if (!strncmp(p, "off", 3)) + wbrf_policy = WBRF_POLICY_FORCE_DISABLE; + else + return -EINVAL; + + return 0; +} +early_param("wbrf", parse_wbrf_policy_mode); + +static struct exclusion_range_pool { + struct exclusion_range band_list[MAX_NUM_OF_WBRF_RANGES]; + u64
[PATCH V8 0/9] Enable Wifi RFI interference mitigation feature support
Due to electrical and mechanical constraints in certain platform designs there may be likely interference of relatively high-powered harmonics of the (G-)DDR memory clocks with local radio module frequency bands used by Wifi 6/6e/7. To mitigate possible RFI interference producers can advertise the frequencies in use and consumers can use this information to avoid using these frequencies for sensitive features. The whole patch set is based on Linux 6.5-rc5. With some brief introductions as below: Patch1 - 2: Core functionality setup for WBRF feature support Patch3 - 4: Bring WBRF support to wifi subsystem. Patch5 - 9: Bring WBRF support to AMD graphics driver. Evan Quan (9): drivers core: Add support for Wifi band RF mitigations drivers core: add ACPI based WBRF mechanism introduced by AMD cfg80211: expose nl80211_chan_width_to_mhz for wide sharing wifi: mac80211: Add support for WBRF features drm/amd/pm: update driver_if and ppsmc headers for coming wbrf feature drm/amd/pm: setup the framework to support Wifi RFI mitigation feature drm/amd/pm: add flood detection for wbrf events drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.0 drm/amd/pm: enable Wifi RFI mitigation feature support for SMU13.0.7 .../admin-guide/kernel-parameters.txt | 9 + drivers/acpi/Makefile | 2 + drivers/acpi/amd_wbrf.c | 294 ++ drivers/base/Kconfig | 20 + drivers/base/Makefile | 1 + drivers/base/wbrf.c | 367 ++ drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 17 + drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 213 ++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 33 ++ .../inc/pmfw_if/smu13_driver_if_v13_0_0.h | 14 +- .../inc/pmfw_if/smu13_driver_if_v13_0_7.h | 14 +- .../pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h | 3 +- .../pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h | 3 +- drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 +- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 3 + .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c| 9 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 60 +++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 59 +++ drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 3 + include/linux/acpi_amd_wbrf.h | 25 ++ include/linux/ieee80211.h | 1 + include/linux/wbrf.h | 47 +++ include/net/cfg80211.h| 8 + net/mac80211/Makefile | 2 + net/mac80211/chan.c | 9 + net/mac80211/ieee80211_i.h| 9 + net/mac80211/main.c | 2 + net/mac80211/wbrf.c | 103 + net/wireless/chan.c | 3 +- 30 files changed, 1332 insertions(+), 6 deletions(-) create mode 100644 drivers/acpi/amd_wbrf.c create mode 100644 drivers/base/wbrf.c create mode 100644 include/linux/acpi_amd_wbrf.h create mode 100644 include/linux/wbrf.h create mode 100644 net/mac80211/wbrf.c -- 2.34.1