[PATCH v4] soundwire: intel: move to auxiliary bus

Pierre-Louis Bossart pierre-louis.bossart at linux.intel.com
Tue May 25 20:30:36 CEST 2021



On 5/11/21 12:21 AM, Bard Liao wrote:
> From: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> 
> Now that the auxiliary_bus exists, there's no reason to use platform
> devices as children of a PCI device any longer.
> 
> This patch refactors the code by extending a basic auxiliary device
> with Intel link-specific structures that need to be passed between
> controller and link levels. This refactoring is much cleaner with no
> need for cross-pointers between device and link structures.
> 
> Note that the auxiliary bus API has separate init and add steps, which
> requires more attention in the error unwinding paths. The main loop
> needs to deal with kfree() and auxiliary_device_uninit() for the
> current iteration before jumping to the common label which releases
> everything allocated in prior iterations.
> 
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski at linux.intel.com>
> Reviewed-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> Signed-off-by: Bard Liao <yung-chuan.liao at linux.intel.com>
> ---
> v2:
>   - add link_dev_register for all kzalloc, device_init, and device_add.
> v3:
>   - Modify the function description of sdw_intel_probe() which was
>     missing in previous version.
> v4:
>   - Move intel_link_dev_unregister(ldev) before pm_runtime_put_noidle(
>     ldev->link_res.dev) to fix use-after-free reported by KASAN.

Two years ago, GregKH stated in
https://lore.kernel.org/lkml/20190509181812.GA10776@kroah.com/

"So soundwire is creating platform devices?  Ick, no!  Don't do that"

Fast forward two years, this patch provides a solution to remove the use 
of the platform devices with the auxiliary bus. This move does not add 
any new functionality, it's just a replacement of one type of device by 
another.

The reviews have been rather limited since the first version shared on 
March 22.

a) I updated the code to follow the model of the Mellanox driver in

https://elixir.bootlin.com/linux/latest/source/include/linux/mlx5/driver.h#L545

I hope this addresses GregKH's feedback on the need for a 'register' 
function to combined the two init and add steps. I didn't see a path to 
add a generic register function in the auxiliary bus code since between 
init and add there is a need to setup domain-specific structures. Other 
contributors to the auxiliary bus (CC:ed) also didn't have a burning 
desire to add this capability.

b) Vinod commented:

"What I would like to see the end result is that sdw driver for Intel
controller here is a simple auxdev device and no additional custom setup
layer required... which implies that this handling should be moved into
auxdev or Intel code setting up auxdev..."

I was unable to figure out what this comment hinted at: the auxbus is 
already handled in the intel_init.c and intel.c files and the auxbus is 
used to model a set of links/managers below the PCI device, not the 
controller itself. There is also no such thing as a simple auxdev device 
used in the kernel today, the base layer is meant to be extended with 
domain-specific structures. There is really no point in creating a 
simple auxbus device without extensions.

My reply from March 24 which included technical details on how the 
auxiliary bus is designed was not followed by any replies/comments from 
Vinod, so I don't know if there is agreement or still a disconnect.

I understand everyone is busy, but I could use more feedback on this 
patch. Vinod and Greg can you please chime in on this v4?

Thank you.

