diff options
| author | Kai Vehmanen <kai.vehmanen@linux.intel.com> | 2020-09-21 17:17:40 +0300 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2020-09-21 17:57:30 +0200 | 
| commit | 7b882fe3e3e8bfd6427bf61780e59d5bed6699b4 (patch) | |
| tree | a3b13e91c615d5bb368b513b450fd03419fa2c70 | |
| parent | 1bee263dfda57e45ad39c59a663c123a357ce38b (diff) | |
ALSA: hda - handle multiple i915 device instances
Currently i915_component_master_match() will return the first matching
i915 instance. This does not work in case system has multiple i915
and HDA audio controller instances.
Add a new connectivity check that handles following cases:
 - i915 and HDA controller on same PCI bus
 - discrete GPU with embedded HDA audio controller connected
   via PCI bridge
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200921141741.2983072-4-kai.vehmanen@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/hda/hdac_i915.c | 44 | 
1 files changed, 42 insertions, 2 deletions
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 3c2db3816029..50b2c1db429b 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -73,11 +73,51 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)  }  EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); +/** + * Returns true if the devices can be connected for audio. + */ +static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) +{ +	struct pci_bus *bus_a = i915->bus, *bus_b = hdac->bus; + +	/* directly connected on the same bus */ +	if (bus_a == bus_b) +		return true; + +	/* +	 * on i915 discrete GPUs with embedded HDA audio, the two +	 * devices are connected via 2nd level PCI bridge +	 */ +	bus_a = bus_a->parent; +	bus_b = bus_b->parent; +	if (!bus_a || !bus_b) +		return false; +	bus_a = bus_a->parent; +	bus_b = bus_b->parent; +	if (bus_a && bus_a == bus_b) +		return true; + +	return false; +} +  static int i915_component_master_match(struct device *dev, int subcomponent,  				       void *data)  { -	return !strcmp(dev->driver->name, "i915") && -	       subcomponent == I915_COMPONENT_AUDIO; +	struct pci_dev *hdac_pci, *i915_pci; +	struct hdac_bus *bus = data; + +	if (!dev_is_pci(dev)) +		return 0; + +	hdac_pci = to_pci_dev(bus->dev); +	i915_pci = to_pci_dev(dev); + +	if (!strcmp(dev->driver->name, "i915") && +	    subcomponent == I915_COMPONENT_AUDIO && +	    connectivity_check(i915_pci, hdac_pci)) +		return 1; + +	return 0;  }  /* check whether intel graphics is present */  | 
