Skip to content

Commit 784cf44

Browse files
committed
Merge branches 'acpi-scan' and 'acpi-tables'
Merge ACPI device enumeration changes and ACPI data-only tables support updates for 6.10: - Rearrange fields in several structures to effectively eliminate computations from container_of() in some cases (Andy Shevchenko). - Do some assorted cleanups of the ACPI device enumeration code (Andy Shevchenko). - Make the ACPI device enumeration code skip devices with _STA values clearly identified by the specification as invalid (Rafael Wysocki). - Rework the handling of the NHLT table to simplify and clarify it and drop some obsolete pieces (Cezary Rojewski). * acpi-scan: ACPI: scan: Avoid enumerating devices with clearly invalid _STA values ACPI: scan: Introduce typedef:s for struct acpi_hotplug_context members ACPI: scan: Use standard error checking pattern ACPI: scan: Move misleading comment to acpi_dma_configure_id() ACPI: scan: Use list_first_entry_or_null() in acpi_device_hid() ACPI: bus: Don't use "proxy" headers ACPI: bus: Make container_of() no-op where it makes sense * acpi-tables: ACPI: NHLT: Streamline struct naming ACPI: NHLT: Drop redundant types ACPI: NHLT: Introduce API for the table ACPI: NHLT: Reintroduce types the table consists of
3 parents 82303dd + d4aa921 + a640aca commit 784cf44

File tree

9 files changed

+652
-238
lines changed

9 files changed

+652
-238
lines changed

drivers/acpi/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,9 @@ config ACPI_REDUCED_HARDWARE_ONLY
469469

470470
If you are unsure what to do, do not enable this option.
471471

472+
config ACPI_NHLT
473+
bool
474+
472475
source "drivers/acpi/nfit/Kconfig"
473476
source "drivers/acpi/numa/Kconfig"
474477
source "drivers/acpi/apei/Kconfig"

drivers/acpi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ obj-$(CONFIG_ACPI_THERMAL_LIB) += thermal_lib.o
9393
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
9494
obj-$(CONFIG_ACPI_PLATFORM_PROFILE) += platform_profile.o
9595
obj-$(CONFIG_ACPI_NFIT) += nfit/
96+
obj-$(CONFIG_ACPI_NHLT) += nhlt.o
9697
obj-$(CONFIG_ACPI_NUMA) += numa/
9798
obj-$(CONFIG_ACPI) += acpi_memhotplug.o
9899
obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o

drivers/acpi/bus.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@ int acpi_bus_get_status(struct acpi_device *device)
112112
if (ACPI_FAILURE(status))
113113
return -ENODEV;
114114

115+
if (!device->status.present && device->status.enabled) {
116+
pr_info(FW_BUG "Device [%s] status [%08x]: not present and enabled\n",
117+
device->pnp.bus_id, (u32)sta);
118+
device->status.enabled = 0;
119+
/*
120+
* The status is clearly invalid, so clear the functional bit as
121+
* well to avoid attempting to use the device.
122+
*/
123+
device->status.functional = 0;
124+
}
125+
115126
acpi_set_device_status(device, sta);
116127

