From 82b8acc06ea48b69c2482ac2ac994656c3740d08 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 19 Mar 2024 09:30:16 +0100 Subject: ACPI: NHLT: Introduce API for the table The table is composed of a range of endpoints with each describing audio formats they support. Most of the operations involve iterating over elements of the table and filtering them. Simplify the process by implementing range of getters. While the acpi_nhlt_endpoint_mic_count() stands out a bit, it is a critical component for any AudioDSP driver to know how many digital microphones it is dealing with. Signed-off-by: Cezary Rojewski Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 3 + drivers/acpi/Makefile | 1 + drivers/acpi/nhlt.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 drivers/acpi/nhlt.c (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ff1689bb3124..e3a7c2aedd5f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -469,6 +469,9 @@ config ACPI_REDUCED_HARDWARE_ONLY If you are unsure what to do, do not enable this option. +config ACPI_NHLT + bool + source "drivers/acpi/nfit/Kconfig" source "drivers/acpi/numa/Kconfig" source "drivers/acpi/apei/Kconfig" diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8cc8c0d9c873..d69d5444acdb 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_ACPI_THERMAL_LIB) += thermal_lib.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_PLATFORM_PROFILE) += platform_profile.o obj-$(CONFIG_ACPI_NFIT) += nfit/ +obj-$(CONFIG_ACPI_NHLT) += nhlt.o obj-$(CONFIG_ACPI_NUMA) += numa/ obj-$(CONFIG_ACPI) += acpi_memhotplug.o obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o diff --git a/drivers/acpi/nhlt.c b/drivers/acpi/nhlt.c new file mode 100644 index 000000000000..ab722a95cbb5 --- /dev/null +++ b/drivers/acpi/nhlt.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2023-2024 Intel Corporation + * + * Authors: Cezary Rojewski + * Amadeusz Slawinski + */ + +#define pr_fmt(fmt) "ACPI: NHLT: " fmt + +#include +#include +#include +#include +#include +#include +#include + +static struct acpi_table_nhlt2 *acpi_gbl_nhlt; + +static struct acpi_table_nhlt2 empty_nhlt = { + .header = { + .signature = ACPI_SIG_NHLT, + }, +}; + +/** + * acpi_nhlt_get_gbl_table - Retrieve a pointer to the first NHLT table. + * + * If there is no NHLT in the system, acpi_gbl_nhlt will instead point to an + * empty table. + * + * Return: ACPI status code of the operation. + */ +acpi_status acpi_nhlt_get_gbl_table(void) +{ + acpi_status status; + + status = acpi_get_table(ACPI_SIG_NHLT, 0, (struct acpi_table_header **)(&acpi_gbl_nhlt)); + if (!acpi_gbl_nhlt) + acpi_gbl_nhlt = &empty_nhlt; + return status; +} +EXPORT_SYMBOL_GPL(acpi_nhlt_get_gbl_table); + +/** + * acpi_nhlt_put_gbl_table - Release the global NHLT table. + */ +void acpi_nhlt_put_gbl_table(void) +{ + acpi_put_table((struct acpi_table_header *)acpi_gbl_nhlt); +} +EXPORT_SYMBOL_GPL(acpi_nhlt_put_gbl_table); + +/** + * acpi_nhlt_endpoint_match - Verify if an endpoint matches criteria. + * @ep: the endpoint to check. + * @link_type: the hardware link type, e.g.: PDM or SSP. + * @dev_type: the device type. + * @dir: stream direction. + * @bus_id: the ID of virtual bus hosting the endpoint. + * + * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative + * value to ignore the parameter when matching. + * + * Return: %true if endpoint matches specified criteria or %false otherwise. + */ +bool acpi_nhlt_endpoint_match(const struct acpi_nhlt2_endpoint *ep, + int link_type, int dev_type, int dir, int bus_id) +{ + return ep && + (link_type < 0 || ep->link_type == link_type) && + (dev_type < 0 || ep->device_type == dev_type) && + (bus_id < 0 || ep->virtual_bus_id == bus_id) && + (dir < 0 || ep->direction == dir); +} +EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_match); + +/** + * acpi_nhlt_tb_find_endpoint - Search a NHLT table for an endpoint. + * @tb: the table to search. + * @link_type: the hardware link type, e.g.: PDM or SSP. + * @dev_type: the device type. + * @dir: stream direction. + * @bus_id: the ID of virtual bus hosting the endpoint. + * + * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative + * value to ignore the parameter during the search. + * + * Return: A pointer to endpoint matching the criteria, %NULL if not found or + * an ERR_PTR() otherwise. + */ +struct acpi_nhlt2_endpoint * +acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt2 *tb, + int link_type, int dev_type, int dir, int bus_id) +{ + struct acpi_nhlt2_endpoint *ep; + + for_each_nhlt_endpoint(tb, ep) + if (acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id)) + return ep; + return NULL; +} +EXPORT_SYMBOL_GPL(acpi_nhlt_tb_find_endpoint); + +/** + * acpi_nhlt_find_endpoint - Search all NHLT tables for an endpoint. + * @link_type: the hardware link type, e.g.: PDM or SSP. + * @dev_type: the device type. + * @dir: stream direction. + * @bus_id: the ID of virtual bus hosting the endpoint. + * + * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative + * value to ignore the parameter during the search. + * + * Return: A pointer to endpoint matching the criteria, %NULL if not found or + * an ERR_PTR() otherwise. + */ +struct acpi_nhlt2_endpoint * +acpi_nhlt_find_endpoint(int link_type, int dev_type, int dir, int bus_id) +{ + /* TODO: Currently limited to table of index 0. */ + return acpi_nhlt_tb_find_endpoint(acpi_gbl_nhlt, link_type, dev_type, dir, bus_id); +} +EXPORT_SYMBOL_GPL(acpi_nhlt_find_endpoint); + +/** + * acpi_nhlt_endpoint_find_fmtcfg - Search endpoint's formats configuration space + * for a specific format. + * @ep: the endpoint to search. + * @ch: number of channels. + * @rate: samples per second. + * @vbps: valid bits per sample. + * @bps: bits per sample. + * + * Return: A pointer to format matching the criteria, %NULL if not found or + * an ERR_PTR() otherwise. + */ +struct acpi_nhlt2_format_config * +acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt2_endpoint *ep, + u16 ch, u32 rate, u16 vbps, u16 bps) +{ + struct acpi_nhlt2_wave_formatext *wav; + struct acpi_nhlt2_format_config *fmt; + + for_each_nhlt_endpoint_fmtcfg(ep, fmt) { + wav = &fmt->format; + + if (wav->valid_bits_per_sample == vbps && + wav->samples_per_sec == rate && + wav->bits_per_sample == bps && + wav->channel_count == ch) + return fmt; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_find_fmtcfg); + +/** + * acpi_nhlt_tb_find_fmtcfg - Search a NHLT table for a specific format. + * @tb: the table to search. + * @link_type: the hardware link type, e.g.: PDM or SSP. + * @dev_type: the device type. + * @dir: stream direction. + * @bus_id: the ID of virtual bus hosting the endpoint. + * + * @ch: number of channels. + * @rate: samples per second. + * @vbps: valid bits per sample. + * @bps: bits per sample. + * + * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative + * value to ignore the parameter during the search. + * + * Return: A pointer to format matching the criteria, %NULL if not found or + * an ERR_PTR() otherwise. + */ +struct acpi_nhlt2_format_config * +acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt2 *tb, + int link_type, int dev_type, int dir, int bus_id, + u16 ch, u32 rate, u16 vbps, u16 bps) +{ + struct acpi_nhlt2_format_config *fmt; + struct acpi_nhlt2_endpoint *ep; + + for_each_nhlt_endpoint(tb, ep) { + if (!acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id)) + continue; + + fmt = acpi_nhlt_endpoint_find_fmtcfg(ep, ch, rate, vbps, bps); + if (fmt) + return fmt; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(acpi_nhlt_tb_find_fmtcfg); + +/** + * acpi_nhlt_find_fmtcfg - Search all NHLT tables for a specific format. + * @link_type: the hardware link type, e.g.: PDM or SSP. + * @dev_type: the device type. + * @dir: stream direction. + * @bus_id: the ID of virtual bus hosting the endpoint. + * + * @ch: number of channels. + * @rate: samples per second. + * @vbps: valid bits per sample. + * @bps: bits per sample. + * + * Either of @link_type, @dev_type, @dir or @bus_id may be set to a negative + * value to ignore the parameter during the search. + * + * Return: A pointer to format matching the criteria, %NULL if not found or + * an ERR_PTR() otherwise. + */ +struct acpi_nhlt2_format_config * +acpi_nhlt_find_fmtcfg(int link_type, int dev_type, int dir, int bus_id, + u16 ch, u32 rate, u16 vbps, u16 bps) +{ + /* TODO: Currently limited to table of index 0. */ + return acpi_nhlt_tb_find_fmtcfg(acpi_gbl_nhlt, link_type, dev_type, dir, bus_id, + ch, rate, vbps, bps); +} +EXPORT_SYMBOL_GPL(acpi_nhlt_find_fmtcfg); + +static bool acpi_nhlt_config_is_micdevice(struct acpi_nhlt_config *cfg) +{ + return cfg->capabilities_size >= sizeof(struct acpi_nhlt_micdevice_config); +} + +static bool acpi_nhlt_config_is_vendor_micdevice(struct acpi_nhlt_config *cfg) +{ + struct acpi_nhlt_vendor_micdevice_config *devcfg = __acpi_nhlt_config_caps(cfg); + + return cfg->capabilities_size >= sizeof(*devcfg) && + cfg->capabilities_size == struct_size(devcfg, mics, devcfg->mics_count); +} + +/** + * acpi_nhlt_endpoint_mic_count - Retrieve number of digital microphones for a PDM endpoint. + * @ep: the endpoint to return microphones count for. + * + * Return: A number of microphones or an error code if an invalid endpoint is provided. + */ +int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt2_endpoint *ep) +{ + union acpi_nhlt_device_config *devcfg; + struct acpi_nhlt2_format_config *fmt; + struct acpi_nhlt_config *cfg; + u16 max_ch = 0; + + if (!ep || ep->link_type != ACPI_NHLT_LINKTYPE_PDM) + return -EINVAL; + + /* Find max number of channels based on formats configuration. */ + for_each_nhlt_endpoint_fmtcfg(ep, fmt) + max_ch = max(fmt->format.channel_count, max_ch); + + cfg = __acpi_nhlt_endpoint_config(ep); + devcfg = __acpi_nhlt_config_caps(cfg); + + /* If @ep is not a mic array, fallback to channels count. */ + if (!acpi_nhlt_config_is_micdevice(cfg) || + devcfg->gen.config_type != ACPI_NHLT_CONFIGTYPE_MICARRAY) + return max_ch; + + switch (devcfg->mic.array_type) { + case ACPI_NHLT_ARRAYTYPE_LINEAR2_SMALL: + case ACPI_NHLT_ARRAYTYPE_LINEAR2_BIG: + return 2; + + case ACPI_NHLT_ARRAYTYPE_LINEAR4_GEO1: + case ACPI_NHLT_ARRAYTYPE_PLANAR4_LSHAPED: + case ACPI_NHLT_ARRAYTYPE_LINEAR4_GEO2: + return 4; + + case ACPI_NHLT_ARRAYTYPE_VENDOR: + if (!acpi_nhlt_config_is_vendor_micdevice(cfg)) + return -EINVAL; + return devcfg->vendor_mic.mics_count; + + default: + pr_warn("undefined mic array type: %#x\n", devcfg->mic.array_type); + return max_ch; + } +} +EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_mic_count); -- cgit v1.2.3 From a640acab545b21ed1f347376f34d34e461ea92ba Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Tue, 19 Mar 2024 09:30:18 +0100 Subject: ACPI: NHLT: Streamline struct naming Few recently introduced structs are named 'nhlt2' instead of 'nhlt' to avoid naming conflicts. With duplicate types gone, the conflicts are no more. Signed-off-by: Cezary Rojewski Signed-off-by: Rafael J. Wysocki --- drivers/acpi/nhlt.c | 36 ++++++++++++++++++------------------ include/acpi/actbl2.h | 22 +++++++++++----------- include/acpi/nhlt.h | 46 +++++++++++++++++++++++----------------------- 3 files changed, 52 insertions(+), 52 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/nhlt.c b/drivers/acpi/nhlt.c index ab722a95cbb5..dc1bd0df9228 100644 --- a/drivers/acpi/nhlt.c +++ b/drivers/acpi/nhlt.c @@ -16,9 +16,9 @@ #include #include -static struct acpi_table_nhlt2 *acpi_gbl_nhlt; +static struct acpi_table_nhlt *acpi_gbl_nhlt; -static struct acpi_table_nhlt2 empty_nhlt = { +static struct acpi_table_nhlt empty_nhlt = { .header = { .signature = ACPI_SIG_NHLT, }, @@ -65,7 +65,7 @@ EXPORT_SYMBOL_GPL(acpi_nhlt_put_gbl_table); * * Return: %true if endpoint matches specified criteria or %false otherwise. */ -bool acpi_nhlt_endpoint_match(const struct acpi_nhlt2_endpoint *ep, +bool acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep, int link_type, int dev_type, int dir, int bus_id) { return ep && @@ -90,11 +90,11 @@ EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_match); * Return: A pointer to endpoint matching the criteria, %NULL if not found or * an ERR_PTR() otherwise. */ -struct acpi_nhlt2_endpoint * -acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt2 *tb, +struct acpi_nhlt_endpoint * +acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt *tb, int link_type, int dev_type, int dir, int bus_id) { - struct acpi_nhlt2_endpoint *ep; + struct acpi_nhlt_endpoint *ep; for_each_nhlt_endpoint(tb, ep) if (acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id)) @@ -116,7 +116,7 @@ EXPORT_SYMBOL_GPL(acpi_nhlt_tb_find_endpoint); * Return: A pointer to endpoint matching the criteria, %NULL if not found or * an ERR_PTR() otherwise. */ -struct acpi_nhlt2_endpoint * +struct acpi_nhlt_endpoint * acpi_nhlt_find_endpoint(int link_type, int dev_type, int dir, int bus_id) { /* TODO: Currently limited to table of index 0. */ @@ -136,12 +136,12 @@ EXPORT_SYMBOL_GPL(acpi_nhlt_find_endpoint); * Return: A pointer to format matching the criteria, %NULL if not found or * an ERR_PTR() otherwise. */ -struct acpi_nhlt2_format_config * -acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt2_endpoint *ep, +struct acpi_nhlt_format_config * +acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep, u16 ch, u32 rate, u16 vbps, u16 bps) { - struct acpi_nhlt2_wave_formatext *wav; - struct acpi_nhlt2_format_config *fmt; + struct acpi_nhlt_wave_formatext *wav; + struct acpi_nhlt_format_config *fmt; for_each_nhlt_endpoint_fmtcfg(ep, fmt) { wav = &fmt->format; @@ -176,13 +176,13 @@ EXPORT_SYMBOL_GPL(acpi_nhlt_endpoint_find_fmtcfg); * Return: A pointer to format matching the criteria, %NULL if not found or * an ERR_PTR() otherwise. */ -struct acpi_nhlt2_format_config * -acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt2 *tb, +struct acpi_nhlt_format_config * +acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt *tb, int link_type, int dev_type, int dir, int bus_id, u16 ch, u32 rate, u16 vbps, u16 bps) { - struct acpi_nhlt2_format_config *fmt; - struct acpi_nhlt2_endpoint *ep; + struct acpi_nhlt_format_config *fmt; + struct acpi_nhlt_endpoint *ep; for_each_nhlt_endpoint(tb, ep) { if (!acpi_nhlt_endpoint_match(ep, link_type, dev_type, dir, bus_id)) @@ -215,7 +215,7 @@ EXPORT_SYMBOL_GPL(acpi_nhlt_tb_find_fmtcfg); * Return: A pointer to format matching the criteria, %NULL if not found or * an ERR_PTR() otherwise. */ -struct acpi_nhlt2_format_config * +struct acpi_nhlt_format_config * acpi_nhlt_find_fmtcfg(int link_type, int dev_type, int dir, int bus_id, u16 ch, u32 rate, u16 vbps, u16 bps) { @@ -244,10 +244,10 @@ static bool acpi_nhlt_config_is_vendor_micdevice(struct acpi_nhlt_config *cfg) * * Return: A number of microphones or an error code if an invalid endpoint is provided. */ -int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt2_endpoint *ep) +int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt_endpoint *ep) { union acpi_nhlt_device_config *devcfg; - struct acpi_nhlt2_format_config *fmt; + struct acpi_nhlt_format_config *fmt; struct acpi_nhlt_config *cfg; u16 max_ch = 0; diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 31a716a74340..f237269bd1cb 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -1894,7 +1894,7 @@ struct nfit_device_handle { * ******************************************************************************/ -struct acpi_table_nhlt2 { +struct acpi_table_nhlt { struct acpi_table_header header; /* Common ACPI table header */ u8 endpoints_count; /* @@ -1903,7 +1903,7 @@ struct acpi_table_nhlt2 { */ }; -struct acpi_nhlt2_endpoint { +struct acpi_nhlt_endpoint { u32 length; u8 link_type; u8 instance_id; @@ -1990,7 +1990,7 @@ struct acpi_nhlt_micdevice_config { #define ACPI_NHLT_ARRAYTYPE_LINEAR4_GEO2 0xE #define ACPI_NHLT_ARRAYTYPE_VENDOR 0xF -struct acpi_nhlt2_vendor_mic_config { +struct acpi_nhlt_vendor_mic_config { u8 type; u8 panel; u16 speaker_position_distance; /* mm */ @@ -2031,7 +2031,7 @@ struct acpi_nhlt_vendor_micdevice_config { u8 config_type; u8 array_type; u8 mics_count; - struct acpi_nhlt2_vendor_mic_config mics[]; + struct acpi_nhlt_vendor_mic_config mics[]; }; union acpi_nhlt_device_config { @@ -2042,7 +2042,7 @@ union acpi_nhlt_device_config { }; /* Inherited from Microsoft's WAVEFORMATEXTENSIBLE. */ -struct acpi_nhlt2_wave_formatext { +struct acpi_nhlt_wave_formatext { u16 format_tag; u16 channel_count; u32 samples_per_sec; @@ -2055,17 +2055,17 @@ struct acpi_nhlt2_wave_formatext { u8 subformat[16]; }; -struct acpi_nhlt2_format_config { - struct acpi_nhlt2_wave_formatext format; +struct acpi_nhlt_format_config { + struct acpi_nhlt_wave_formatext format; struct acpi_nhlt_config config; }; -struct acpi_nhlt2_formats_config { +struct acpi_nhlt_formats_config { u8 formats_count; - struct acpi_nhlt2_format_config formats[]; + struct acpi_nhlt_format_config formats[]; }; -struct acpi_nhlt2_device_info { +struct acpi_nhlt_device_info { u8 id[16]; u8 instance_id; u8 port_id; @@ -2073,7 +2073,7 @@ struct acpi_nhlt2_device_info { struct acpi_nhlt_devices_info { u8 devices_count; - struct acpi_nhlt2_device_info devices[]; + struct acpi_nhlt_device_info devices[]; }; /******************************************************************************* diff --git a/include/acpi/nhlt.h b/include/acpi/nhlt.h index 7c394e7bc2bb..2108aa6d0207 100644 --- a/include/acpi/nhlt.h +++ b/include/acpi/nhlt.h @@ -23,12 +23,12 @@ * * Return: A pointer to the formats configuration space. */ -static inline struct acpi_nhlt2_formats_config * -acpi_nhlt_endpoint_fmtscfg(const struct acpi_nhlt2_endpoint *ep) +static inline struct acpi_nhlt_formats_config * +acpi_nhlt_endpoint_fmtscfg(const struct acpi_nhlt_endpoint *ep) { struct acpi_nhlt_config *cfg = __acpi_nhlt_endpoint_config(ep); - return (struct acpi_nhlt2_formats_config *)((u8 *)(cfg + 1) + cfg->capabilities_size); + return (struct acpi_nhlt_formats_config *)((u8 *)(cfg + 1) + cfg->capabilities_size); } #define __acpi_nhlt_first_endpoint(tb) \ @@ -99,24 +99,24 @@ acpi_nhlt_endpoint_fmtscfg(const struct acpi_nhlt2_endpoint *ep) acpi_status acpi_nhlt_get_gbl_table(void); void acpi_nhlt_put_gbl_table(void); -bool acpi_nhlt_endpoint_match(const struct acpi_nhlt2_endpoint *ep, +bool acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep, int link_type, int dev_type, int dir, int bus_id); -struct acpi_nhlt2_endpoint * -acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt2 *tb, +struct acpi_nhlt_endpoint * +acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt *tb, int link_type, int dev_type, int dir, int bus_id); -struct acpi_nhlt2_endpoint * +struct acpi_nhlt_endpoint * acpi_nhlt_find_endpoint(int link_type, int dev_type, int dir, int bus_id); -struct acpi_nhlt2_format_config * -acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt2_endpoint *ep, +struct acpi_nhlt_format_config * +acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep, u16 ch, u32 rate, u16 vbps, u16 bps); -struct acpi_nhlt2_format_config * -acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt2 *tb, +struct acpi_nhlt_format_config * +acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt *tb, int link_type, int dev_type, int dir, int bus_id, u16 ch, u32 rate, u16 vpbs, u16 bps); -struct acpi_nhlt2_format_config * +struct acpi_nhlt_format_config * acpi_nhlt_find_fmtcfg(int link_type, int dev_type, int dir, int bus_id, u16 ch, u32 rate, u16 vpbs, u16 bps); -int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt2_endpoint *ep); +int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt_endpoint *ep); #else /* !CONFIG_ACPI_NHLT */ @@ -130,46 +130,46 @@ static inline void acpi_nhlt_put_gbl_table(void) } static inline bool -acpi_nhlt_endpoint_match(const struct acpi_nhlt2_endpoint *ep, +acpi_nhlt_endpoint_match(const struct acpi_nhlt_endpoint *ep, int link_type, int dev_type, int dir, int bus_id) { return false; } -static inline struct acpi_nhlt2_endpoint * -acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt2 *tb, +static inline struct acpi_nhlt_endpoint * +acpi_nhlt_tb_find_endpoint(const struct acpi_table_nhlt *tb, int link_type, int dev_type, int dir, int bus_id) { return NULL; } -static inline struct acpi_nhlt2_format_config * -acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt2_endpoint *ep, +static inline struct acpi_nhlt_format_config * +acpi_nhlt_endpoint_find_fmtcfg(const struct acpi_nhlt_endpoint *ep, u16 ch, u32 rate, u16 vbps, u16 bps) { return NULL; } -static inline struct acpi_nhlt2_format_config * -acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt2 *tb, +static inline struct acpi_nhlt_format_config * +acpi_nhlt_tb_find_fmtcfg(const struct acpi_table_nhlt *tb, int link_type, int dev_type, int dir, int bus_id, u16 ch, u32 rate, u16 vpbs, u16 bps) { return NULL; } -static inline int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt2_endpoint *ep) +static inline int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt_endpoint *ep) { return 0; } -static inline struct acpi_nhlt2_endpoint * +static inline struct acpi_nhlt_endpoint * acpi_nhlt_find_endpoint(int link_type, int dev_type, int dir, int bus_id) { return NULL; } -static inline struct acpi_nhlt2_format_config * +static inline struct acpi_nhlt_format_config * acpi_nhlt_find_fmtcfg(int link_type, int dev_type, int dir, int bus_id, u16 ch, u32 rate, u16 vpbs, u16 bps) { -- cgit v1.2.3 From 2649a0f29a39f455ff39eb2296269e20df3bba0d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Mar 2024 14:33:00 +0200 Subject: ACPI: scan: Use list_first_entry_or_null() in acpi_device_hid() To replace list_empty() + list_first_entry() pair to simplify code. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7c157bf92695..dc625653b198 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1298,10 +1298,10 @@ const char *acpi_device_hid(struct acpi_device *device) { struct acpi_hardware_id *hid; - if (list_empty(&device->pnp.ids)) + hid = list_first_entry_or_null(&device->pnp.ids, struct acpi_hardware_id, list); + if (!hid) return dummy_hid; - hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); return hid->id; } EXPORT_SYMBOL(acpi_device_hid); -- cgit v1.2.3 From e80d4122df9c707ebc9cfe20ab60be302fc9b833 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Mar 2024 14:33:01 +0200 Subject: ACPI: scan: Move misleading comment to acpi_dma_configure_id() The acpi_iommu_configure_id() implementation has a misleading comment since after it the flow does something different to what it states. Move the commit to the caller and with that unshadow the error code inside acpi_iommu_configure_id(). Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index dc625653b198..e64e1ec626b3 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1625,12 +1625,11 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in) if (!err && dev->bus) err = iommu_probe_device(dev); - /* Ignore all other errors apart from EPROBE_DEFER */ - if (err == -EPROBE_DEFER) { + if (err == -EPROBE_DEFER) return err; - } else if (err) { + if (err) { dev_dbg(dev, "Adding to IOMMU failed: %d\n", err); - return -ENODEV; + return err; } if (!acpi_iommu_fwspec_ops(dev)) return -ENODEV; @@ -1671,13 +1670,14 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, acpi_arch_dma_setup(dev); + /* Ignore all other errors apart from EPROBE_DEFER */ ret = acpi_iommu_configure_id(dev, input_id); if (ret == -EPROBE_DEFER) return -EPROBE_DEFER; /* * Historically this routine doesn't fail driver probing due to errors - * in acpi_iommu_configure_id() + * in acpi_iommu_configure_id(). */ arch_setup_dma_ops(dev, 0, U64_MAX, attr == DEV_DMA_COHERENT); -- cgit v1.2.3 From 602401e32847f90c513df4a34bcac4dd6b02dd8d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Mar 2024 14:33:02 +0200 Subject: ACPI: scan: Use standard error checking pattern Check for an error and return it as it's the usual way to handle this. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e64e1ec626b3..b9a33364e553 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1581,12 +1581,13 @@ int acpi_iommu_fwspec_init(struct device *dev, u32 id, struct fwnode_handle *fwnode, const struct iommu_ops *ops) { - int ret = iommu_fwspec_init(dev, fwnode, ops); + int ret; - if (!ret) - ret = iommu_fwspec_add_ids(dev, &id, 1); + ret = iommu_fwspec_init(dev, fwnode, ops); + if (ret) + return ret; - return ret; + return iommu_fwspec_add_ids(dev, &id, 1); } static inline const struct iommu_ops *acpi_iommu_fwspec_ops(struct device *dev) -- cgit v1.2.3 From f5c519fc3628915c2eccd65f86d7ee2ce5cc8645 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Mar 2024 14:33:03 +0200 Subject: ACPI: scan: Introduce typedef:s for struct acpi_hotplug_context members Follow the struct acpi_device_ops approach and introduce typedef:s for the members. It makes code less verbose and more particular on what parameters we take or types we use. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 48 +++++++++++++++++------------------------------- drivers/acpi/scan.c | 5 ++--- include/acpi/acpi_bus.h | 13 ++++++++----- 3 files changed, 27 insertions(+), 39 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index a7c00ef78086..34affbda295e 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -88,43 +88,29 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, enum dock_callback_type cb_type) { struct acpi_device *adev = dd->adev; + acpi_hp_fixup fixup = NULL; + acpi_hp_uevent uevent = NULL; + acpi_hp_notify notify = NULL; acpi_lock_hp_context(); - if (!adev->hp) - goto out; - - if (cb_type == DOCK_CALL_FIXUP) { - void (*fixup)(struct acpi_device *); - - fixup = adev->hp->fixup; - if (fixup) { - acpi_unlock_hp_context(); - fixup(adev); - return; - } - } else if (cb_type == DOCK_CALL_UEVENT) { - void (*uevent)(struct acpi_device *, u32); - - uevent = adev->hp->uevent; - if (uevent) { - acpi_unlock_hp_context(); - uevent(adev, event); - return; - } - } else { - int (*notify)(struct acpi_device *, u32); - - notify = adev->hp->notify; - if (notify) { - acpi_unlock_hp_context(); - notify(adev, event); - return; - } + if (adev->hp) { + if (cb_type == DOCK_CALL_FIXUP) + fixup = adev->hp->fixup; + else if (cb_type == DOCK_CALL_UEVENT) + uevent = adev->hp->uevent; + else + notify = adev->hp->notify; } - out: acpi_unlock_hp_context(); + + if (fixup) + fixup(adev); + else if (uevent) + uevent(adev, event); + else if (notify) + notify(adev, event); } static struct dock_station *find_dock_station(acpi_handle handle) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b9a33364e553..f06d92b1183f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -73,8 +73,7 @@ void acpi_unlock_hp_context(void) void acpi_initialize_hp_context(struct acpi_device *adev, struct acpi_hotplug_context *hp, - int (*notify)(struct acpi_device *, u32), - void (*uevent)(struct acpi_device *, u32)) + acpi_hp_notify notify, acpi_hp_uevent uevent) { acpi_lock_hp_context(); hp->notify = notify; @@ -428,7 +427,7 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) } else if (adev->flags.hotplug_notify) { error = acpi_generic_hotplug_event(adev, src); } else { - int (*notify)(struct acpi_device *, u32); + acpi_hp_notify notify; acpi_lock_hp_context(); notify = adev->hp ? adev->hp->notify : NULL; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a6ced88a08f3..6f8cc4cc61be 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -144,11 +144,15 @@ struct acpi_scan_handler { * -------------------- */ +typedef int (*acpi_hp_notify) (struct acpi_device *, u32); +typedef void (*acpi_hp_uevent) (struct acpi_device *, u32); +typedef void (*acpi_hp_fixup) (struct acpi_device *); + struct acpi_hotplug_context { struct acpi_device *self; - int (*notify)(struct acpi_device *, u32); - void (*uevent)(struct acpi_device *, u32); - void (*fixup)(struct acpi_device *); + acpi_hp_notify notify; + acpi_hp_uevent uevent; + acpi_hp_fixup fixup; }; /* @@ -583,8 +587,7 @@ static inline void acpi_set_hp_context(struct acpi_device *adev, void acpi_initialize_hp_context(struct acpi_device *adev, struct acpi_hotplug_context *hp, - int (*notify)(struct acpi_device *, u32), - void (*uevent)(struct acpi_device *, u32)); + acpi_hp_notify notify, acpi_hp_uevent uevent); /* acpi_device.dev.bus == &acpi_bus_type */ extern const struct bus_type acpi_bus_type; -- cgit v1.2.3 From d4aa921eb85a74bf0502eff64f0b9e06fe17081b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Apr 2024 18:02:20 +0200 Subject: ACPI: scan: Avoid enumerating devices with clearly invalid _STA values The return value of _STA with the "present" bit unset and the "enabled" bit set is clearly invalid as per the ACPI specification, Section 6.3.7 "_STA (Device Status)", so make the ACPI device enumeration code disregard devices with such _STA return values. Also, because this implies that status.enabled will only be set if status.present is set too, acpi_device_is_enabled() can be modified to simply return the value of the former. Link: https://uefi.org/specs/ACPI/6.5/06_Device_Configuration.html#sta-device-status Link: https://lore.kernel.org/linux-acpi/88179311a503493099028c12ca37d430@huawei.com/ Suggested-by: Salil Mehta Signed-off-by: Rafael J. Wysocki Reviewed-by: Jonathan Cameron Reviewed-by: Sudeep Holla --- drivers/acpi/bus.c | 11 +++++++++++ drivers/acpi/scan.c | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d9fa730416f1..18d50448ae1c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -112,6 +112,17 @@ int acpi_bus_get_status(struct acpi_device *device) if (ACPI_FAILURE(status)) return -ENODEV; + if (!device->status.present && device->status.enabled) { + pr_info(FW_BUG "Device [%s] status [%08x]: not present and enabled\n", + device->pnp.bus_id, (u32)sta); + device->status.enabled = 0; + /* + * The status is clearly invalid, so clear the functional bit as + * well to avoid attempting to use the device. + */ + device->status.functional = 0; + } + acpi_set_device_status(device, sta); if (device->status.functional && !device->status.present) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 68f101323f53..e41fb5716bc0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1962,7 +1962,7 @@ bool acpi_device_is_present(const struct acpi_device *adev) bool acpi_device_is_enabled(const struct acpi_device *adev) { - return adev->status.present && adev->status.enabled; + return adev->status.enabled; } static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, -- cgit v1.2.3