]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amdgpu: Fix memory leak of i2s_pdata in ACP initialization
authorCe Sun <cesun102@amd.com>
Tue, 12 May 2026 01:53:21 +0000 (09:53 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 May 2026 15:51:39 +0000 (11:51 -0400)
Currently, the i2s_pdata structure is dynamically allocated in
acp_hw_init() but never freed in both the error handling path and
the acp_hw_fini() cleanup path, causing a permanent memory leak.

Signed-off-by: Ce Sun <cesun102@amd.com>
Reviewed-by: Tao Zhou <tao.zhou1@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h

index 62807b65f2af8b9602ce9a468826aa63d4894057..4c732e0f776e1269399469dd3d66369bfe5062be 100644 (file)
@@ -228,7 +228,6 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
        u64 acp_base;
        u32 val = 0;
        u32 count = 0;
-       struct i2s_platform_data *i2s_pdata = NULL;
 
        struct amdgpu_device *adev = ip_block->adev;
 
@@ -272,18 +271,18 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
                        goto failure;
                }
 
-               i2s_pdata = kzalloc_objs(struct i2s_platform_data, 1);
-               if (!i2s_pdata) {
+               adev->acp.i2s_pdata = kzalloc_objs(struct i2s_platform_data, 1);
+               if (!adev->acp.i2s_pdata) {
                        r = -ENOMEM;
                        goto failure;
                }
 
-               i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
-                                     DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
-               i2s_pdata[0].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
-               i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
-               i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
-               i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
+               adev->acp.i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
+                                               DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
+               adev->acp.i2s_pdata[0].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
+               adev->acp.i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
+               adev->acp.i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
+               adev->acp.i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
 
                adev->acp.acp_res[0].name = "acp2x_dma";
                adev->acp.acp_res[0].flags = IORESOURCE_MEM;
@@ -311,7 +310,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
                adev->acp.acp_cell[1].id = 1;
                adev->acp.acp_cell[1].num_resources = 1;
                adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1];
-               adev->acp.acp_cell[1].platform_data = &i2s_pdata[0];
+               adev->acp.acp_cell[1].platform_data = &adev->acp.i2s_pdata[0];
                adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data);
                r = mfd_add_devices(adev->acp.parent, 0, adev->acp.acp_cell, 2, NULL, 0, NULL);
                if (r)
@@ -336,53 +335,53 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
                        goto failure;
                }
 
-               i2s_pdata = kzalloc_objs(struct i2s_platform_data, 3);
-               if (!i2s_pdata) {
+               adev->acp.i2s_pdata = kzalloc_objs(struct i2s_platform_data, 3);
+               if (!adev->acp.i2s_pdata) {
                        r = -ENOMEM;
                        goto failure;
                }
 
                switch (adev->asic_type) {
                case CHIP_STONEY:
-                       i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
-                               DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
+                       adev->acp.i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
+                                                       DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
                        break;
                default:
-                       i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
+                       adev->acp.i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
                }
-               i2s_pdata[0].cap = DWC_I2S_PLAY;
-               i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
-               i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_PLAY_REG_OFFSET;
-               i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_PLAY_REG_OFFSET;
+               adev->acp.i2s_pdata[0].cap = DWC_I2S_PLAY;
+               adev->acp.i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
+               adev->acp.i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_PLAY_REG_OFFSET;
+               adev->acp.i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_PLAY_REG_OFFSET;
                switch (adev->asic_type) {
                case CHIP_STONEY:
-                       i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
-                               DW_I2S_QUIRK_COMP_PARAM1 |
-                               DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
+                       adev->acp.i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
+                                                       DW_I2S_QUIRK_COMP_PARAM1 |
+                                                       DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
                        break;
                default:
-                       i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
-                               DW_I2S_QUIRK_COMP_PARAM1;
+                       adev->acp.i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
+                                                       DW_I2S_QUIRK_COMP_PARAM1;
                }
 
-               i2s_pdata[1].cap = DWC_I2S_RECORD;
-               i2s_pdata[1].snd_rates = SNDRV_PCM_RATE_8000_96000;
-               i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
-               i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
+               adev->acp.i2s_pdata[1].cap = DWC_I2S_RECORD;
+               adev->acp.i2s_pdata[1].snd_rates = SNDRV_PCM_RATE_8000_96000;
+               adev->acp.i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
+               adev->acp.i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
 
-               i2s_pdata[2].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
+               adev->acp.i2s_pdata[2].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
                switch (adev->asic_type) {
                case CHIP_STONEY:
-                       i2s_pdata[2].quirks |= DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
+                       adev->acp.i2s_pdata[2].quirks |= DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
                        break;
                default:
                        break;
                }
 
-               i2s_pdata[2].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
-               i2s_pdata[2].snd_rates = SNDRV_PCM_RATE_8000_96000;
-               i2s_pdata[2].i2s_reg_comp1 = ACP_BT_COMP1_REG_OFFSET;
-               i2s_pdata[2].i2s_reg_comp2 = ACP_BT_COMP2_REG_OFFSET;
+               adev->acp.i2s_pdata[2].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
+               adev->acp.i2s_pdata[2].snd_rates = SNDRV_PCM_RATE_8000_96000;
+               adev->acp.i2s_pdata[2].i2s_reg_comp1 = ACP_BT_COMP1_REG_OFFSET;
+               adev->acp.i2s_pdata[2].i2s_reg_comp2 = ACP_BT_COMP2_REG_OFFSET;
 
                adev->acp.acp_res[0].name = "acp2x_dma";
                adev->acp.acp_res[0].flags = IORESOURCE_MEM;
@@ -420,21 +419,21 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
                adev->acp.acp_cell[1].id = 1;
                adev->acp.acp_cell[1].num_resources = 1;
                adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1];
