mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
soundwire updates for 7.2
- Improvements in handling of soundwire groups
- Additional checks flagged by various tools
- Intel driver updates for ghost Realtek device handling in firmware and
adding devices to wake lists
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmo6rhwACgkQfBQHDyUj
g0dYtBAAiEa7b58duDNxl2lf4YlZBqa/MvMfMWVMbW5ZtYd00aokv2QBIEVubb22
a5l+7T7X5wHA1meS3mrsYktWInjJTe257b3qpwghfhbBkbLnbMs7esmZES03p9eg
9lcmznhJnWSFddO8/CTch3EALGjmqN1WnCjwCaqjFXeQc36qxWILbEzShKtu88CE
IU8MAvMyj4TWtklbZh6Y/VKKc+tcah2KgdHmKhv+z/ypiDUH5k5fHORQOsHo+Hxt
rukFL4hQvdBA1B7//Q6u6Usvu7yKQQRsYQ6ybZi9ZXa7+GJ5BOznfM5fTVU5mQjS
+xbPH/CMrdDH/HxdoKns72DQvC2n18tAGobS0UiadpTLSWkZ9PypW3VfYUb5Z+Ur
iWt+plzYXceM8viq3KcmgV07gzTwLXopBWv0iVDP9fEBzVnpJbX/l5+yUwtfabq0
IJMzSILlKoqwIJgP69rN3SScTm1G3biB6m+Y3GCzeUBbEEQs4JQB6mjkPVvpP7/I
qp9pz5mQJwVBoInlKzYWlNmAEjWRqmQUoEYU0g35vI7bcWjtbtemFzuDFXkqZMp9
wk784sXlXOvUoBudBuJFy2OG/tdELarmVj/Pk7U1XNPAzh39nf9tMfQnj9CzOxVR
trzkPKoR7m65WbuIFt8nlC81JOSunDRBmXvBSzbXvVvdVqd9Vn0=
=dF8L
-----END PGP SIGNATURE-----
Merge tag 'soundwire-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire
Pull soundwire updates from Vinod Koul:
- Improvements in handling of soundwire groups
- Additional checks flagged by various tools
- Intel driver updates for ghost Realtek device handling in firmware
and adding devices to wake lists
* tag 'soundwire-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
soundwire: dmi-quirks: Disable ghost Realtek devices
soundwire: only handle alert events when the peripheral is attached
soundwire: intel_ace2x: release bpt_stream when close it
soundwire: intel: Move suspend tracking from trigger to pm suspend
soundwire: intel_auxdevice: Add es9356 to wake_capable_list
soundwire: use krealloc_array to prevent integer overflow
soundwire: increase group->max_size after allocation
soundwire: fix bug in sdw_add_element_group_count found by syzkaller
soundwire: don't program SDW_SCP_BUSCLOCK_SCALE on a unattached Peripheral
soundwire: validate DT compatible before parsing it
soundwire: intel_auxdevice: Add cs42l43b to wake_capable_list
soundwire: stream: sdw_stream_remove_slave(): Check stream is valid
This commit is contained in:
commit
240303e47f
|
|
@ -1986,6 +1986,10 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
|
|||
break;
|
||||
|
||||
case SDW_SLAVE_ALERT:
|
||||
if (slave->status != SDW_SLAVE_ATTACHED &&
|
||||
slave->status != SDW_SLAVE_ALERT)
|
||||
continue;
|
||||
|
||||
ret = sdw_handle_slave_alerts(slave);
|
||||
if (ret < 0)
|
||||
dev_err(&slave->dev,
|
||||
|
|
|
|||
|
|
@ -90,6 +90,19 @@ static const struct adr_remap intel_rooks_county[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Many platforms have ghost realtek devices in the ACPI that don't physically
|
||||
* exist, remove those devices.
|
||||
*/
|
||||
static const struct adr_remap ghost_realtek[] = {
|
||||
/* rt722 on link3 */
|
||||
{
|
||||
0x000330025d072201ull,
|
||||
0x0000000000000000ull
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct dmi_system_id adr_remap_quirk_table[] = {
|
||||
/* TGL devices */
|
||||
{
|
||||
|
|
@ -164,6 +177,28 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
|
|||
},
|
||||
.driver_data = (void *)hp_omen_16,
|
||||
},
|
||||
/* PTL devices */
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "UX5406AA"),
|
||||
},
|
||||
.driver_data = (void *)ghost_realtek,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "83QK"),
|
||||
},
|
||||
.driver_data = (void *)ghost_realtek,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "83SF"),
|
||||
},
|
||||
.driver_data = (void *)ghost_realtek,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -299,39 +299,35 @@ static int sdw_add_element_group_count(struct sdw_group *group,
|
|||
int num = group->count;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= num; i++) {
|
||||
for (i = 0; i < num; i++) {
|
||||
if (rate == group->rates[i] && lane == group->lanes[i])
|
||||
break;
|
||||
|
||||
if (i != num)
|
||||
continue;
|
||||
|
||||
if (group->count >= group->max_size) {
|
||||
unsigned int *rates;
|
||||
unsigned int *lanes;
|
||||
|
||||
group->max_size += 1;
|
||||
rates = krealloc(group->rates,
|
||||
(sizeof(int) * group->max_size),
|
||||
GFP_KERNEL);
|
||||
if (!rates)
|
||||
return -ENOMEM;
|
||||
|
||||
group->rates = rates;
|
||||
|
||||
lanes = krealloc(group->lanes,
|
||||
(sizeof(int) * group->max_size),
|
||||
GFP_KERNEL);
|
||||
if (!lanes)
|
||||
return -ENOMEM;
|
||||
|
||||
group->lanes = lanes;
|
||||
}
|
||||
|
||||
group->rates[group->count] = rate;
|
||||
group->lanes[group->count++] = lane;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (group->count >= group->max_size) {
|
||||
unsigned int *rates;
|
||||
unsigned int *lanes;
|
||||
|
||||
rates = krealloc_array(group->rates, group->max_size + 1,
|
||||
sizeof(*group->rates), GFP_KERNEL);
|
||||
if (!rates)
|
||||
return -ENOMEM;
|
||||
|
||||
group->rates = rates;
|
||||
|
||||
lanes = krealloc_array(group->lanes, group->max_size + 1,
|
||||
sizeof(*group->lanes), GFP_KERNEL);
|
||||
if (!lanes)
|
||||
return -ENOMEM;
|
||||
|
||||
group->lanes = lanes;
|
||||
|
||||
group->max_size += 1;
|
||||
}
|
||||
|
||||
group->rates[group->count] = rate;
|
||||
group->lanes[group->count++] = lane;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -906,19 +906,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
|
|||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
|
||||
/*
|
||||
* The .prepare callback is used to deal with xruns and resume operations.
|
||||
* In the case of xruns, the DMAs and SHIM registers cannot be touched,
|
||||
* but for resume operations the DMAs and SHIM registers need to be initialized.
|
||||
* the .trigger callback is used to track the suspend case only.
|
||||
*/
|
||||
|
||||
dai_runtime->suspended = true;
|
||||
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
dai_runtime->paused = true;
|
||||
break;
|
||||
|
|
@ -955,10 +942,12 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
|
|||
struct snd_soc_dai *dai;
|
||||
|
||||
/*
|
||||
* In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
|
||||
* does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
|
||||
* Since the component suspend is called last, we can trap this corner case
|
||||
* and force the DAIs to release their resources.
|
||||
* Mark all open streams as suspended.
|
||||
* Open streams at this point can be in SUSPENDED, PAUSED or STOPPED
|
||||
* state and during prepare the DMAs and SHIM registers need to be
|
||||
* initialized for them.
|
||||
* The STOPPED state is a special corner case which can happen if audio
|
||||
* experiences xrun at suspend time.
|
||||
*/
|
||||
for_each_component_dais(component, dai) {
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
|
|
@ -966,13 +955,7 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
|
|||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
|
||||
if (!dai_runtime)
|
||||
continue;
|
||||
|
||||
if (dai_runtime->suspended)
|
||||
continue;
|
||||
|
||||
if (dai_runtime->paused)
|
||||
if (dai_runtime)
|
||||
dai_runtime->suspended = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -317,6 +317,7 @@ static void intel_ace2x_bpt_close_stream(struct sdw_intel *sdw, struct sdw_slave
|
|||
dev_err(cdns->dev, "%s: remove slave failed: %d\n",
|
||||
__func__, ret);
|
||||
|
||||
sdw_release_stream(cdns->bus.bpt_stream);
|
||||
cdns->bus.bpt_stream = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -894,19 +895,6 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
|
|||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
|
||||
/*
|
||||
* The .prepare callback is used to deal with xruns and resume operations.
|
||||
* In the case of xruns, the DMAs and SHIM registers cannot be touched,
|
||||
* but for resume operations the DMAs and SHIM registers need to be initialized.
|
||||
* the .trigger callback is used to track the suspend case only.
|
||||
*/
|
||||
|
||||
dai_runtime->suspended = true;
|
||||
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
dai_runtime->paused = true;
|
||||
break;
|
||||
|
|
@ -930,8 +918,34 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
|
|||
.get_stream = intel_get_sdw_stream,
|
||||
};
|
||||
|
||||
static int intel_component_dais_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_dai *dai;
|
||||
|
||||
/*
|
||||
* Mark all open streams as suspended.
|
||||
* Open streams at this point can be in SUSPENDED, PAUSED or STOPPED
|
||||
* state and during prepare the DMAs and SHIM registers need to be
|
||||
* initialized for them.
|
||||
* The STOPPED state is a special corner case which can happen if audio
|
||||
* experiences xrun at suspend time.
|
||||
*/
|
||||
for_each_component_dais(component, dai) {
|
||||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
|
||||
struct sdw_cdns_dai_runtime *dai_runtime;
|
||||
|
||||
dai_runtime = cdns->dai_runtime_array[dai->id];
|
||||
|
||||
if (dai_runtime)
|
||||
dai_runtime->suspended = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver dai_component = {
|
||||
.name = "soundwire",
|
||||
.suspend = intel_component_dais_suspend,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ struct wake_capable_part {
|
|||
};
|
||||
|
||||
static struct wake_capable_part wake_capable_list[] = {
|
||||
{0x01fa, 0x2A30},
|
||||
{0x01fa, 0x2A3B},
|
||||
{0x01fa, 0x4243},
|
||||
{0x01fa, 0x4245},
|
||||
{0x01fa, 0x4249},
|
||||
|
|
@ -70,6 +72,7 @@ static struct wake_capable_part wake_capable_list[] = {
|
|||
{0x025d, 0x717},
|
||||
{0x025d, 0x721},
|
||||
{0x025d, 0x722},
|
||||
{0x04b3, 0x9356},
|
||||
};
|
||||
|
||||
static bool is_wake_capable(struct sdw_slave *slave)
|
||||
|
|
|
|||
|
|
@ -244,8 +244,8 @@ int sdw_of_find_slaves(struct sdw_bus *bus)
|
|||
struct sdw_slave_id id;
|
||||
const __be32 *addr;
|
||||
|
||||
compat = of_get_property(node, "compatible", NULL);
|
||||
if (!compat)
|
||||
ret = of_property_read_string(node, "compatible", &compat);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
ret = sscanf(compat, "sdw%01x%04hx%04hx%02hhx", &sdw_version,
|
||||
|
|
|
|||
|
|
@ -697,6 +697,13 @@ static int sdw_program_params(struct sdw_bus *bus, bool prepare)
|
|||
if (scale_index < 0)
|
||||
return scale_index;
|
||||
|
||||
/* Skip the unattached Peripherals */
|
||||
if (!completion_done(&slave->enumeration_complete)) {
|
||||
dev_warn(&slave->dev,
|
||||
"Not enumerated, skip programming BUSCLOCK_SCALE\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sdw_write_no_pm(slave, addr1, scale_index);
|
||||
if (ret < 0) {
|
||||
dev_err(&slave->dev, "SDW_SCP_BUSCLOCK_SCALE register write failed\n");
|
||||
|
|
@ -2229,11 +2236,15 @@ EXPORT_SYMBOL(sdw_stream_add_slave);
|
|||
* @slave: SDW Slave instance
|
||||
* @stream: SoundWire stream
|
||||
*
|
||||
* This removes and frees port_rt and slave_rt from a stream
|
||||
* This removes and frees port_rt and slave_rt from a stream.
|
||||
* If stream is NULL or an ERR_PTR, do nothing and return 0.
|
||||
*/
|
||||
int sdw_stream_remove_slave(struct sdw_slave *slave,
|
||||
struct sdw_stream_runtime *stream)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(stream))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&slave->bus->bus_lock);
|
||||
|
||||
sdw_slave_port_free(slave, stream);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user