Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASoC: SOF: Intel: prepare i915 deferred probe #4645

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4b90ba9
Revert "ALSA: hda: hdac-i915: fix i915 timeout variable to msec"
plbossart Oct 19, 2023
6d6ad90
Revert "ALSA: hda: hdac-i915: make i915 timeout configurable"
plbossart Oct 19, 2023
93067d4
Revert "ASoC: SOF: Intel: Use consistent name for struct sof_intel_hd…
plbossart Oct 19, 2023
e4c7ae0
ASoC: SOF: core: Ensure sof_ops_free() is still called when probe nev…
mlankhorst Oct 9, 2023
fc4ae5a
ASoC: SOF: core: Add probe_early and remove_late callbacks
plbossart Oct 9, 2023
d50c380
ASoC: SOF: Intel: hda: start splitting the probe
plbossart Oct 9, 2023
accbe06
ASoC: SOF: Intel: Fix error handling in hda_init()
mlankhorst Oct 9, 2023
5fe0f71
ALSA: hda: Intel: Fix error handling in azx_probe()
mlankhorst Oct 9, 2023
663c94d
ALSA: hda: i915: Allow override of gpu binding.
mlankhorst Oct 9, 2023
33f10e2
ALSA: hda: i915: Add an allow_modprobe argument to snd_hdac_i915_init
mlankhorst Oct 9, 2023
9b56295
ALSA: hda: i915: Allow xe as match for i915_component_master_match
mlankhorst Oct 9, 2023
409c175
ASoC: Intel: avs: Move snd_hdac_i915_init to before probe_work.
mlankhorst Oct 9, 2023
06a74c4
ALSA: hda: Intel: Move snd_hdac_i915_init to before probe_work.
mlankhorst Oct 9, 2023
4dc0413
ASoC: Intel: Skylake: Move snd_hdac_i915_init to before probe_work.
mlankhorst Oct 9, 2023
e6d1a17
ASoC: SOF: Intel: Move binding to display driver outside of deferred …
mlankhorst Oct 19, 2023
b87a398
ALSA: hda: i915: Remove extra argument from snd_hdac_i915_init
mlankhorst Oct 9, 2023
4bb0e68
ASoC: SOF: Intel: make remove_late return void
plbossart Oct 19, 2023
20306e6
[NOT FOR UPSTREAM] ALSA: hdac_i915: add helper to disable GPU bind
plbossart Oct 19, 2023
9d95961
[NOT FOR UPSTREAM] ASoC: SOF: Intel: mtl: temporarily disable GPU bind
plbossart Oct 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/sound/hda_i915.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#ifdef CONFIG_SND_HDA_I915
void snd_hdac_i915_set_bclk(struct hdac_bus *bus);
int snd_hdac_i915_init(struct hdac_bus *bus);
void snd_hdac_i915_bind(struct hdac_bus *bus, int i915_bind);
#else
static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
{
Expand All @@ -18,6 +19,9 @@ static inline int snd_hdac_i915_init(struct hdac_bus *bus)
{
return -ENODEV;
}
static inline void snd_hdac_i915_bind(struct hdac_bus *bus, int i915_bind)
{
}
#endif
static inline int snd_hdac_i915_exit(struct hdac_bus *bus)
{
Expand Down
38 changes: 25 additions & 13 deletions sound/hda/hdac_i915.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include <sound/hda_register.h>
#include <video/nomodeset.h>

static int hdac_i915_timeout_ms = 60000;
module_param(hdac_i915_timeout_ms, int, 0444);
MODULE_PARM_DESC(hdac_i915_timeout_ms, "i915 initialization timeout in msec");
static int gpu_bind = -1;
module_param(gpu_bind, int, 0644);
MODULE_PARM_DESC(gpu_bind, "Whether to bind sound component to GPU "
"(1=always, 0=never, -1=on nomodeset(default))");

/**
* snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW
Expand Down Expand Up @@ -113,7 +115,8 @@ static int i915_component_master_match(struct device *dev, int subcomponent,
hdac_pci = to_pci_dev(bus->dev);
i915_pci = to_pci_dev(dev);

if (!strcmp(dev->driver->name, "i915") &&
if ((!strcmp(dev->driver->name, "i915") ||
!strcmp(dev->driver->name, "xe")) &&
subcomponent == I915_COMPONENT_AUDIO &&
connectivity_check(i915_pci, hdac_pci))
return 1;
Expand All @@ -126,6 +129,9 @@ static int i915_gfx_present(struct pci_dev *hdac_pci)
{
struct pci_dev *display_dev = NULL;

if (!gpu_bind || (gpu_bind < 0 && video_firmware_drivers_only()))
return false;

for_each_pci_dev(display_dev) {
if (display_dev->vendor == PCI_VENDOR_ID_INTEL &&
(display_dev->class >> 16) == PCI_BASE_CLASS_DISPLAY &&
Expand All @@ -138,6 +144,19 @@ static int i915_gfx_present(struct pci_dev *hdac_pci)
return false;
}

/**
* snd_hdac_i915_bind - override i915 audio component bind options
* @bus: HDA core bus
* @i915_bind: bind options between sound component and GPU
* 1=always, 0=never, -1=on nomodeset(default))
*/

void snd_hdac_i915_bind(struct hdac_bus *bus, int i915_bind)
{
gpu_bind = i915_bind;
}
EXPORT_SYMBOL_GPL(snd_hdac_i915_bind);

/**
* snd_hdac_i915_init - Initialize i915 audio component
* @bus: HDA core bus
Expand Down Expand Up @@ -167,16 +186,9 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
if (!acomp)
return -ENODEV;
if (!acomp->ops) {
if (!IS_ENABLED(CONFIG_MODULES) ||
!request_module("i915")) {
wait_for_completion_killable_timeout(&acomp->master_bind_complete,
msecs_to_jiffies(hdac_i915_timeout_ms));
}
}
if (!acomp->ops) {
dev_info(bus->dev, "couldn't bind with audio component\n");
snd_hdac_acomp_exit(bus);
return -ENODEV;
return dev_err_probe(bus->dev, -EPROBE_DEFER,
"couldn't bind with audio component\n");
}
return 0;
}
Expand Down
60 changes: 31 additions & 29 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -2135,6 +2135,36 @@ static int azx_probe(struct pci_dev *pci,

pci_set_drvdata(pci, card);

#ifdef CONFIG_SND_HDA_I915
/* bind with i915 if needed */
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) {
err = snd_hdac_i915_init(azx_bus(chip));
if (err < 0) {
/* if the controller is bound only with HDMI/DP
* (for HSW and BDW), we need to abort the probe;
* for other chips, still continue probing as other
* codecs can be on the same link.
*/
if (HDA_CONTROLLER_IN_GPU(pci)) {
dev_err_probe(card->dev, err,
"HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n");

goto out_free;
} else {
/* don't bother any longer */
chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
}
}

/* HSW/BDW controllers need this power */
if (HDA_CONTROLLER_IN_GPU(pci))
hda->need_i915_power = true;
}
#else
if (HDA_CONTROLLER_IN_GPU(pci))
dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
#endif

err = register_vga_switcheroo(chip);
if (err < 0) {
dev_err(card->dev, "Error registering vga_switcheroo client\n");
Expand Down Expand Up @@ -2162,11 +2192,6 @@ static int azx_probe(struct pci_dev *pci,
}
#endif /* CONFIG_SND_HDA_PATCH_LOADER */

#ifndef CONFIG_SND_HDA_I915
if (HDA_CONTROLLER_IN_GPU(pci))
dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
#endif

if (schedule_probe)
schedule_delayed_work(&hda->probe_work, 0);

Expand All @@ -2176,6 +2201,7 @@ static int azx_probe(struct pci_dev *pci,
return 0;

out_free:
pci_set_drvdata(pci, NULL);
snd_card_free(card);
return err;
}
Expand Down Expand Up @@ -2263,30 +2289,6 @@ static int azx_probe_continue(struct azx *chip)
to_hda_bus(bus)->bus_probing = 1;
hda->probe_continued = 1;

/* bind with i915 if needed */
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) {
err = snd_hdac_i915_init(bus);
if (err < 0) {
/* if the controller is bound only with HDMI/DP
* (for HSW and BDW), we need to abort the probe;
* for other chips, still continue probing as other
* codecs can be on the same link.
*/
if (HDA_CONTROLLER_IN_GPU(pci)) {
dev_err(chip->card->dev,
"HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n");
goto out_free;
} else {
/* don't bother any longer */
chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
}
}

/* HSW/BDW controllers need this power */
if (HDA_CONTROLLER_IN_GPU(pci))
hda->need_i915_power = true;
}

/* Request display power well for the HDA controller or codec. For
* Haswell/Broadwell, both the display HDA controller and codec need
* this power. For other platforms, like Baytrail/Braswell, only the
Expand Down
13 changes: 9 additions & 4 deletions sound/soc/intel/avs/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,6 @@ static void avs_hda_probe_work(struct work_struct *work)

pm_runtime_set_active(bus->dev); /* clear runtime_error flag */

ret = snd_hdac_i915_init(bus);
if (ret < 0)
dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret);

snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
avs_hdac_bus_init_chip(bus, true);
avs_hdac_bus_probe_codecs(bus);
Expand Down Expand Up @@ -470,10 +466,19 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
pci_set_drvdata(pci, bus);
device_disable_async_suspend(dev);

ret = snd_hdac_i915_init(bus);
if (ret == -EPROBE_DEFER)
goto err_i915_init;
else if (ret < 0)
dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret);

schedule_work(&adev->probe_work);

return 0;

err_i915_init:
pci_clear_master(pci);
pci_set_drvdata(pci, NULL);
err_acquire_irq:
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
Expand Down
31 changes: 9 additions & 22 deletions sound/soc/intel/skylake/skl.c
Original file line number Diff line number Diff line change
Expand Up @@ -784,35 +784,15 @@ static void skl_codec_create(struct hdac_bus *bus)
}
}

static int skl_i915_init(struct hdac_bus *bus)
{
int err;

/*
* The HDMI codec is in GPU so we need to ensure that it is powered
* up and ready for probe
*/
err = snd_hdac_i915_init(bus);
if (err < 0)
return err;

snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);

return 0;
}

static void skl_probe_work(struct work_struct *work)
{
struct skl_dev *skl = container_of(work, struct skl_dev, probe_work);
struct hdac_bus *bus = skl_to_bus(skl);
struct hdac_ext_link *hlink;
int err;

if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
err = skl_i915_init(bus);
if (err < 0)
return;
}
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);