-               adev->acp.acp_cell[1].platform_data = &i2s_pdata[0];
+               adev->acp.acp_cell[1].platform_data = &adev->acp.i2s_pdata[0];
                adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data);
 
                adev->acp.acp_cell[2].name = "designware-i2s";
                adev->acp.acp_cell[2].id = 2;
                adev->acp.acp_cell[2].num_resources = 1;
                adev->acp.acp_cell[2].resources = &adev->acp.acp_res[2];
-               adev->acp.acp_cell[2].platform_data = &i2s_pdata[1];
+               adev->acp.acp_cell[2].platform_data = &adev->acp.i2s_pdata[1];
                adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data);
 
                adev->acp.acp_cell[3].name = "designware-i2s";
                adev->acp.acp_cell[3].id = 3;
                adev->acp.acp_cell[3].num_resources = 1;
                adev->acp.acp_cell[3].resources = &adev->acp.acp_res[3];
-               adev->acp.acp_cell[3].platform_data = &i2s_pdata[2];
+               adev->acp.acp_cell[3].platform_data = &adev->acp.i2s_pdata[2];
                adev->acp.acp_cell[3].pdata_size = sizeof(struct i2s_platform_data);
 
                r = mfd_add_devices(adev->acp.parent, 0, adev->acp.acp_cell, ACP_DEVS, NULL, 0, NULL);
@@ -491,7 +490,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
        return 0;
 
 failure:
-       kfree(i2s_pdata);
+       kfree(adev->acp.i2s_pdata);
        kfree(adev->acp.acp_res);
        kfree(adev->acp.acp_cell);
        kfree(adev->acp.acp_genpd);
@@ -556,6 +555,7 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block)
                              acp_genpd_remove_device);
 
        mfd_remove_devices(adev->acp.parent);
+       kfree(adev->acp.i2s_pdata);
        kfree(adev->acp.acp_res);
        kfree(adev->acp.acp_genpd);
        kfree(adev->acp.acp_cell);
index a288ce25c176528a792bb1b751453a27bddc486b..13b48c582314429eeea32805c4bf89127f0aba34 100644 (file)
@@ -35,6 +35,7 @@ struct amdgpu_acp {
        struct mfd_cell *acp_cell;
        struct resource *acp_res;
        struct acp_pm_domain *acp_genpd;
+       struct i2s_platform_data *i2s_pdata;
 };
 
 extern const struct amdgpu_ip_block_version acp_ip_block;