From 2bd2fdeeb265d2e909f96a399c290ee43e1243a2 Mon Sep 17 00:00:00 2001 From: Aviral Gupta Date: Mon, 24 Mar 2014 22:19:52 +0530 Subject: [PATCH] ASoC: msm: update machine and codec driver for proper ioremap checks ioremapped address is directly accessed without a proper NULL check. This causes the NULL pointer dereference leading to target crash. Crosscheck for the address returned by the ioremap api. Change-Id: I343a11e1dd6b4f30d2e8b2c1d10d382d3cacf3cd Signed-off-by: Aviral Gupta --- sound/soc/codecs/msm8x16-wcd.c | 101 ++++++++++++++++++++++++++------- sound/soc/codecs/msm8x16-wcd.h | 1 + sound/soc/msm/msm8x16.c | 30 ++++++++-- 3 files changed, 108 insertions(+), 24 deletions(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index 444931687713..b1cfa77b0557 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -59,6 +59,7 @@ #define TOMBAK_CORE_1_SPMI_ADDR 0xf100 #define CODEC_DT_MAX_PROP_SIZE 40 +#define MSM8X16_DIGITAL_CODEC_REG_SIZE 0x400 #define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64 #define TOMBAK_MCLK_CLK_9P6MHZ 9600000 @@ -207,10 +208,11 @@ static int get_spmi_msm8x16_wcd_device_info(u16 *reg, return rtn; } -static int msm8x16_wcd_ahb_write_device(u16 reg, u8 *value, u32 bytes) +static int msm8x16_wcd_ahb_write_device(struct msm8x16_wcd *msm8x16_wcd, + u16 reg, u8 *value, u32 bytes) { u32 temp = ((u32)(*value)) & 0x000000FF; - u32 offset = (((u32)(reg)) ^ 0x00000200) & 0x00000FFF; + u16 offset = (reg ^ 0x0200) & 0x0FFF; bool q6_state = false; q6_state = q6core_is_adsp_ready(); @@ -220,14 +222,15 @@ static int msm8x16_wcd_ahb_write_device(u16 reg, u8 *value, u32 bytes) } else pr_debug("%s: DSP is ready %d\n", __func__, q6_state); - iowrite32(temp, ioremap(MSM8X16_DIGITAL_CODEC_BASE_ADDR + offset, 4)); + iowrite32(temp, msm8x16_wcd->dig_base + offset); return 0; } -static int msm8x16_wcd_ahb_read_device(u16 reg, u32 bytes, u8 *value) +static int msm8x16_wcd_ahb_read_device(struct msm8x16_wcd *msm8x16_wcd, + u16 reg, u32 bytes, u8 *value) { u32 temp; - u32 offset = (((u32)(reg)) ^ 0x00000200) & 0x00000FFF; + u16 offset = (reg ^ 0x0200) & 0x0FFF; bool q6_state = false; q6_state = q6core_is_adsp_ready(); @@ -237,8 +240,7 @@ static int msm8x16_wcd_ahb_read_device(u16 reg, u32 bytes, u8 *value) } else pr_debug("%s: DSP is ready %d\n", __func__, q6_state); - temp = ioread32(ioremap(MSM8X16_DIGITAL_CODEC_BASE_ADDR + - offset, 4)); + temp = ioread32(msm8x16_wcd->dig_base + offset); *value = (u8)temp; return 0; } @@ -343,12 +345,13 @@ static int __msm8x16_wcd_reg_read(struct snd_soc_codec *codec, pr_debug("%s: MCLK not enabled\n", __func__); atomic_set(&pdata->dis_work_mclk, true); schedule_delayed_work(&pdata->enable_mclk_work, 50); - ret = msm8x16_wcd_ahb_read_device(reg, 1, &temp); + ret = msm8x16_wcd_ahb_read_device( + msm8x16_wcd, reg, 1, &temp); mutex_unlock(&pdata->cdc_mclk_mutex); mutex_unlock(&msm8x16_wcd->io_lock); return temp; } - ret = msm8x16_wcd_ahb_read_device(reg, 1, &temp); + ret = msm8x16_wcd_ahb_read_device(msm8x16_wcd, reg, 1, &temp); } mutex_unlock(&msm8x16_wcd->io_lock); @@ -392,12 +395,13 @@ static int __msm8x16_wcd_reg_write(struct snd_soc_codec *codec, } atomic_set(&pdata->dis_work_mclk, true); schedule_delayed_work(&pdata->enable_mclk_work, 50); - ret = msm8x16_wcd_ahb_write_device(reg, &val, 1); + ret = msm8x16_wcd_ahb_write_device( + msm8x16_wcd, reg, &val, 1); mutex_unlock(&pdata->cdc_mclk_mutex); mutex_unlock(&msm8x16_wcd->io_lock); return ret; } - ret = msm8x16_wcd_ahb_write_device(reg, &val, 1); + ret = msm8x16_wcd_ahb_write_device(msm8x16_wcd, reg, &val, 1); } mutex_unlock(&msm8x16_wcd->io_lock); @@ -2932,6 +2936,13 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) /* codec resmgr module init */ msm8x16_wcd = codec->control_data; + msm8x16_wcd->dig_base = ioremap(MSM8X16_DIGITAL_CODEC_BASE_ADDR, + MSM8X16_DIGITAL_CODEC_REG_SIZE); + if (msm8x16_wcd->dig_base == NULL) { + dev_err(codec->dev, "%s ioremap failed", __func__); + kfree(msm8x16_wcd_priv); + return -ENOMEM; + } msm8x16_wcd_bringup(codec); msm8x16_wcd_codec_init_reg(codec); msm8x16_wcd_update_reg_defaults(codec); @@ -2957,6 +2968,8 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) if (!modem_state_notifier) { dev_err(codec->dev, "Failed to register modem state notifier\n" ); + iounmap(msm8x16_wcd->dig_base); + kfree(msm8x16_wcd_priv); registered_codec = NULL; return -ENOMEM; } @@ -2965,10 +2978,14 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) static int msm8x16_wcd_codec_remove(struct snd_soc_codec *codec) { - struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + struct msm8x16_wcd *msm8x16_wcd; - msm8x16_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL; - atomic_set(&msm8x16_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0); + msm8x16_wcd = codec->control_data; + msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL; + atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0); + iounmap(msm8x16_wcd->dig_base); return 0; } @@ -3118,15 +3135,59 @@ static void msm8x16_wcd_disable_supplies(struct msm8x16_wcd *msm8x16, static int msm8x16_wcd_clk_init(void) { + void __iomem *vaddr = NULL; + /* Div-2 */ - iowrite32(0x3, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CFG_RCGR, 4)); - iowrite32(0x0, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_M, 4)); - iowrite32(0x0, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_N, 4)); - iowrite32(0x0, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_D, 4)); + vaddr = ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CFG_RCGR, 4); + if (vaddr == NULL) { + pr_err("%s: ioremap failed for %x\n", + __func__, MSM8X16_TOMBAK_LPASS_DIGCODEC_CFG_RCGR); + return -ENOMEM; + } + iowrite32(0x3, vaddr); + iounmap(vaddr); + vaddr = ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_M, 4); + if (vaddr == NULL) { + pr_err("%s: ioremap failed for %x\n", + __func__, MSM8X16_TOMBAK_LPASS_DIGCODEC_M); + return -ENOMEM; + } + iowrite32(0x0, vaddr); + iounmap(vaddr); + vaddr = ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_N, 4); + if (vaddr == NULL) { + pr_err("%s: ioremap failed for %x\n", + __func__, MSM8X16_TOMBAK_LPASS_DIGCODEC_N); + return -ENOMEM; + } + iowrite32(0x0, vaddr); + iounmap(vaddr); + vaddr = ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_D, 4); + if (vaddr == NULL) { + pr_err("%s: ioremap failed for %x\n", + __func__, MSM8X16_TOMBAK_LPASS_DIGCODEC_D); + return -ENOMEM; + } + iowrite32(0x0, vaddr); + iounmap(vaddr); /* Digital codec clock enable */ - iowrite32(0x1, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR, 4)); + vaddr = ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR, 4); + if (vaddr == NULL) { + pr_err("%s: ioremap failed for %x\n", + __func__, MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR); + return -ENOMEM; + } + iowrite32(0x1, vaddr); + iounmap(vaddr); /* Set the update bit to make the settings go through */ - iowrite32(0x1, ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CMD_RCGR, 4)); + vaddr = ioremap(MSM8X16_TOMBAK_LPASS_DIGCODEC_CMD_RCGR, 4); + if (vaddr == NULL) { + pr_err("%s: ioremap failed for %x\n", + __func__, MSM8X16_TOMBAK_LPASS_DIGCODEC_CMD_RCGR); + return -ENOMEM; + } + iowrite32(0x1, vaddr); + iounmap(vaddr); usleep_range(100, 200); return 0; } diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h index a5188e82973e..2cbe641d2f9c 100644 --- a/sound/soc/codecs/msm8x16-wcd.h +++ b/sound/soc/codecs/msm8x16-wcd.h @@ -160,6 +160,7 @@ struct msm8x16_wcd { int num_irqs; u32 mclk_rate; + char __iomem *dig_base; }; extern int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index 054117ddec3c..85a32875809a 100644 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -387,6 +387,7 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) struct msm8916_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); int ret = 0; int val = 0; + void __iomem *vaddr = NULL; pr_debug("%s(): substream = %s stream = %d\n", __func__, substream->name, substream->stream); @@ -396,12 +397,33 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) * slave select to invalid state, for machine mode this * should move to HW, I do not like to do it here */ - val = ioread32(ioremap(LPASS_CSR_GP_IO_MUX_SPKR_CTL , 4)); + vaddr = ioremap(LPASS_CSR_GP_IO_MUX_SPKR_CTL , 4); + if (!vaddr) { + pr_err("%s ioremap failure for addr %x", + __func__, LPASS_CSR_GP_IO_MUX_SPKR_CTL); + return -ENOMEM; + } + val = ioread32(vaddr); val = val | 0x00030300; - iowrite32(val, ioremap(LPASS_CSR_GP_IO_MUX_SPKR_CTL , 4)); - val = ioread32(ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4)); + iowrite32(val, vaddr); + iounmap(vaddr); + vaddr = ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4); + if (!vaddr) { + pr_err("%s ioremap failure for addr %x", + __func__, LPASS_CSR_GP_IO_MUX_MIC_CTL); + return -ENOMEM; + } + val = ioread32(vaddr); + iounmap(vaddr); val = val | 0x00200000; - iowrite32(val, ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4)); + vaddr = ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4); + if (!vaddr) { + pr_err("%s ioremap failure for addr %x", + __func__, LPASS_CSR_GP_IO_MUX_MIC_CTL); + return -ENOMEM; + } + iowrite32(val, vaddr); + iounmap(vaddr); } ret = msm8x16_enable_codec_ext_clk(codec, 1, true); if (ret < 0) {