skl_init_pci(skl);
skl_dum_set(bus);
Expand Down Expand Up @@ -1076,10 +1056,17 @@ static int skl_probe(struct pci_dev *pci,
goto out_dsp_free;
}

if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
err = snd_hdac_i915_init(bus);
if (err < 0)
goto out_dmic_unregister;
}
schedule_work(&skl->probe_work);

return 0;

out_dmic_unregister:
skl_dmic_device_unregister(skl);
out_dsp_free:
skl_free_dsp(skl);
out_clk_free:
Expand Down
17 changes: 16 additions & 1 deletion sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
dsp_err:
snd_sof_remove(sdev);
probe_err:
snd_sof_remove_late(sdev);
sof_ops_free(sdev);

/* all resources freed, update state to match */
Expand Down Expand Up @@ -436,6 +437,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)

sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);

/*
* first pass of probe which isn't allowed to run in a work-queue,
* typically to rely on -EPROBE_DEFER dependencies
*/
ret = snd_sof_probe_early(sdev);
if (ret < 0)
return ret;

if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
INIT_WORK(&sdev->probe_work, sof_probe_work);
schedule_work(&sdev->probe_work);
Expand All @@ -459,9 +468,10 @@ int snd_sof_device_remove(struct device *dev)
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_pdata *pdata = sdev->pdata;
int ret;
bool aborted = false;

if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
cancel_work_sync(&sdev->probe_work);
aborted = cancel_work_sync(&sdev->probe_work);

/*
* Unregister any registered client device first before IPC and debugfs
Expand All @@ -486,6 +496,11 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_ipc_free(sdev);
snd_sof_free_debug(sdev);
snd_sof_remove(sdev);
snd_sof_remove_late(sdev);
sof_ops_free(sdev);
} else if (aborted) {
/* probe_work never ran */
snd_sof_remove_late(sdev);
sof_ops_free(sdev);
}

Expand Down
18 changes: 9 additions & 9 deletions sound/soc/sof/intel/cnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");

if (ack_received) {
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;

if (hda->delayed_ipc_tx_msg)
cnl_ipc4_send_msg(sdev, hda->delayed_ipc_tx_msg);
if (hdev->delayed_ipc_tx_msg)
cnl_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg);
}

return IRQ_HANDLED;
Expand Down Expand Up @@ -261,15 +261,15 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg,

int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;

if (hda_ipc4_tx_is_busy(sdev)) {
hda->delayed_ipc_tx_msg = msg;
hdev->delayed_ipc_tx_msg = msg;
return 0;
}

hda->delayed_ipc_tx_msg = NULL;
hdev->delayed_ipc_tx_msg = NULL;

/* send the message via mailbox */
if (msg_data->data_size)
Expand All @@ -280,14 +280,14 @@ int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR,
msg_data->primary | CNL_DSP_REG_HIPCIDR_BUSY);

hda_dsp_ipc4_schedule_d0i3_work(hda, msg);
hda_dsp_ipc4_schedule_d0i3_work(hdev, msg);

return 0;
}

int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc_cmd_hdr *hdr;
u32 dr = 0;
u32 dd = 0;
Expand Down Expand Up @@ -326,7 +326,7 @@ int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
* CTX_SAVE IPC, which is sent before the DSP enters D3.
*/
if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE))
mod_delayed_work(system_wq, &hda->d0i3_work,
mod_delayed_work(system_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));

return 0;
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/intel/hda-common-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

struct snd_sof_dsp_ops sof_hda_common_ops = {
/* probe/remove/shutdown */
.probe_early = hda_dsp_probe_early,
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
.remove_late = hda_dsp_remove_late,

/* Register IO uses direct mmio */

Expand Down
7 changes: 4 additions & 3 deletions sound/soc/sof/intel/hda-dsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1040,9 +1040,10 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)

void hda_dsp_d0i3_work(struct work_struct *work)
{
struct sof_intel_hda_dev *hda = container_of(work, struct sof_intel_hda_dev,
d0i3_work.work);
struct hdac_bus *bus = &hda->hbus.core;
struct sof_intel_hda_dev *hdev = container_of(work,
struct sof_intel_hda_dev,
d0i3_work.work);
struct hdac_bus *bus = &hdev->hbus.core;
struct snd_sof_dev *sdev = dev_get_drvdata(bus->dev);
struct sof_dsp_power_state target_state = {
.state = SOF_DSP_PM_D0,
Expand Down
Loading