lkml.org 
[lkml]   [2022]   [Oct]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 6.0 734/862] ALSA: hda: Fix page fault in snd_hda_codec_shutdown()
    Date
    From: Cezary Rojewski <cezary.rojewski@intel.com>

    [ Upstream commit f2bd1c5ae2cb0cf9525c9bffc0038c12dd7e1338 ]

    If early probe of HDAudio bus driver fails e.g.: due to missing
    firmware file, snd_hda_codec_shutdown() ends in manipulating
    uninitialized codec->pcm_list_head causing page fault.

    Initialization of HDAudio codec in ASoC is split in two:
    - snd_hda_codec_device_init()
    - snd_hda_codec_device_new()

    snd_hda_codec_device_init() is called during probe_codecs() by HDAudio
    bus driver while snd_hda_codec_device_new() is called by
    codec-component's ->probe(). The second call will not happen until all
    components required by related sound card are present within the ASoC
    framework. With firmware failing to load during the PCI's deferred
    initialization i.e.: probe_work(), no platform components are ever
    registered. HDAudio codec enumeration is done at that point though, so
    the codec components became registered to ASoC framework, calling
    snd_hda_codec_device_init() in the process.

    Now, during platform reboot snd_hda_codec_shutdown() is called for every
    codec found on the HDAudio bus causing oops if any of them has not
    completed both of their initialization steps. Relocating field
    initialization fixes the issue.

    Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
    Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
    Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
    Link: https://lore.kernel.org/r/20220816111727.3218543-7-cezary.rojewski@intel.com
    Signed-off-by: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    sound/pci/hda/hda_codec.c | 41 +++++++++++++++++++--------------------
    1 file changed, 20 insertions(+), 21 deletions(-)

    diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
    index 384426d7e9dd..4ae8b9574778 100644
    --- a/sound/pci/hda/hda_codec.c
    +++ b/sound/pci/hda/hda_codec.c
    @@ -931,8 +931,28 @@ snd_hda_codec_device_init(struct hda_bus *bus, unsigned int codec_addr,
    }

    codec->bus = bus;
    + codec->depop_delay = -1;
    + codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
    + codec->core.dev.release = snd_hda_codec_dev_release;
    + codec->core.exec_verb = codec_exec_verb;
    codec->core.type = HDA_DEV_LEGACY;

    + mutex_init(&codec->spdif_mutex);
    + mutex_init(&codec->control_mutex);
    + snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
    + snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
    + snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
    + snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
    + snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
    + snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
    + snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
    + snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8);
    + INIT_LIST_HEAD(&codec->conn_list);
    + INIT_LIST_HEAD(&codec->pcm_list_head);
    + INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
    + refcount_set(&codec->pcm_ref, 1);
    + init_waitqueue_head(&codec->remove_sleep);
    +
    return codec;
    }
    EXPORT_SYMBOL_GPL(snd_hda_codec_device_init);
    @@ -985,29 +1005,8 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
    if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
    return -EINVAL;

    - codec->core.dev.release = snd_hda_codec_dev_release;
    - codec->core.exec_verb = codec_exec_verb;
    -
    codec->card = card;
    codec->addr = codec_addr;
    - mutex_init(&codec->spdif_mutex);
    - mutex_init(&codec->control_mutex);
    - snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
    - snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
    - snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
    - snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
    - snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
    - snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
    - snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
    - snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8);
    - INIT_LIST_HEAD(&codec->conn_list);
    - INIT_LIST_HEAD(&codec->pcm_list_head);
    - refcount_set(&codec->pcm_ref, 1);
    - init_waitqueue_head(&codec->remove_sleep);
    -
    - INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
    - codec->depop_delay = -1;
    - codec->fixup_id = HDA_FIXUP_ID_NOT_SET;

    #ifdef CONFIG_PM
    codec->power_jiffies = jiffies;
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-10-19 14:07    [W:2.381 / U:0.316 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site