117128
if (device->status.functional && !device->status.present) {

drivers/acpi/dock.c

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -88,43 +88,29 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
8888
enum dock_callback_type cb_type)
8989
{
9090
struct acpi_device *adev = dd->adev;
91+
acpi_hp_fixup fixup = NULL;
92+
acpi_hp_uevent uevent = NULL;
93+
acpi_hp_notify notify = NULL;
9194

9295
acpi_lock_hp_context();
9396

94-
if (!adev->hp)
95-
goto out;
96-
97-
if (cb_type == DOCK_CALL_FIXUP) {
98-
void (*fixup)(struct acpi_device *);
99-
100-
fixup = adev->hp->fixup;
101-
if (fixup) {
102-
acpi_unlock_hp_context();
103-
fixup(adev);
104-
return;
105-
}
106-
} else if (cb_type == DOCK_CALL_UEVENT) {
107-
void (*uevent)(struct acpi_device *, u32);
108-
109-
uevent = adev->hp->uevent;
110-
if (uevent) {
111-
acpi_unlock_hp_context();
112-
uevent(adev, event);
113-
return;
114-
}
115-
} else {
116-
int (*notify)(struct acpi_device *, u32);
117-
118-
notify = adev->hp->notify;
119-
if (notify) {
120-
acpi_unlock_hp_context();
121-
notify(adev, event);
122-
return;
123-
}
97+
if (adev->hp) {
98+
if (cb_type == DOCK_CALL_FIXUP)
99+
fixup = adev->hp->fixup;
100+
else if (cb_type == DOCK_CALL_UEVENT)
101+
uevent = adev->hp->uevent;
102+
else
103+
notify = adev->hp->notify;
124104
}
125105

126-
out:
127106
acpi_unlock_hp_context();
107+
108+
if (fixup)
109+
fixup(adev);
110+
else if (uevent)
111+
uevent(adev, event);
112+
else if (notify)
113+
notify(adev, event);
128114
}
129115

130116
static struct dock_station *find_dock_station(acpi_handle handle)

drivers/acpi/nhlt.c

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright(c) 2023-2024 Intel Corporation
4+
*
5+
* Authors: Cezary Rojewski <[email protected]>
6+
* Amadeusz Slawinski <[email protected]>
7+
*/
8+
9+
#define pr_fmt(fmt) "ACPI: NHLT: " fmt
10+
11+
#include <linux/acpi.h>
12+
#include <linux/errno.h>
13+
#include <linux/export.h>
14+
#include <linux/minmax.h>
15+
#include <linux/printk.h>
16+
#include <linux/types.h>
17+
#include <acpi/nhlt.h>
18+
19+
static struct acpi_table_nhlt *acpi_gbl_nhlt;
20+
21+
static struct acpi_table_nhlt empty_nhlt = {
22+
.header = {
23+
.signature = ACPI_SIG_NHLT,
24+
},
25+
};
26+
27+
/**
28+
* acpi_nhlt_get_gbl_table - Retrieve a pointer to the first NHLT table.
29+
*
30+
* If there is no NHLT in the system, acpi_gbl_nhlt will instead point to an
31+
* empty table.
32+
*
33+
* Return: ACPI status code of the operation.
34+
*/
35+
acpi_status acpi_nhlt_get_gbl_table(void)
36+
{
37+
acpi_status status;
38+
39+
status = acpi_get_table(ACPI_SIG_NHLT, 0, (struct acpi_table_header **)(&acpi_gbl_nhlt));
40+
if (!acpi_gbl_nhlt)
41+
acpi_gbl_nhlt = &empty_nhlt;
42+
return status;
43+
}
44+
EXPORT_SYMBOL_GPL(acpi_nhlt_get_gbl_table);
45+
46+
/**
47+
* acpi_nhlt_put_gbl_table - Release the global NHLT table.
48+
*/
49+
void acpi_nhlt_put_gbl_table(void)
50+
{
51+
acpi_put_table((struct acpi_table_header *)acpi_gbl_nhlt);
52+
}
53+
EXPORT_SYMBOL_GPL(acpi_nhlt_put_gbl_table);
54+
55+
/**
56+
* acpi_nhlt_endpoint_match - Verify if an endpoint matches criteria.
57+
* @ep: the endpoint to check.
58+
* @link_type: the hardware link type, e.g.: PDM or SSP.
59+
* @dev_type: the device type.
60+
* @dir: stream direction.
61+
* @bus_id: the ID of virtual bus hosting the endpoint.
62+
*
63+
* Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
64+
* value to ignore the parameter when matching.
65+
*
66+
* Return: %true if endpoint matches specified criteria or %false otherwise.
67+
*/
68+
bool acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep,
69+
int link_type, int dev_type, int dir, int bus_id)
70+
{
71+
return ep &&
72+
(link_type < 0 || ep->link_type == link_type) &&
73+
(dev_type < 0 || ep->device_type == dev_type) &&
74+
(bus_id < 0 || ep->virtual_bus_id == bus_id) &&
75+
(dir < 0 || ep->direction == dir);
76+
}
77+
EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_match);
78+
79+
/**
80+
* acpi_nhlt_tb_find_endpoint - Search a NHLT table for an endpoint.
81+
* @tb: the table to search.
82+
* @link_type: the hardware link type, e.g.: PDM or SSP.
83+
* @dev_type: the device type.
84+
* @dir: stream direction.
85+
* @bus_id: the ID of virtual bus hosting the endpoint.
86+
*
87+
* Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
88+
* value to ignore the parameter during the search.
89+
*
90+
* Return: A pointer to endpoint matching the criteria, %NULL if not found or
91+
* an ERR_PTR() otherwise.
92+
*/
93+
struct acpi_nhlt_endpoint *
94+
acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt *tb,
95+
int link_type, int dev_type, int dir, int bus_id)
96+
{
97+
struct acpi_nhlt_endpoint *ep;
98+
99+
for_each_nhlt_endpoint(tb, ep)
100+
if (acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id))
101+
return ep;
102+
return NULL;
103+
}
104+
EXPORT_SYMBOL_GPL(acpi_nhlt_tb_find_endpoint);
105+
106+
/**
107+
* acpi_nhlt_find_endpoint - Search all NHLT tables for an endpoint.
108+
* @link_type: the hardware link type, e.g.: PDM or SSP.
109+
* @dev_type: the device type.
110+
* @dir: stream direction.
111+
* @bus_id: the ID of virtual bus hosting the endpoint.
112+
*
113+
* Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
114+
* value to ignore the parameter during the search.
115+
*
116+
* Return: A pointer to endpoint matching the criteria, %NULL if not found or
117+
* an ERR_PTR() otherwise.
118+
*/
119+
struct acpi_nhlt_endpoint *
120+
acpi_nhlt_find_endpoint(int link_type, int dev_type, int dir, int bus_id)
121+
{
122+
/* TODO: Currently limited to table of index 0. */
123+
return acpi_nhlt_tb_find_endpoint(acpi_gbl_nhlt, link_type, dev_type, dir, bus_id);
124+
}
125+
EXPORT_SYMBOL_GPL(acpi_nhlt_find_endpoint);
126+
127+
/**
128+
* acpi_nhlt_endpoint_find_fmtcfg - Search endpoint's formats configuration space
129+
* for a specific format.
130+
* @ep: the endpoint to search.
131+
* @ch: number of channels.
132+
* @rate: samples per second.
133+
* @vbps: valid bits per sample.
134+
* @bps: bits per sample.
135+
*
136+
* Return: A pointer to format matching the criteria, %NULL if not found or
137+
* an ERR_PTR() otherwise.
138+
*/
139+
struct acpi_nhlt_format_config *
140+
acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep,
141+
u16 ch, u32 rate, u16 vbps, u16 bps)
142+
{
143+
struct acpi_nhlt_wave_formatext *wav;
144+
struct acpi_nhlt_format_config *fmt;
145+
146+
for_each_nhlt_endpoint_fmtcfg(ep, fmt) {
147+
wav = &fmt->format;
148+
149+
if (wav->valid_bits_per_sample == vbps &&
150+
wav->samples_per_sec == rate &&
151+
wav->bits_per_sample == bps &&
152+
wav->channel_count == ch)
153+
return fmt;
154+
}
155+
156+
return NULL;
157+
}
158+
EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_find_fmtcfg);
159+
160+
/**
161+
* acpi_nhlt_tb_find_fmtcfg - Search a NHLT table for a specific format.
162+
* @tb: the table to search.
163+
* @link_type: the hardware link type, e.g.: PDM or SSP.
164+
* @dev_type: the device type.
165+
* @dir: stream direction.
166+
* @bus_id: the ID of virtual bus hosting the endpoint.
167+
*
168+
* @ch: number of channels.
169+
* @rate: samples per second.
170+
* @vbps: valid bits per sample.
171+
* @bps: bits per sample.
172+
*
173+
* Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
174+
* value to ignore the parameter during the search.
175+
*
176+
* Return: A pointer to format matching the criteria, %NULL if not found or
177+
* an ERR_PTR() otherwise.
178+
*/
179+
struct acpi_nhlt_format_config *
180+
acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt *tb,
181+
int link_type, int dev_type, int dir, int bus_id,
182+
u16 ch, u32 rate, u16 vbps, u16 bps)
183+
{
184+
struct acpi_nhlt_format_config *fmt;
185+
struct acpi_nhlt_endpoint *ep;
186+
187+
for_each_nhlt_endpoint(tb, ep) {
188+
if (!acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id))
189+
continue;
190+
191+
fmt = acpi_nhlt_endpoint_find_fmtcfg(ep, ch, rate, vbps, bps);
192+
if (fmt)
193+
return fmt;
194+
}
195+
196+
return NULL;
197+
}
198+
EXPORT_SYMBOL_GPL(acpi_nhlt_tb_find_fmtcfg);
199+
200+
/**
201+
* acpi_nhlt_find_fmtcfg - Search all NHLT tables for a specific format.
202+
* @link_type: the hardware link type, e.g.: PDM or SSP.
203+
* @dev_type: the device type.
204+
* @dir: stream direction.
205+
* @bus_id: the ID of virtual bus hosting the endpoint.
206+
*
207+
* @ch: number of channels.
208+
* @rate: samples per second.
209+
* @vbps: valid bits per sample.
210+
* @bps: bits per sample.
211+
*
212+
* Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative
213+
* value to ignore the parameter during the search.
214+
*
215+
* Return: A pointer to format matching the criteria, %NULL if not found or
216+
* an ERR_PTR() otherwise.
217+
*/
218+
struct acpi_nhlt_format_config *
219+
acpi_nhlt_find_fmtcfg(int link_type, int dev_type, int dir, int bus_id,
220+
u16 ch, u32 rate, u16 vbps, u16 bps)
221+
{
222+
/* TODO: Currently limited to table of index 0. */
223+
return acpi_nhlt_tb_find_fmtcfg(acpi_gbl_nhlt, link_type, dev_type, dir, bus_id,
224+
ch, rate, vbps, bps);
225+
}
226+
EXPORT_SYMBOL_GPL(acpi_nhlt_find_fmtcfg);
227+
228+
static bool acpi_nhlt_config_is_micdevice(struct acpi_nhlt_config *cfg)
229+
{
230+
return cfg->capabilities_size >= sizeof(struct acpi_nhlt_micdevice_config);
231+
}
232+
233+
static bool acpi_nhlt_config_is_vendor_micdevice(struct acpi_nhlt_config *cfg)
234+
{
235+
struct acpi_nhlt_vendor_micdevice_config *devcfg = __acpi_nhlt_config_caps(cfg);
236+
237+
return cfg->capabilities_size >= sizeof(*devcfg) &&
238+
cfg->capabilities_size == struct_size(devcfg, mics, devcfg->mics_count);
239+
}
240+
241+
/**
242+
* acpi_nhlt_endpoint_mic_count - Retrieve number of digital microphones for a PDM endpoint.
243+
* @ep: the endpoint to return microphones count for.
244+
*
245+
* Return: A number of microphones or an error code if an invalid endpoint is provided.
246+
*/
247+
int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt_endpoint *ep)
248+
{
249+
union acpi_nhlt_device_config *devcfg;
250+
struct acpi_nhlt_format_config *fmt;
251+
struct acpi_nhlt_config *cfg;
252+
u16 max_ch = 0;
253+
254+
if (!ep || ep->link_type != ACPI_NHLT_LINKTYPE_PDM)
255+
return -EINVAL;
256+
257+
/* Find max number of channels based on formats configuration. */
258+
for_each_nhlt_endpoint_fmtcfg(ep, fmt)
259+
max_ch = max(fmt->format.channel_count, max_ch);
260+
261+
cfg = __acpi_nhlt_endpoint_config(ep);
262+
devcfg = __acpi_nhlt_config_caps(cfg);
263+
264+
/* If @ep is not a mic array, fallback to channels count. */
265+
if (!acpi_nhlt_config_is_micdevice(cfg) ||
266+
devcfg->gen.config_type != ACPI_NHLT_CONFIGTYPE_MICARRAY)
267+
return max_ch;
268+
269+
switch (devcfg->mic.array_type) {
270+
case ACPI_NHLT_ARRAYTYPE_LINEAR2_SMALL:
271+
case ACPI_NHLT_ARRAYTYPE_LINEAR2_BIG:
272+
return 2;
273+
274+
case ACPI_NHLT_ARRAYTYPE_LINEAR4_GEO1:
275+
case ACPI_NHLT_ARRAYTYPE_PLANAR4_LSHAPED:
276+
case ACPI_NHLT_ARRAYTYPE_LINEAR4_GEO2:
277+
return 4;
278+
279+
case ACPI_NHLT_ARRAYTYPE_VENDOR:
280+
if (!acpi_nhlt_config_is_vendor_micdevice(cfg))
281+
return -EINVAL;
282+
return devcfg->vendor_mic.mics_count;
283+
284+
default:
285+
pr_warn("undefined mic array type: %#x\n", devcfg->mic.array_type);
286+
return max_ch;
287+
}
288+
}
289+
EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_mic_count);

0 commit comments

Comments
 (0)