[alsa-devel] [PATCH v4 0/6] sanitize hda/i915 interface using the component fw
This is v4 of [1] addressing the review comments from Takashi and Jani.
[1] http://lists.freedesktop.org/archives/intel-gfx/2014-December/056992.html
Imre Deak (6): drm/i915: add dev_to_i915 helper drm/i915: add component support ALSA: hda: export struct hda_intel ALSA: hda: pass intel_hda to all i915 interface functions ALSA: hda: add component support drm/i915: remove unused power_well/get_cdclk_freq api
drivers/gpu/drm/i915/i915_dma.c | 4 + drivers/gpu/drm/i915/i915_drv.c | 9 +- drivers/gpu/drm/i915/i915_drv.h | 8 ++ drivers/gpu/drm/i915/intel_audio.c | 110 +++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_runtime_pm.c | 56 ------------ include/drm/i915_component.h | 38 ++++++++ include/drm/i915_powerwell.h | 37 -------- sound/pci/hda/hda_i915.c | 152 ++++++++++++++++++++++---------- sound/pci/hda/hda_i915.h | 37 -------- sound/pci/hda/hda_intel.c | 60 ++++--------- sound/pci/hda/hda_intel.h | 71 +++++++++++++++ 12 files changed, 360 insertions(+), 224 deletions(-) create mode 100644 include/drm/i915_component.h delete mode 100644 include/drm/i915_powerwell.h delete mode 100644 sound/pci/hda/hda_i915.h create mode 100644 sound/pci/hda/hda_intel.h
This will be needed by later patches, so factor it out.
No functional change.
v2: - s/dev_to_i915_priv/dev_to_i915/ (Jani) - don't use the helper in i915_pm_suspend (Chris) - simplify the helper (Chris) v3: - remove redundant upcasting in the helper (Daniel)
Signed-off-by: Imre Deak imre.deak@intel.com Reviewed-by: Takashi Iwai tiwai@suse.de --- drivers/gpu/drm/i915/i915_drv.c | 9 +++------ drivers/gpu/drm/i915/i915_drv.h | 5 +++++ 2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 574057c..cbbd23f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -940,8 +940,7 @@ static int i915_pm_suspend(struct device *dev)
static int i915_pm_suspend_late(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev;
/* * We have a suspedn ordering issue with the snd-hda driver also @@ -960,8 +959,7 @@ static int i915_pm_suspend_late(struct device *dev)
static int i915_pm_resume_early(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -971,8 +969,7 @@ static int i915_pm_resume_early(struct device *dev)
static int i915_pm_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 70d0f0f..99eddad 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1783,6 +1783,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev) return dev->dev_private; }
+static inline struct drm_i915_private *dev_to_i915(struct device *dev) +{ + return to_i915(dev_get_drvdata(dev)); +} + /* Iterate over initialised rings */ #define for_each_ring(ring__, dev_priv__, i__) \ for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
Register a component to be used to interface with the snd_hda_intel driver. This is meant to replace the same interface that is currently based on module symbol lookup.
v2: - change roles between the hda and i915 components (Daniel) - add the implementation to a new file (Jani) - use better namespacing (Jani) v3: - move the implementation to intel_audio.c (Daniel) - rename display_component to audio_component (Daniel) - add kerneldoc (Daniel) v4: - run forgotten git rm i915_component.c (Jani)
Signed-off-by: Imre Deak imre.deak@intel.com Reviewed-by: Takashi Iwai tiwai@suse.de --- drivers/gpu/drm/i915/i915_dma.c | 4 ++ drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/intel_audio.c | 110 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 + include/drm/i915_component.h | 38 +++++++++++++ 5 files changed, 157 insertions(+) create mode 100644 include/drm/i915_component.h
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ecee3bc..26b3199 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_runtime_pm_enable(dev_priv);
+ i915_audio_component_init(dev_priv); + return 0;
out_power_well: @@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret;
+ i915_audio_component_cleanup(dev_priv); + ret = i915_gem_suspend(dev); if (ret) { DRM_ERROR("failed to idle hardware: %d\n", ret); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 99eddad..af01412 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1698,6 +1698,9 @@ struct drm_i915_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property;
+ /* hda/i915 audio component */ + bool audio_component_registered; + uint32_t hw_context_size; struct list_head context_list;
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 2c7ed5c..ee41b88 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -22,6 +22,9 @@ */
#include <linux/kernel.h> +#include <linux/component.h> +#include <drm/i915_component.h> +#include "intel_drv.h"
#include <drm/drmP.h> #include <drm/drm_edid.h> @@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev) dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; } } + +static void i915_audio_component_get_power(struct device *dev) +{ + intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +static void i915_audio_component_put_power(struct device *dev) +{ + intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +/* Get CDCLK in kHz */ +static int i915_audio_component_get_cdclk_freq(struct device *dev) +{ + struct drm_i915_private *dev_priv = dev_to_i915(dev); + int ret; + + if (WARN_ON_ONCE(!HAS_DDI(dev_priv))) + return -ENODEV; + + intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); + ret = intel_ddi_get_cdclk_freq(dev_priv); + intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); + + return ret; +} + +static const struct i915_audio_component_ops i915_audio_component_ops = { + .owner = THIS_MODULE, + .get_power = i915_audio_component_get_power, + .put_power = i915_audio_component_put_power, + .get_cdclk_freq = i915_audio_component_get_cdclk_freq, +}; + +static int i915_audio_component_bind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + if (WARN_ON(acomp->ops || acomp->dev)) + return -EEXIST; + + acomp->ops = &i915_audio_component_ops; + acomp->dev = i915_dev; + + return 0; +} + +static void i915_audio_component_unbind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + acomp->ops = NULL; + acomp->dev = NULL; +} + +static const struct component_ops i915_audio_component_bind_ops = { + .bind = i915_audio_component_bind, + .unbind = i915_audio_component_unbind, +}; + +/** + * i915_audio_component_init - initialize and register the audio component + * @dev_priv: i915 device instance + * + * This will register with the component framework a child component which + * will bind dynamically to the snd_hda_intel driver's corresponding master + * component when the latter is registered. During binding the child + * initializes an instance of struct i915_audio_component which it receives + * from the master. The master can then start to use the interface defined by + * this struct. Each side can break the binding at any point by deregistering + * its own component after which each side's component unbind callback is + * called. + * + * We ignore any error during registration and continue with reduced + * functionality (i.e. without HDMI audio). + */ +void i915_audio_component_init(struct drm_i915_private *dev_priv) +{ + int ret; + + ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops); + if (ret < 0) { + DRM_ERROR("failed to add audio component (%d)\n", ret); + /* continue with reduced functionality */ + return; + } + + dev_priv->audio_component_registered = true; +} + +/** + * i915_audio_component_cleanup - deregister the audio component + * @dev_priv: i915 device instance + * + * Deregisters the audio component, breaking any existing binding to the + * corresponding snd_hda_intel driver's master component. + */ +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv) +{ + if (!dev_priv->audio_component_registered) + return; + + component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops); + dev_priv->audio_component_registered = false; +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 25fdbb1..e88fd5d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -872,6 +872,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); void intel_init_audio(struct drm_device *dev); void intel_audio_codec_enable(struct intel_encoder *encoder); void intel_audio_codec_disable(struct intel_encoder *encoder); +void i915_audio_component_init(struct drm_i915_private *dev_priv); +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
/* intel_display.c */ const char *intel_output_name(int output); diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h new file mode 100644 index 0000000..3e2f22e --- /dev/null +++ b/include/drm/i915_component.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _I915_COMPONENT_H_ +#define _I915_COMPONENT_H_ + +struct i915_audio_component { + struct device *dev; + + const struct i915_audio_component_ops { + struct module *owner; + void (*get_power)(struct device *); + void (*put_power)(struct device *); + int (*get_cdclk_freq)(struct device *); + } *ops; +}; + +#endif /* _I915_COMPONENT_H_ */
This struct will be needed by the component code added in an upcoming patch, so export it into a new hda_intel.h file. At the same time also merge hda_i915.h into this new header, there is no reason to keep two separate intel specific header file.
Suggested-by: Takashi Iwai tiwai@suse.de Signed-off-by: Imre Deak imre.deak@intel.com Reviewed-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_i915.c | 2 +- sound/pci/hda/hda_i915.h | 37 --------------------------- sound/pci/hda/hda_intel.c | 27 +------------------- sound/pci/hda/hda_intel.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 64 deletions(-) delete mode 100644 sound/pci/hda/hda_i915.h create mode 100644 sound/pci/hda/hda_intel.h
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index d4d0375..6a7854d 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -21,7 +21,7 @@ #include <sound/core.h> #include <drm/i915_powerwell.h> #include "hda_priv.h" -#include "hda_i915.h" +#include "hda_intel.h"
/* Intel HSW/BDW display HDA controller Extended Mode registers. * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h deleted file mode 100644 index e6072c6..0000000 --- a/sound/pci/hda/hda_i915.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __SOUND_HDA_I915_H -#define __SOUND_HDA_I915_H - -#ifdef CONFIG_SND_HDA_I915 -int hda_display_power(bool enable); -void haswell_set_bclk(struct azx *chip); -int hda_i915_init(void); -int hda_i915_exit(void); -#else -static inline int hda_display_power(bool enable) { return 0; } -static inline void haswell_set_bclk(struct azx *chip) { return; } -static inline int hda_i915_init(void) -{ - return -ENODEV; -} -static inline int hda_i915_exit(void) -{ - return 0; -} -#endif - -#endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d426a0b..e4bc0dc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include "hda_codec.h" #include "hda_controller.h" #include "hda_priv.h" -#include "hda_i915.h" +#include "hda_intel.h"
/* position fix mode */ enum { @@ -354,31 +354,6 @@ static char *driver_short_names[] = { [AZX_DRIVER_GENERIC] = "HD-Audio Generic", };
-struct hda_intel { - struct azx chip; - - /* for pending irqs */ - struct work_struct irq_pending_work; - - /* sync probing */ - struct completion probe_wait; - struct work_struct probe_work; - - /* card list (for power_save trigger) */ - struct list_head list; - - /* extra flags */ - unsigned int irq_pending_warned:1; - - /* VGA-switcheroo setup */ - unsigned int use_vga_switcheroo:1; - unsigned int vga_switcheroo_registered:1; - unsigned int init_failed:1; /* delayed init failed */ - - /* secondary power domain for hdmi audio under vga device */ - struct dev_pm_domain hdmi_pm_domain; -}; - #ifdef CONFIG_X86 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) { diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h new file mode 100644 index 0000000..434f254 --- /dev/null +++ b/sound/pci/hda/hda_intel.h @@ -0,0 +1,64 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __SOUND_HDA_INTEL_H +#define __SOUND_HDA_INTEL_H + +#include "hda_priv.h" + +struct hda_intel { + struct azx chip; + + /* for pending irqs */ + struct work_struct irq_pending_work; + + /* sync probing */ + struct completion probe_wait; + struct work_struct probe_work; + + /* card list (for power_save trigger) */ + struct list_head list; + + /* extra flags */ + unsigned int irq_pending_warned:1; + + /* VGA-switcheroo setup */ + unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; + unsigned int init_failed:1; /* delayed init failed */ + + /* secondary power domain for hdmi audio under vga device */ + struct dev_pm_domain hdmi_pm_domain; +}; + +#ifdef CONFIG_SND_HDA_I915 +int hda_display_power(bool enable); +void haswell_set_bclk(struct azx *chip); +int hda_i915_init(void); +int hda_i915_exit(void); +#else +static inline int hda_display_power(bool enable) { return 0; } +static inline void haswell_set_bclk(struct azx *chip) { return; } +static inline int hda_i915_init(void) +{ + return -ENODEV; +} +static inline int hda_i915_exit(void) +{ + return 0; +} +#endif + +#endif
chip is already passed to most of the i915 interface functions. Unify the interface by passing intel_hda instead of chip and passing it to all functions. Passing intel_hda instead of chip makes more sense since this is an intel specific interface. Also in an upcoming patch we will use intel_hda in all of these functions so by passing intel_hda we can save on some pointer casts from chip to intel_hda.
This will be needed by an upcoming patch adding component support.
No functional change.
v2-3: unchanged v4: - pass intel_hda instead of chip
Signed-off-by: Imre Deak imre.deak@intel.com Reviewed-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_i915.c | 12 ++++++------ sound/pci/hda/hda_intel.c | 28 ++++++++++++++++------------ sound/pci/hda/hda_intel.h | 19 +++++++++++-------- 3 files changed, 33 insertions(+), 26 deletions(-)
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 6a7854d..66acd09 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -35,7 +35,7 @@ static int (*get_power)(void); static int (*put_power)(void); static int (*get_cdclk)(void);
-int hda_display_power(bool enable) +int hda_display_power(struct hda_intel *hda, bool enable) { if (!get_power || !put_power) return -ENODEV; @@ -48,7 +48,7 @@ int hda_display_power(bool enable) return put_power(); }
-void haswell_set_bclk(struct azx *chip) +void haswell_set_bclk(struct hda_intel *hda) { int cdclk_freq; unsigned int bclk_m, bclk_n; @@ -80,12 +80,12 @@ void haswell_set_bclk(struct azx *chip) break; }
- azx_writew(chip, EM4, bclk_m); - azx_writew(chip, EM5, bclk_n); + azx_writew(&hda->chip, EM4, bclk_m); + azx_writew(&hda->chip, EM5, bclk_n); }
-int hda_i915_init(void) +int hda_i915_init(struct hda_intel *hda) { int err = 0;
@@ -111,7 +111,7 @@ int hda_i915_init(void) return err; }
-int hda_i915_exit(void) +int hda_i915_exit(struct hda_intel *hda) { if (get_power) { symbol_put(i915_request_power_well); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e4bc0dc..323abf9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -803,7 +803,7 @@ static int azx_suspend(struct device *dev) pci_save_state(pci); pci_set_power_state(pci, PCI_D3hot); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(false); + hda_display_power(hda, false); return 0; }
@@ -823,8 +823,8 @@ static int azx_resume(struct device *dev) return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(true); - haswell_set_bclk(chip); + hda_display_power(hda, true); + haswell_set_bclk(hda); } pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); @@ -876,7 +876,7 @@ static int azx_runtime_suspend(struct device *dev) azx_enter_link_reset(chip); azx_clear_irq_pending(chip); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_display_power(false); + hda_display_power(hda, false);
return 0; } @@ -902,8 +902,8 @@ static int azx_runtime_resume(struct device *dev) return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(true); - haswell_set_bclk(chip); + hda_display_power(hda, true); + haswell_set_bclk(hda); }
/* Read STATESTS before controller reset */ @@ -1125,8 +1125,8 @@ static int azx_free(struct azx *chip) release_firmware(chip->fw); #endif if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - hda_display_power(false); - hda_i915_exit(); + hda_display_power(hda, false); + hda_i915_exit(hda); } kfree(hda);
@@ -1604,8 +1604,12 @@ static int azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip);
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - haswell_set_bclk(chip); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + struct hda_intel *hda; + + hda = container_of(chip, struct hda_intel, chip); + haswell_set_bclk(hda); + }
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
@@ -1885,13 +1889,13 @@ static int azx_probe_continue(struct azx *chip) /* Request power well for Haswell HDA controller and codec */ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { #ifdef CONFIG_SND_HDA_I915 - err = hda_i915_init(); + err = hda_i915_init(hda); if (err < 0) { dev_err(chip->card->dev, "Error request power-well from i915\n"); goto out_free; } - err = hda_display_power(true); + err = hda_display_power(hda, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 434f254..70b8306 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -44,18 +44,21 @@ struct hda_intel { };
#ifdef CONFIG_SND_HDA_I915 -int hda_display_power(bool enable); -void haswell_set_bclk(struct azx *chip); -int hda_i915_init(void); -int hda_i915_exit(void); +int hda_display_power(struct hda_intel *hda, bool enable); +void haswell_set_bclk(struct hda_intel *hda); +int hda_i915_init(struct hda_intel *hda); +int hda_i915_exit(struct hda_intel *hda); #else -static inline int hda_display_power(bool enable) { return 0; } -static inline void haswell_set_bclk(struct azx *chip) { return; } -static inline int hda_i915_init(void) +static inline int hda_display_power(struct hda_intel *hda, bool enable) +{ + return 0; +} +static inline void haswell_set_bclk(struct hda_intel *hda) { return; } +static inline int hda_i915_init(struct hda_intel *hda) { return -ENODEV; } -static inline int hda_i915_exit(void) +static inline int hda_i915_exit(struct hda_intel *hda) { return 0; }
Register a component master to be used to interface with the i915 driver. This is meant to replace the current interface which is based on module symbol lookups.
Note that currently we keep the existing behavior and pin the i915 module while the hda driver is loaded. Using the component interface allows us to remove this dependency once support for dynamically enabling / disabling the HDMI functionality is added to the driver.
v2: - change roles between the hda and i915 components (Daniel) v3: - rename display_component to audio_component (Daniel) v4: - move removal of i915_powerwell.h from this patch to the next (Takashi) - request_module fails if module support isn't enabled, so ignore any error it returns and depend on the following NULL check of the component ops (Takashi) - change over to using dev_* instead of pr_* (Takashi)
Signed-off-by: Imre Deak imre.deak@intel.com Reviewed-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_i915.c | 140 +++++++++++++++++++++++++++++++++------------- sound/pci/hda/hda_intel.c | 5 +- sound/pci/hda/hda_intel.h | 4 ++ 3 files changed, 105 insertions(+), 44 deletions(-)
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 66acd09..7148945 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -18,8 +18,10 @@
#include <linux/init.h> #include <linux/module.h> +#include <linux/pci.h> +#include <linux/component.h> +#include <drm/i915_component.h> #include <sound/core.h> -#include <drm/i915_powerwell.h> #include "hda_priv.h" #include "hda_intel.h"
@@ -31,32 +33,33 @@ #define AZX_REG_EM4 0x100c #define AZX_REG_EM5 0x1010
-static int (*get_power)(void); -static int (*put_power)(void); -static int (*get_cdclk)(void); - int hda_display_power(struct hda_intel *hda, bool enable) { - if (!get_power || !put_power) + struct i915_audio_component *acomp = &hda->audio_component; + + if (!acomp->ops) return -ENODEV;
- pr_debug("HDA display power %s \n", - enable ? "Enable" : "Disable"); + dev_dbg(&hda->chip.pci->dev, "display power %s\n", + enable ? "enable" : "disable"); if (enable) - return get_power(); + acomp->ops->get_power(acomp->dev); else - return put_power(); + acomp->ops->put_power(acomp->dev); + + return 0; }
void haswell_set_bclk(struct hda_intel *hda) { int cdclk_freq; unsigned int bclk_m, bclk_n; + struct i915_audio_component *acomp = &hda->audio_component;
- if (!get_cdclk) + if (!acomp->ops) return;
- cdclk_freq = get_cdclk(); + cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); switch (cdclk_freq) { case 337500: bclk_m = 16; @@ -84,47 +87,104 @@ void haswell_set_bclk(struct hda_intel *hda) azx_writew(&hda->chip, EM5, bclk_n); }
+static int hda_component_master_bind(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct i915_audio_component *acomp = &hda->audio_component; + int ret; + + ret = component_bind_all(dev, acomp); + if (ret < 0) + return ret; + + if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power && + acomp->ops->put_power && acomp->ops->get_cdclk_freq))) { + ret = -EINVAL; + goto out_unbind; + } + + /* + * Atm, we don't support dynamic unbinding initiated by the child + * component, so pin its containing module until we unbind. + */ + if (!try_module_get(acomp->ops->owner)) { + ret = -ENODEV; + goto out_unbind; + } + + return 0; + +out_unbind: + component_unbind_all(dev, acomp); + + return ret; +} + +static void hda_component_master_unbind(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct i915_audio_component *acomp = &hda->audio_component; + + module_put(acomp->ops->owner); + component_unbind_all(dev, acomp); + WARN_ON(acomp->ops || acomp->dev); +} + +static const struct component_master_ops hda_component_master_ops = { + .bind = hda_component_master_bind, + .unbind = hda_component_master_unbind, +}; + +static int hda_component_master_match(struct device *dev, void *data) +{ + /* i915 is the only supported component */ + return !strcmp(dev->driver->name, "i915"); +}
int hda_i915_init(struct hda_intel *hda) { - int err = 0; + struct component_match *match = NULL; + struct device *dev = &hda->chip.pci->dev; + struct i915_audio_component *acomp = &hda->audio_component; + int ret;
- get_power = symbol_request(i915_request_power_well); - if (!get_power) { - pr_warn("hda-i915: get_power symbol get fail\n"); - return -ENODEV; - } + component_match_add(dev, &match, hda_component_master_match, hda); + ret = component_master_add_with_match(dev, &hda_component_master_ops, + match); + if (ret < 0) + goto out_err; + + /* + * Atm, we don't support deferring the component binding, so make sure + * i915 is loaded and that the binding successfully completes. + */ + request_module("i915");
- put_power = symbol_request(i915_release_power_well); - if (!put_power) { - symbol_put(i915_request_power_well); - get_power = NULL; - return -ENODEV; + if (!acomp->ops) { + ret = -ENODEV; + goto out_master_del; }
- get_cdclk = symbol_request(i915_get_cdclk_freq); - if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ - pr_warn("hda-i915: get_cdclk symbol get fail\n"); + dev_dbg(dev, "bound to i915 component master\n");
- pr_debug("HDA driver get symbol successfully from i915 module\n"); + return 0; +out_master_del: + component_master_del(dev, &hda_component_master_ops); +out_err: + dev_err(dev, "failed to add i915 component master (%d)\n", ret);
- return err; + return ret; }
int hda_i915_exit(struct hda_intel *hda) { - if (get_power) { - symbol_put(i915_request_power_well); - get_power = NULL; - } - if (put_power) { - symbol_put(i915_release_power_well); - put_power = NULL; - } - if (get_cdclk) { - symbol_put(i915_get_cdclk_freq); - get_cdclk = NULL; - } + struct device *dev = &hda->chip.pci->dev; + + component_master_del(dev, &hda_component_master_ops);
return 0; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 323abf9..95a5399 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1890,11 +1890,8 @@ static int azx_probe_continue(struct azx *chip) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { #ifdef CONFIG_SND_HDA_I915 err = hda_i915_init(hda); - if (err < 0) { - dev_err(chip->card->dev, - "Error request power-well from i915\n"); + if (err < 0) goto out_free; - } err = hda_display_power(hda, true); if (err < 0) { dev_err(chip->card->dev, diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 70b8306..3486118 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -16,6 +16,7 @@ #ifndef __SOUND_HDA_INTEL_H #define __SOUND_HDA_INTEL_H
+#include <drm/i915_component.h> #include "hda_priv.h"
struct hda_intel { @@ -41,6 +42,9 @@ struct hda_intel {
/* secondary power domain for hdmi audio under vga device */ struct dev_pm_domain hdmi_pm_domain; + + /* i915 component interface */ + struct i915_audio_component audio_component; };
#ifdef CONFIG_SND_HDA_I915
On Thu, Jan 08, 2015 at 05:54:12PM +0200, Imre Deak wrote:
This is v4 of [1] addressing the review comments from Takashi and Jani.
[1] http://lists.freedesktop.org/archives/intel-gfx/2014-December/056992.html
Imre Deak (6): drm/i915: add dev_to_i915 helper drm/i915: add component support ALSA: hda: export struct hda_intel ALSA: hda: pass intel_hda to all i915 interface functions ALSA: hda: add component support drm/i915: remove unused power_well/get_cdclk_freq api
All merged to dinq, thanks. -Daniel
drivers/gpu/drm/i915/i915_dma.c | 4 + drivers/gpu/drm/i915/i915_drv.c | 9 +- drivers/gpu/drm/i915/i915_drv.h | 8 ++ drivers/gpu/drm/i915/intel_audio.c | 110 +++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_runtime_pm.c | 56 ------------ include/drm/i915_component.h | 38 ++++++++ include/drm/i915_powerwell.h | 37 -------- sound/pci/hda/hda_i915.c | 152 ++++++++++++++++++++++---------- sound/pci/hda/hda_i915.h | 37 -------- sound/pci/hda/hda_intel.c | 60 ++++--------- sound/pci/hda/hda_intel.h | 71 +++++++++++++++ 12 files changed, 360 insertions(+), 224 deletions(-) create mode 100644 include/drm/i915_component.h delete mode 100644 include/drm/i915_powerwell.h delete mode 100644 sound/pci/hda/hda_i915.h create mode 100644 sound/pci/hda/hda_intel.h
-- 2.1.0
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
At Fri, 9 Jan 2015 10:18:45 +0100, Daniel Vetter wrote:
On Thu, Jan 08, 2015 at 05:54:12PM +0200, Imre Deak wrote:
This is v4 of [1] addressing the review comments from Takashi and Jani.
[1] http://lists.freedesktop.org/archives/intel-gfx/2014-December/056992.html
Imre Deak (6): drm/i915: add dev_to_i915 helper drm/i915: add component support ALSA: hda: export struct hda_intel ALSA: hda: pass intel_hda to all i915 interface functions ALSA: hda: add component support drm/i915: remove unused power_well/get_cdclk_freq api
All merged to dinq, thanks.
Daniel, could you give a clean branch? This will change lots in hd-audio driver code, so I'd like to pull it into my tree for further development, too.
thanks,
Takashi
-Daniel
drivers/gpu/drm/i915/i915_dma.c | 4 + drivers/gpu/drm/i915/i915_drv.c | 9 +- drivers/gpu/drm/i915/i915_drv.h | 8 ++ drivers/gpu/drm/i915/intel_audio.c | 110 +++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_runtime_pm.c | 56 ------------ include/drm/i915_component.h | 38 ++++++++ include/drm/i915_powerwell.h | 37 -------- sound/pci/hda/hda_i915.c | 152 ++++++++++++++++++++++---------- sound/pci/hda/hda_i915.h | 37 -------- sound/pci/hda/hda_intel.c | 60 ++++--------- sound/pci/hda/hda_intel.h | 71 +++++++++++++++ 12 files changed, 360 insertions(+), 224 deletions(-) create mode 100644 include/drm/i915_component.h delete mode 100644 include/drm/i915_powerwell.h delete mode 100644 sound/pci/hda/hda_i915.h create mode 100644 sound/pci/hda/hda_intel.h
-- 2.1.0
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch
On Fri, Jan 9, 2015 at 11:20 AM, Takashi Iwai tiwai@suse.de wrote:
At Fri, 9 Jan 2015 10:18:45 +0100, Daniel Vetter wrote:
On Thu, Jan 08, 2015 at 05:54:12PM +0200, Imre Deak wrote:
This is v4 of [1] addressing the review comments from Takashi and Jani.
[1] http://lists.freedesktop.org/archives/intel-gfx/2014-December/056992.html
Imre Deak (6): drm/i915: add dev_to_i915 helper drm/i915: add component support ALSA: hda: export struct hda_intel ALSA: hda: pass intel_hda to all i915 interface functions ALSA: hda: add component support drm/i915: remove unused power_well/get_cdclk_freq api
All merged to dinq, thanks.
Daniel, could you give a clean branch? This will change lots in hd-audio driver code, so I'd like to pull it into my tree for further development, too.
Yeah my plan is to createa a branch plus send you a pull request. Just wanted to give these patches some testing before heading out to lca. -Daniel
At Mon, 12 Jan 2015 02:32:16 +0100, Daniel Vetter wrote:
On Fri, Jan 9, 2015 at 11:20 AM, Takashi Iwai tiwai@suse.de wrote:
At Fri, 9 Jan 2015 10:18:45 +0100, Daniel Vetter wrote:
On Thu, Jan 08, 2015 at 05:54:12PM +0200, Imre Deak wrote:
This is v4 of [1] addressing the review comments from Takashi and Jani.
[1] http://lists.freedesktop.org/archives/intel-gfx/2014-December/056992.html
Imre Deak (6): drm/i915: add dev_to_i915 helper drm/i915: add component support ALSA: hda: export struct hda_intel ALSA: hda: pass intel_hda to all i915 interface functions ALSA: hda: add component support drm/i915: remove unused power_well/get_cdclk_freq api
All merged to dinq, thanks.
Daniel, could you give a clean branch? This will change lots in hd-audio driver code, so I'd like to pull it into my tree for further development, too.
Yeah my plan is to createa a branch plus send you a pull request. Just wanted to give these patches some testing before heading out to lca.
OK, thanks!
Takashi
participants (3)
-
Daniel Vetter
-
Imre Deak
-
Takashi Iwai