Commit 2c63bea7 authored by Kai Vehmanen's avatar Kai Vehmanen Committed by Mark Brown

ASoC: SOF: Intel: fix HDA codec driver probe with multiple controllers

In case system has multiple HDA controllers, it can happen that
same HDA codec driver is used for codecs of multiple controllers.
In this case, SOF may fail to probe the HDA driver and SOF
initialization fails.

SOF HDA code currently relies that a call to request_module() will
also run device matching logic to attach driver to the codec instance.
However if driver for another HDA controller was already loaded and it
already loaded the HDA codec driver, this breaks current logic in SOF.
In this case the request_module() SOF does becomes a no-op and HDA
Codec driver is not attached to the codec instance sitting on the HDA
bus SOF is controlling. Typical scenario would be a system with both
external and internal GPUs, with driver of the external GPU loaded
first.

Fix this by adding similar logic as is used in legacy HDA driver
where an explicit device_attach() call is done after request_module().

Also add logic to propagate errors reported by device_attach() back
to caller. This also works in the case where drivers are not built
as modules.
Signed-off-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20200110235751.3404-8-pierre-louis.bossart@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent ceca2197
...@@ -24,19 +24,18 @@ ...@@ -24,19 +24,18 @@
#define IDISP_VID_INTEL 0x80860000 #define IDISP_VID_INTEL 0x80860000
/* load the legacy HDA codec driver */ /* load the legacy HDA codec driver */
#ifdef MODULE static int hda_codec_load_module(struct hda_codec *codec)
static void hda_codec_load_module(struct hda_codec *codec)
{ {
#ifdef MODULE
char alias[MODULE_NAME_LEN]; char alias[MODULE_NAME_LEN];
const char *module = alias; const char *module = alias;
snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias)); snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias));
dev_dbg(&codec->core.dev, "loading codec module: %s\n", module); dev_dbg(&codec->core.dev, "loading codec module: %s\n", module);
request_module(module); request_module(module);
}
#else
static void hda_codec_load_module(struct hda_codec *codec) {}
#endif #endif
return device_attach(hda_codec_dev(codec));
}
/* enable controller wake up event for all codecs with jack connectors */ /* enable controller wake up event for all codecs with jack connectors */
void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev)
...@@ -129,10 +128,16 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) ...@@ -129,10 +128,16 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
if ((mach_params && mach_params->common_hdmi_codec_drv) || if ((mach_params && mach_params->common_hdmi_codec_drv) ||
(resp & 0xFFFF0000) != IDISP_VID_INTEL) { (resp & 0xFFFF0000) != IDISP_VID_INTEL) {
hdev->type = HDA_DEV_LEGACY; hdev->type = HDA_DEV_LEGACY;
hda_codec_load_module(&hda_priv->codec); ret = hda_codec_load_module(&hda_priv->codec);
/*
* handle ret==0 (no driver bound) as an error, but pass
* other return codes without modification
*/
if (ret == 0)
ret = -ENOENT;
} }
return 0; return ret;
#else #else
hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL);
if (!hdev) if (!hdev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment