Skip to content

Commit 9a20e57

Browse files
plbossartgregkh
authored andcommitted
ALSA: hda: intel-nhlt: verify config type
[ Upstream commit a864e8f ] Multiple bug reports report issues with the SOF and SST drivers when dealing with single microphone cases. We currently read the DMIC array information unconditionally but we don't check that the configuration type is actually a mic array. When the DMIC link does not rely on a mic array configuration, the recommendation is to check the format information to infer the maximum number of channels, and map this to the number of microphones. This leaves a potential for a mismatch between actual microphones available in hardware and what the ACPI table contains, but we have no other source of information. Note that single microphone configurations can alternatively be handled with a 'mic array' configuration along with a 'vendor-defined' geometry. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=201251 BugLink: thesofproject/linux#2725 Fixes: 7a33ea7 ('ALSA: hda: intel-nhlt: handle NHLT VENDOR_DEFINED DMIC geometry') Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Link: https://lore.kernel.org/r/20210302000146.1177770-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 86b3b62 commit 9a20e57

2 files changed

Lines changed: 50 additions & 9 deletions

File tree

include/sound/intel-nhlt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ struct nhlt_vendor_dmic_array_config {
112112
/* TODO add vendor mic config */
113113
} __packed;
114114

115+
enum {
116+
NHLT_CONFIG_TYPE_GENERIC = 0,
117+
NHLT_CONFIG_TYPE_MIC_ARRAY = 1
118+
};
119+
115120
enum {
116121
NHLT_MIC_ARRAY_2CH_SMALL = 0xa,
117122
NHLT_MIC_ARRAY_2CH_BIG = 0xb,

sound/hda/intel-nhlt.c

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,44 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
6464
struct nhlt_endpoint *epnt;
6565
struct nhlt_dmic_array_config *cfg;
6666
struct nhlt_vendor_dmic_array_config *cfg_vendor;
67+
struct nhlt_fmt *fmt_configs;
6768
unsigned int dmic_geo = 0;
68-
u8 j;
69+
u16 max_ch = 0;
70+
u8 i, j;
6971

7072
if (!nhlt)
7173
return 0;
7274

73-
epnt = (struct nhlt_endpoint *)nhlt->desc;
75+
for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++,
76+
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) {
7477

75-
for (j = 0; j < nhlt->endpoint_count; j++) {
76-
if (epnt->linktype == NHLT_LINK_DMIC) {
77-
cfg = (struct nhlt_dmic_array_config *)
78-
(epnt->config.caps);
78+
if (epnt->linktype != NHLT_LINK_DMIC)
79+
continue;
80+
81+
cfg = (struct nhlt_dmic_array_config *)(epnt->config.caps);
82+
fmt_configs = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
83+
84+
/* find max number of channels based on format_configuration */
85+
if (fmt_configs->fmt_count) {
86+
dev_dbg(dev, "%s: found %d format definitions\n",
87+
__func__, fmt_configs->fmt_count);
88+
89+
for (i = 0; i < fmt_configs->fmt_count; i++) {
90+
struct wav_fmt_ext *fmt_ext;
91+
92+
fmt_ext = &fmt_configs->fmt_config[i].fmt_ext;
93+
94+
if (fmt_ext->fmt.channels > max_ch)
95+
max_ch = fmt_ext->fmt.channels;
96+
}
97+
dev_dbg(dev, "%s: max channels found %d\n", __func__, max_ch);
98+
} else {
99+
dev_dbg(dev, "%s: No format information found\n", __func__);
100+
}
101+
102+
if (cfg->device_config.config_type != NHLT_CONFIG_TYPE_MIC_ARRAY) {
103+
dmic_geo = max_ch;
104+
} else {
79105
switch (cfg->array_type) {
80106
case NHLT_MIC_ARRAY_2CH_SMALL:
81107
case NHLT_MIC_ARRAY_2CH_BIG:
@@ -92,13 +118,23 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
92118
dmic_geo = cfg_vendor->nb_mics;
93119
break;
94120
default:
95-
dev_warn(dev, "undefined DMIC array_type 0x%0x\n",
96-
cfg->array_type);
121+
dev_warn(dev, "%s: undefined DMIC array_type 0x%0x\n",
122+
__func__, cfg->array_type);
123+
}
124+
125+
if (dmic_geo > 0) {
126+
dev_dbg(dev, "%s: Array with %d dmics\n", __func__, dmic_geo);
127+
}
128+
if (max_ch > dmic_geo) {
129+
dev_dbg(dev, "%s: max channels %d exceed dmic number %d\n",
130+
__func__, max_ch, dmic_geo);
97131
}
98132
}
99-
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
100133
}
101134

135+
dev_dbg(dev, "%s: dmic number %d max_ch %d\n",
136+
__func__, dmic_geo, max_ch);
137+
102138
return dmic_geo;
103139
}
104140
EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo);

0 commit comments

Comments
 (0)