> ---
>   drivers/soundwire/Kconfig           |   1 +
>   drivers/soundwire/intel.c           |  56 ++++---
>   drivers/soundwire/intel.h           |  14 +-
>   drivers/soundwire/intel_init.c      | 232 +++++++++++++++++++---------
>   include/linux/soundwire/sdw_intel.h |   6 +-
>   5 files changed, 202 insertions(+), 107 deletions(-)
> 
> diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig
> index 016e74230bb7..2b7795233282 100644
> --- a/drivers/soundwire/Kconfig
> +++ b/drivers/soundwire/Kconfig
> @@ -25,6 +25,7 @@ config SOUNDWIRE_INTEL
>   	tristate "Intel SoundWire Master driver"
>   	select SOUNDWIRE_CADENCE
>   	select SOUNDWIRE_GENERIC_ALLOCATION
> +	select AUXILIARY_BUS
>   	depends on ACPI && SND_SOC
>   	help
>   	  SoundWire Intel Master driver.
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index fd95f94630b1..c11e3d8cd308 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -11,7 +11,7 @@
>   #include <linux/module.h>
>   #include <linux/interrupt.h>
>   #include <linux/io.h>
> -#include <linux/platform_device.h>
> +#include <linux/auxiliary_bus.h>
>   #include <sound/pcm_params.h>
>   #include <linux/pm_runtime.h>
>   #include <sound/soc.h>
> @@ -1327,11 +1327,14 @@ static int intel_init(struct sdw_intel *sdw)
>   }
>   
>   /*
> - * probe and init
> + * probe and init (aux_dev_id argument is required by function prototype but not used)
>    */
> -static int intel_master_probe(struct platform_device *pdev)
> +static int intel_link_probe(struct auxiliary_device *auxdev,
> +			    const struct auxiliary_device_id *aux_dev_id)
> +
>   {
> -	struct device *dev = &pdev->dev;
> +	struct device *dev = &auxdev->dev;
> +	struct sdw_intel_link_dev *ldev = auxiliary_dev_to_sdw_intel_link_dev(auxdev);
>   	struct sdw_intel *sdw;
>   	struct sdw_cdns *cdns;
>   	struct sdw_bus *bus;
> @@ -1344,14 +1347,14 @@ static int intel_master_probe(struct platform_device *pdev)
>   	cdns = &sdw->cdns;
>   	bus = &cdns->bus;
>   
> -	sdw->instance = pdev->id;
> -	sdw->link_res = dev_get_platdata(dev);
> +	sdw->instance = auxdev->id;
> +	sdw->link_res = &ldev->link_res;
>   	cdns->dev = dev;
>   	cdns->registers = sdw->link_res->registers;
>   	cdns->instance = sdw->instance;
>   	cdns->msg_count = 0;
>   
> -	bus->link_id = pdev->id;
> +	bus->link_id = auxdev->id;
>   
>   	sdw_cdns_probe(cdns);
>   
> @@ -1384,10 +1387,10 @@ static int intel_master_probe(struct platform_device *pdev)
>   	return 0;
>   }
>   
> -int intel_master_startup(struct platform_device *pdev)
> +int intel_link_startup(struct auxiliary_device *auxdev)
>   {
>   	struct sdw_cdns_stream_config config;
> -	struct device *dev = &pdev->dev;
> +	struct device *dev = &auxdev->dev;
>   	struct sdw_cdns *cdns = dev_get_drvdata(dev);
>   	struct sdw_intel *sdw = cdns_to_intel(cdns);
>   	struct sdw_bus *bus = &cdns->bus;
> @@ -1524,9 +1527,9 @@ int intel_master_startup(struct platform_device *pdev)
>   	return ret;
>   }
>   
> -static int intel_master_remove(struct platform_device *pdev)
> +static void intel_link_remove(struct auxiliary_device *auxdev)
>   {
> -	struct device *dev = &pdev->dev;
> +	struct device *dev = &auxdev->dev;
>   	struct sdw_cdns *cdns = dev_get_drvdata(dev);
>   	struct sdw_intel *sdw = cdns_to_intel(cdns);
>   	struct sdw_bus *bus = &cdns->bus;
> @@ -1542,19 +1545,17 @@ static int intel_master_remove(struct platform_device *pdev)
>   		snd_soc_unregister_component(dev);
>   	}
>   	sdw_bus_master_delete(bus);
> -
> -	return 0;
>   }
>   
> -int intel_master_process_wakeen_event(struct platform_device *pdev)
> +int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
>   {
> -	struct device *dev = &pdev->dev;
> +	struct device *dev = &auxdev->dev;
>   	struct sdw_intel *sdw;
>   	struct sdw_bus *bus;
>   	void __iomem *shim;
>   	u16 wake_sts;
>   
> -	sdw = platform_get_drvdata(pdev);
> +	sdw = dev_get_drvdata(dev);
>   	bus = &sdw->cdns.bus;
>   
>   	if (bus->prop.hw_disabled) {
> @@ -1976,17 +1977,22 @@ static const struct dev_pm_ops intel_pm = {
>   	SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL)
>   };
>   
> -static struct platform_driver sdw_intel_drv = {
> -	.probe = intel_master_probe,
> -	.remove = intel_master_remove,
> +static const struct auxiliary_device_id intel_link_id_table[] = {
> +	{ .name = "soundwire_intel.link" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(auxiliary, intel_link_id_table);
> +
> +static struct auxiliary_driver sdw_intel_drv = {
> +	.probe = intel_link_probe,
> +	.remove = intel_link_remove,
>   	.driver = {
> -		.name = "intel-sdw",
> +		/* auxiliary_driver_register() sets .name to be the modname */
>   		.pm = &intel_pm,
> -	}
> +	},
> +	.id_table = intel_link_id_table
>   };
> -
> -module_platform_driver(sdw_intel_drv);
> +module_auxiliary_driver(sdw_intel_drv);
>   
>   MODULE_LICENSE("Dual BSD/GPL");
> -MODULE_ALIAS("platform:intel-sdw");
> -MODULE_DESCRIPTION("Intel Soundwire Master Driver");
> +MODULE_DESCRIPTION("Intel Soundwire Link Driver");
> diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h
> index 06bac8ba14e9..0b47b148da3f 100644
> --- a/drivers/soundwire/intel.h
> +++ b/drivers/soundwire/intel.h
> @@ -7,7 +7,6 @@
>   /**
>    * struct sdw_intel_link_res - Soundwire Intel link resource structure,
>    * typically populated by the controller driver.
> - * @pdev: platform_device
>    * @mmio_base: mmio base of SoundWire registers
>    * @registers: Link IO registers base
>    * @shim: Audio shim pointer
> @@ -23,7 +22,6 @@
>    * @list: used to walk-through all masters exposed by the same controller
>    */
>   struct sdw_intel_link_res {
> -	struct platform_device *pdev;
>   	void __iomem *mmio_base; /* not strictly needed, useful for debug */
>   	void __iomem *registers;
>   	void __iomem *shim;
> @@ -48,7 +46,15 @@ struct sdw_intel {
>   #endif
>   };
>   
> -int intel_master_startup(struct platform_device *pdev);
> -int intel_master_process_wakeen_event(struct platform_device *pdev);
> +int intel_link_startup(struct auxiliary_device *auxdev);
> +int intel_link_process_wakeen_event(struct auxiliary_device *auxdev);
> +
> +struct sdw_intel_link_dev {
> +	struct auxiliary_device auxdev;
> +	struct sdw_intel_link_res link_res;
> +};
> +
> +#define auxiliary_dev_to_sdw_intel_link_dev(auxiliary_dev) \
> +	container_of(auxiliary_dev, struct sdw_intel_link_dev, auxdev)
>   
>   #endif /* __SDW_INTEL_LOCAL_H */
> diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
> index 30ce95ec2d70..9e283bef53d2 100644
> --- a/drivers/soundwire/intel_init.c
> +++ b/drivers/soundwire/intel_init.c
> @@ -12,7 +12,7 @@
>   #include <linux/interrupt.h>
>   #include <linux/io.h>
>   #include <linux/module.h>
> -#include <linux/platform_device.h>
> +#include <linux/auxiliary_bus.h>
>   #include <linux/pm_runtime.h>
>   #include <linux/soundwire/sdw_intel.h>
>   #include "cadence_master.h"
> @@ -24,28 +24,108 @@
>   #define SDW_LINK_BASE		0x30000
>   #define SDW_LINK_SIZE		0x10000
>   
> +static void intel_link_dev_release(struct device *dev)
> +{
> +	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
> +	struct sdw_intel_link_dev *ldev = auxiliary_dev_to_sdw_intel_link_dev(auxdev);
> +
> +	kfree(ldev);
> +}
> +
> +/* alloc, init and add link devices */
> +static struct sdw_intel_link_dev *intel_link_dev_register(struct sdw_intel_res *res,
> +							  struct sdw_intel_ctx *ctx,
> +							  struct fwnode_handle *fwnode,
> +							  const char *name,
> +							  int link_id)
> +{
> +	struct sdw_intel_link_dev *ldev;
> +	struct sdw_intel_link_res *link;
> +	struct auxiliary_device *auxdev;
> +	int ret;
> +
> +	ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
> +	if (!ldev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	auxdev = &ldev->auxdev;
> +	auxdev->name = name;
> +	auxdev->dev.parent = res->parent;
> +	auxdev->dev.fwnode = fwnode;
> +	auxdev->dev.release = intel_link_dev_release;
> +
> +	/* we don't use an IDA since we already have a link ID */
> +	auxdev->id = link_id;
> +
> +	/*
> +	 * keep a handle on the allocated memory, to be used in all other functions.
> +	 * Since the same pattern is used to skip links that are not enabled, there is
> +	 * no need to check if ctx->ldev[i] is NULL later on.
> +	 */
> +	ctx->ldev[link_id] = ldev;
> +
> +	/* Add link information used in the driver probe */
> +	link = &ldev->link_res;
> +	link->mmio_base = res->mmio_base;
> +	link->registers = res->mmio_base + SDW_LINK_BASE
> +		+ (SDW_LINK_SIZE * link_id);
> +	link->shim = res->mmio_base + SDW_SHIM_BASE;
> +	link->alh = res->mmio_base + SDW_ALH_BASE;
> +
> +	link->ops = res->ops;
> +	link->dev = res->dev;
> +
> +	link->clock_stop_quirks = res->clock_stop_quirks;
> +	link->shim_lock = &ctx->shim_lock;
> +	link->shim_mask = &ctx->shim_mask;
> +	link->link_mask = ctx->link_mask;
> +
> +	/* now follow the two-step init/add sequence */
> +	ret = auxiliary_device_init(auxdev);
> +	if (ret < 0) {
> +		dev_err(res->parent, "failed to initialize link dev %s link_id %d\n",
> +			name, link_id);
> +		kfree(ldev);
> +		return ERR_PTR(ret);
> +	}
> +
> +	ret = auxiliary_device_add(&ldev->auxdev);
> +	if (ret < 0) {
> +		dev_err(res->parent, "failed to add link dev %s link_id %d\n",
> +			ldev->auxdev.name, link_id);
> +		/* ldev will be freed with the put_device() and .release sequence */
> +		auxiliary_device_uninit(&ldev->auxdev);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return ldev;
> +}
> +
> +static void intel_link_dev_unregister(struct sdw_intel_link_dev *ldev)
> +{
> +	auxiliary_device_delete(&ldev->auxdev);
> +	auxiliary_device_uninit(&ldev->auxdev);
> +}
> +
>   static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
>   {
> -	struct sdw_intel_link_res *link = ctx->links;
> +	struct sdw_intel_link_dev *ldev;
>   	u32 link_mask;
>   	int i;
>   
> -	if (!link)
> -		return 0;
> -
>   	link_mask = ctx->link_mask;
>   
> -	for (i = 0; i < ctx->count; i++, link++) {
> +	for (i = 0; i < ctx->count; i++) {
>   		if (!(link_mask & BIT(i)))
>   			continue;
>   
> -		if (link->pdev) {
> -			pm_runtime_disable(&link->pdev->dev);
> -			platform_device_unregister(link->pdev);
> -		}
> +		ldev = ctx->ldev[i];
>   
> -		if (!link->clock_stop_quirks)
> -			pm_runtime_put_noidle(link->dev);
> +		pm_runtime_disable(&ldev->auxdev.dev);
> +		if (!ldev->link_res.clock_stop_quirks)
> +			pm_runtime_put_noidle(ldev->link_res.dev);
> +
> +		intel_link_dev_unregister(ldev);
>   	}
>   
>   	return 0;
> @@ -91,9 +171,8 @@ EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
>   static struct sdw_intel_ctx
>   *sdw_intel_probe_controller(struct sdw_intel_res *res)
>   {
> -	struct platform_device_info pdevinfo;
> -	struct platform_device *pdev;
>   	struct sdw_intel_link_res *link;
> +	struct sdw_intel_link_dev *ldev;
>   	struct sdw_intel_ctx *ctx;
>   	struct acpi_device *adev;
>   	struct sdw_slave *slave;
> @@ -116,67 +195,60 @@ static struct sdw_intel_ctx
>   	count = res->count;
>   	dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
>   
> -	ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL);
> +	/*
> +	 * we need to alloc/free memory manually and can't use devm:
> +	 * this routine may be called from a workqueue, and not from
> +	 * the parent .probe.
> +	 * If devm_ was used, the memory might never be freed on errors.
> +	 */
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>   	if (!ctx)
>   		return NULL;
>   
>   	ctx->count = count;
> -	ctx->links = devm_kcalloc(&adev->dev, ctx->count,
> -				  sizeof(*ctx->links), GFP_KERNEL);
> -	if (!ctx->links)
> +
> +	/*
> +	 * allocate the array of pointers. The link-specific data is allocated
> +	 * as part of the first loop below and released with the auxiliary_device_uninit().
> +	 * If some links are disabled, the link pointer will remain NULL. Given that the
> +	 * number of links is small, this is simpler than using a list to keep track of links.
> +	 */
> +	ctx->ldev = kcalloc(ctx->count, sizeof(*ctx->ldev), GFP_KERNEL);
> +	if (!ctx->ldev) {
> +		kfree(ctx);
>   		return NULL;
> +	}
>   
> -	ctx->count = count;
>   	ctx->mmio_base = res->mmio_base;
>   	ctx->link_mask = res->link_mask;
>   	ctx->handle = res->handle;
>   	mutex_init(&ctx->shim_lock);
>   
> -	link = ctx->links;
>   	link_mask = ctx->link_mask;
>   
>   	INIT_LIST_HEAD(&ctx->link_list);
>   
> -	/* Create SDW Master devices */
> -	for (i = 0; i < count; i++, link++) {
> -		if (!(link_mask & BIT(i))) {
> -			dev_dbg(&adev->dev,
> -				"Link %d masked, will not be enabled\n", i);
> +	for (i = 0; i < count; i++) {
> +		if (!(link_mask & BIT(i)))
>   			continue;
> -		}
>   
> -		link->mmio_base = res->mmio_base;
> -		link->registers = res->mmio_base + SDW_LINK_BASE
> -			+ (SDW_LINK_SIZE * i);
> -		link->shim = res->mmio_base + SDW_SHIM_BASE;
> -		link->alh = res->mmio_base + SDW_ALH_BASE;
> -
> -		link->ops = res->ops;
> -		link->dev = res->dev;
> -
> -		link->clock_stop_quirks = res->clock_stop_quirks;
> -		link->shim_lock = &ctx->shim_lock;
> -		link->shim_mask = &ctx->shim_mask;
> -		link->link_mask = link_mask;
> -
> -		memset(&pdevinfo, 0, sizeof(pdevinfo));
> -
> -		pdevinfo.parent = res->parent;
> -		pdevinfo.name = "intel-sdw";
> -		pdevinfo.id = i;
> -		pdevinfo.fwnode = acpi_fwnode_handle(adev);
> -		pdevinfo.data = link;
> -		pdevinfo.size_data = sizeof(*link);
> -
> -		pdev = platform_device_register_full(&pdevinfo);
> -		if (IS_ERR(pdev)) {
> -			dev_err(&adev->dev,
> -				"platform device creation failed: %ld\n",
> -				PTR_ERR(pdev));
> +		/*
> +		 * init and add a device for each link
> +		 *
> +		 * The name of the device will be soundwire_intel.link.[i],
> +		 * with the "soundwire_intel" module prefix automatically added
> +		 * by the auxiliary bus core.
> +		 */
> +		ldev = intel_link_dev_register(res,
> +					       ctx,
> +					       acpi_fwnode_handle(adev),
> +					       "link",
> +					       i);
> +		if (IS_ERR(ldev))
>   			goto err;
> -		}
> -		link->pdev = pdev;
> -		link->cdns = platform_get_drvdata(pdev);
> +
> +		link = &ldev->link_res;
> +		link->cdns = dev_get_drvdata(&ldev->auxdev.dev);
>   
>   		if (!link->cdns) {
>   			dev_err(&adev->dev, "failed to get link->cdns\n");
> @@ -194,8 +266,7 @@ static struct sdw_intel_ctx
>   			num_slaves++;
>   	}
>   
> -	ctx->ids = devm_kcalloc(&adev->dev, num_slaves,
> -				sizeof(*ctx->ids), GFP_KERNEL);
> +	ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
>   	if (!ctx->ids)
>   		goto err;
>   
> @@ -213,8 +284,14 @@ static struct sdw_intel_ctx
>   	return ctx;
>   
>   err:
> -	ctx->count = i;
> -	sdw_intel_cleanup(ctx);
> +	while (i--) {
> +		if (!(link_mask & BIT(i)))
> +			continue;
> +		ldev = ctx->ldev[i];
> +		intel_link_dev_unregister(ldev);
> +	}
> +	kfree(ctx->ldev);
> +	kfree(ctx);
>   	return NULL;
>   }
>   
> @@ -222,7 +299,7 @@ static int
>   sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
>   {
>   	struct acpi_device *adev;
> -	struct sdw_intel_link_res *link;
> +	struct sdw_intel_link_dev *ldev;
>   	u32 caps;
>   	u32 link_mask;
>   	int i;
> @@ -241,27 +318,28 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
>   		return -EINVAL;
>   	}
>   
> -	if (!ctx->links)
> +	if (!ctx->ldev)
>   		return -EINVAL;
>   
> -	link = ctx->links;
>   	link_mask = ctx->link_mask;
>   
>   	/* Startup SDW Master devices */
> -	for (i = 0; i < ctx->count; i++, link++) {
> +	for (i = 0; i < ctx->count; i++) {
>   		if (!(link_mask & BIT(i)))
>   			continue;
>   
> -		intel_master_startup(link->pdev);
> +		ldev = ctx->ldev[i];
>   
> -		if (!link->clock_stop_quirks) {
> +		intel_link_startup(&ldev->auxdev);
> +
> +		if (!ldev->link_res.clock_stop_quirks) {
>   			/*
>   			 * we need to prevent the parent PCI device
>   			 * from entering pm_runtime suspend, so that
>   			 * power rails to the SoundWire IP are not
>   			 * turned off.
>   			 */
> -			pm_runtime_get_noresume(link->dev);
> +			pm_runtime_get_noresume(ldev->link_res.dev);
>   		}
>   	}
>   
> @@ -272,8 +350,8 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
>    * sdw_intel_probe() - SoundWire Intel probe routine
>    * @res: resource data
>    *
> - * This registers a platform device for each Master handled by the controller,
> - * and SoundWire Master and Slave devices will be created by the platform
> + * This registers an auxiliary device for each Master handled by the controller,
> + * and SoundWire Master and Slave devices will be created by the auxiliary
>    * device probe. All the information necessary is stored in the context, and
>    * the res argument pointer can be freed after this step.
>    * This function will be called after sdw_intel_acpi_scan() by SOF probe.
> @@ -306,27 +384,31 @@ EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
>   void sdw_intel_exit(struct sdw_intel_ctx *ctx)
>   {
>   	sdw_intel_cleanup(ctx);
> +	kfree(ctx->ids);
> +	kfree(ctx->ldev);
> +	kfree(ctx);
>   }
>   EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
>   
>   void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
>   {
> -	struct sdw_intel_link_res *link;
> +	struct sdw_intel_link_dev *ldev;
>   	u32 link_mask;
>   	int i;
>   
> -	if (!ctx->links)
> +	if (!ctx->ldev)
>   		return;
>   
> -	link = ctx->links;
>   	link_mask = ctx->link_mask;
>   
>   	/* Startup SDW Master devices */
> -	for (i = 0; i < ctx->count; i++, link++) {
> +	for (i = 0; i < ctx->count; i++) {
>   		if (!(link_mask & BIT(i)))
>   			continue;
>   
> -		intel_master_process_wakeen_event(link->pdev);
> +		ldev = ctx->ldev[i];
> +
> +		intel_link_process_wakeen_event(&ldev->auxdev);
>   	}
>   }
>   EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT);
> diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h
> index 3a5446ac014a..1ebea7764011 100644
> --- a/include/linux/soundwire/sdw_intel.h
> +++ b/include/linux/soundwire/sdw_intel.h
> @@ -58,7 +58,7 @@ struct sdw_intel_acpi_info {
>   	u32 link_mask;
>   };
>   
> -struct sdw_intel_link_res;
> +struct sdw_intel_link_dev;
>   
>   /* Intel clock-stop/pm_runtime quirk definitions */
>   
> @@ -109,7 +109,7 @@ struct sdw_intel_slave_id {
>    * Controller
>    * @num_slaves: total number of devices exposed across all enabled links
>    * @handle: ACPI parent handle
> - * @links: information for each link (controller-specific and kept
> + * @ldev: information for each link (controller-specific and kept
>    * opaque here)
>    * @ids: array of slave_id, representing Slaves exposed across all enabled
>    * links
> @@ -123,7 +123,7 @@ struct sdw_intel_ctx {
>   	u32 link_mask;
>   	int num_slaves;
>   	acpi_handle handle;
> -	struct sdw_intel_link_res *links;
> +	struct sdw_intel_link_dev **ldev;
>   	struct sdw_intel_slave_id *ids;
>   	struct list_head link_list;
>   	struct mutex shim_lock; /* lock for access to shared SHIM registers */
> 


More information about the Alsa-devel mailing list