Skip to content

Commit e66f91a

Browse files
plbossartvinodkoul
authored andcommitted
soundwire: intel_auxdevice: add hybrid IDA-based device_number allocation
The IDA-based allocation is useful to simplify debug, but it was also introduced as a prerequisite to deal with the Intel Lunar Lake hardware programming sequences: the wake-ups have to be handled with a system-unique SDI address at the HDaudio controller level. At the time, the restriction introduced by the IDA to 8 devices total seemed perfectly fine, but recently hardware vendors created configurations with more than 8 devices. Add a new allocation strategy to allow for more than 8 devices using information on the type of devices, and only use the IDA-based allocation for devices capable of generating a wake. In theory the information on wake capabilities should come from firmware, but none of the existing ACPI tables provide it. The drivers set the 'wake_capable' property, but this cannot be used reliably: if the driver probe happens *after* the enumeration, then that property is not initialized yet. Trying to modify the device_number on-the-fly proved to be an impossible task generating race conditions left and right. The only reliable work-around to control the enumeration is to add a quirk table. It's ugly but until platform firmware improves, hopefully as a result of MIPI/SDCA stardization, we can expect that quirk table to grow for each new headset or microphone codec. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Rander Wang <rander.wang@intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20230731091333.3593132-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 39d80b0 commit e66f91a

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

drivers/soundwire/intel_auxdevice.c

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
#include "intel.h"
2424
#include "intel_auxdevice.h"
2525

26-
/* IDA min selected to avoid conflicts with HDaudio/iDISP SDI values */
27-
#define INTEL_DEV_NUM_IDA_MIN 4
28-
2926
#define INTEL_MASTER_SUSPEND_DELAY_MS 3000
3027

3128
/*
@@ -44,6 +41,39 @@ static int md_flags;
4441
module_param_named(sdw_md_flags, md_flags, int, 0444);
4542
MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)");
4643

44+
struct wake_capable_part {
45+
const u16 mfg_id;
46+
const u16 part_id;
47+
};
48+
49+
static struct wake_capable_part wake_capable_list[] = {
50+
{0x025d, 0x5682},
51+
{0x025d, 0x700},
52+
{0x025d, 0x711},
53+
{0x025d, 0x1712},
54+
{0x025d, 0x1713},
55+
{0x025d, 0x1716},
56+
{0x025d, 0x1717},
57+
{0x025d, 0x712},
58+
{0x025d, 0x713},
59+
{0x025d, 0x714},
60+
{0x025d, 0x715},
61+
{0x025d, 0x716},
62+
{0x025d, 0x717},
63+
{0x025d, 0x722},
64+
};
65+
66+
static bool is_wake_capable(struct sdw_slave *slave)
67+
{
68+
int i;
69+
70+
for (i = 0; i < ARRAY_SIZE(wake_capable_list); i++)
71+
if (slave->id.part_id == wake_capable_list[i].part_id &&
72+
slave->id.mfg_id == wake_capable_list[i].mfg_id)
73+
return true;
74+
return false;
75+
}
76+
4777
static int generic_pre_bank_switch(struct sdw_bus *bus)
4878
{
4979
struct sdw_cdns *cdns = bus_to_cdns(bus);
@@ -66,14 +96,26 @@ static void generic_new_peripheral_assigned(struct sdw_bus *bus,
6696
{
6797
struct sdw_cdns *cdns = bus_to_cdns(bus);
6898
struct sdw_intel *sdw = cdns_to_intel(cdns);
99+
int dev_num_min;
100+
int dev_num_max;
101+
bool wake_capable = slave->prop.wake_capable || is_wake_capable(slave);
102+
103+
if (wake_capable) {
104+
dev_num_min = SDW_INTEL_DEV_NUM_IDA_MIN;
105+
dev_num_max = SDW_MAX_DEVICES;
106+
} else {
107+
dev_num_min = 1;
108+
dev_num_max = SDW_INTEL_DEV_NUM_IDA_MIN - 1;
109+
}
69110

70111
/* paranoia check, this should never happen */
71-
if (dev_num < INTEL_DEV_NUM_IDA_MIN || dev_num > SDW_MAX_DEVICES) {
72-
dev_err(bus->dev, "%s: invalid dev_num %d\n", __func__, dev_num);
112+
if (dev_num < dev_num_min || dev_num > dev_num_max) {
113+
dev_err(bus->dev, "%s: invalid dev_num %d, wake supported %d\n",
114+
__func__, dev_num, slave->prop.wake_capable);
73115
return;
74116
}
75117

76-
if (sdw->link_res->hw_ops->program_sdi)
118+
if (sdw->link_res->hw_ops->program_sdi && wake_capable)
77119
sdw->link_res->hw_ops->program_sdi(sdw, dev_num);
78120
}
79121

@@ -129,14 +171,24 @@ static DEFINE_IDA(intel_peripheral_ida);
129171

130172
static int intel_get_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave)
131173
{
132-
return ida_alloc_range(&intel_peripheral_ida,
133-
INTEL_DEV_NUM_IDA_MIN, SDW_MAX_DEVICES,
134-
GFP_KERNEL);
174+
int bit;
175+
176+
if (slave->prop.wake_capable || is_wake_capable(slave))
177+
return ida_alloc_range(&intel_peripheral_ida,
178+
SDW_INTEL_DEV_NUM_IDA_MIN, SDW_MAX_DEVICES,
179+
GFP_KERNEL);
180+
181+
bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES);
182+
if (bit == SDW_MAX_DEVICES)
183+
return -ENODEV;
184+
185+
return bit;
135186
}
136187

137188
static void intel_put_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave)
138189
{
139-
return ida_free(&intel_peripheral_ida, slave->dev_num);
190+
if (slave->prop.wake_capable || is_wake_capable(slave))
191+
ida_free(&intel_peripheral_ida, slave->dev_num);
140192
}
141193

142194
static struct sdw_master_ops sdw_intel_ops = {

include/linux/soundwire/sdw_intel.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,4 +433,11 @@ struct sdw_intel_hw_ops {
433433
extern const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops;
434434
extern const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops;
435435

436+
/*
437+
* IDA min selected to allow for 5 unconstrained devices per link,
438+
* and 6 system-unique Device Numbers for wake-capable devices.
439+
*/
440+
441+
#define SDW_INTEL_DEV_NUM_IDA_MIN 6
442+
436443
#endif

0 commit comments

Comments
 (0)