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 <cezary.rojewski@intel.com> --- drivers/acpi/nhlt.c | 36 ++++++++++++++++----------------- include/acpi/actbl2.h | 22 ++++++++++----------- include/acpi/nhlt.h | 46 +++++++++++++++++++++---------------------- 3 files changed, 52 insertions(+), 52 deletions(-) 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 <linux/types.h> #include <acpi/nhlt.h> -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) { -- 2.25.1
ACPICA commit 0c7379eae2a0342bfc36d6b7db0bb90ad13a5a3e There are no users for the duplicated NHLT table components. Link: https://github.com/acpica/acpica/pull/890 Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> --- include/acpi/actbl2.h | 254 ------------------------------------------ 1 file changed, 254 deletions(-) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 8030a1743100..31a716a74340 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -1887,260 +1887,6 @@ struct nfit_device_handle { #define ACPI_NFIT_GET_NODE_ID(handle) \ (((handle) & ACPI_NFIT_NODE_ID_MASK) >> ACPI_NFIT_NODE_ID_OFFSET) -/******************************************************************************* - * - * NHLT - Non HD Audio Link Table - * - * Conforms to: Intel Smart Sound Technology NHLT Specification - * Version 0.8.1, January 2020. - * - ******************************************************************************/ - -/* Main table */ - -struct acpi_table_nhlt { - struct acpi_table_header header; /* Common ACPI table header */ - u8 endpoint_count; -}; - -struct acpi_nhlt_endpoint { - u32 descriptor_length; - u8 link_type; - u8 instance_id; - u16 vendor_id; - u16 device_id; - u16 revision_id; - u32 subsystem_id; - u8 device_type; - u8 direction; - u8 virtual_bus_id; -}; - -/* Types for link_type field above */ - -#define ACPI_NHLT_RESERVED_HD_AUDIO 0 -#define ACPI_NHLT_RESERVED_DSP 1 -#define ACPI_NHLT_PDM 2 -#define ACPI_NHLT_SSP 3 -#define ACPI_NHLT_RESERVED_SLIMBUS 4 -#define ACPI_NHLT_RESERVED_SOUNDWIRE 5 -#define ACPI_NHLT_TYPE_RESERVED 6 /* 6 and above are reserved */ - -/* All other values above are reserved */ - -/* Values for device_id field above */ - -#define ACPI_NHLT_PDM_DMIC 0xAE20 -#define ACPI_NHLT_BT_SIDEBAND 0xAE30 -#define ACPI_NHLT_I2S_TDM_CODECS 0xAE23 - -/* Values for device_type field above */ - -/* SSP Link */ - -#define ACPI_NHLT_LINK_BT_SIDEBAND 0 -#define ACPI_NHLT_LINK_FM 1 -#define ACPI_NHLT_LINK_MODEM 2 -/* 3 is reserved */ -#define ACPI_NHLT_LINK_SSP_ANALOG_CODEC 4 - -/* PDM Link */ - -#define ACPI_NHLT_PDM_ON_CAVS_1P8 0 -#define ACPI_NHLT_PDM_ON_CAVS_1P5 1 - -/* Values for Direction field above */ - -#define ACPI_NHLT_DIR_RENDER 0 -#define ACPI_NHLT_DIR_CAPTURE 1 -#define ACPI_NHLT_DIR_RENDER_LOOPBACK 2 -#define ACPI_NHLT_DIR_RENDER_FEEDBACK 3 -#define ACPI_NHLT_DIR_RESERVED 4 /* 4 and above are reserved */ - -struct acpi_nhlt_device_specific_config { - u32 capabilities_size; - u8 virtual_slot; - u8 config_type; -}; - -struct acpi_nhlt_device_specific_config_a { - u32 capabilities_size; - u8 virtual_slot; - u8 config_type; - u8 array_type; -}; - -/* Values for Config Type above */ - -#define ACPI_NHLT_CONFIG_TYPE_GENERIC 0x00 -#define ACPI_NHLT_CONFIG_TYPE_MIC_ARRAY 0x01 -#define ACPI_NHLT_CONFIG_TYPE_RENDER_FEEDBACK 0x03 -#define ACPI_NHLT_CONFIG_TYPE_RESERVED 0x04 /* 4 and above are reserved */ - -struct acpi_nhlt_device_specific_config_b { - u32 capabilities_size; -}; - -struct acpi_nhlt_device_specific_config_c { - u32 capabilities_size; - u8 virtual_slot; -}; - -struct acpi_nhlt_render_device_specific_config { - u32 capabilities_size; - u8 virtual_slot; -}; - -struct acpi_nhlt_wave_extensible { - u16 format_tag; - u16 channel_count; - u32 samples_per_sec; - u32 avg_bytes_per_sec; - u16 block_align; - u16 bits_per_sample; - u16 extra_format_size; - u16 valid_bits_per_sample; - u32 channel_mask; - u8 sub_format_guid[16]; -}; - -/* Values for channel_mask above */ - -#define ACPI_NHLT_SPKR_FRONT_LEFT 0x1 -#define ACPI_NHLT_SPKR_FRONT_RIGHT 0x2 -#define ACPI_NHLT_SPKR_FRONT_CENTER 0x4 -#define ACPI_NHLT_SPKR_LOW_FREQ 0x8 -#define ACPI_NHLT_SPKR_BACK_LEFT 0x10 -#define ACPI_NHLT_SPKR_BACK_RIGHT 0x20 -#define ACPI_NHLT_SPKR_FRONT_LEFT_OF_CENTER 0x40 -#define ACPI_NHLT_SPKR_FRONT_RIGHT_OF_CENTER 0x80 -#define ACPI_NHLT_SPKR_BACK_CENTER 0x100 -#define ACPI_NHLT_SPKR_SIDE_LEFT 0x200 -#define ACPI_NHLT_SPKR_SIDE_RIGHT 0x400 -#define ACPI_NHLT_SPKR_TOP_CENTER 0x800 -#define ACPI_NHLT_SPKR_TOP_FRONT_LEFT 0x1000 -#define ACPI_NHLT_SPKR_TOP_FRONT_CENTER 0x2000 -#define ACPI_NHLT_SPKR_TOP_FRONT_RIGHT 0x4000 -#define ACPI_NHLT_SPKR_TOP_BACK_LEFT 0x8000 -#define ACPI_NHLT_SPKR_TOP_BACK_CENTER 0x10000 -#define ACPI_NHLT_SPKR_TOP_BACK_RIGHT 0x20000 - -struct acpi_nhlt_format_config { - struct acpi_nhlt_wave_extensible format; - u32 capability_size; - u8 capabilities[]; -}; - -struct acpi_nhlt_formats_config { - u8 formats_count; -}; - -struct acpi_nhlt_device_specific_hdr { - u8 virtual_slot; - u8 config_type; -}; - -/* Types for config_type above */ - -#define ACPI_NHLT_GENERIC 0 -#define ACPI_NHLT_MIC 1 -#define ACPI_NHLT_RENDER 3 - -struct acpi_nhlt_mic_device_specific_config { - struct acpi_nhlt_device_specific_hdr device_config; - u8 array_type_ext; -}; - -/* Values for array_type_ext above */ - -#define ACPI_NHLT_ARRAY_TYPE_RESERVED 0x09 /* 9 and below are reserved */ -#define ACPI_NHLT_SMALL_LINEAR_2ELEMENT 0x0A -#define ACPI_NHLT_BIG_LINEAR_2ELEMENT 0x0B -#define ACPI_NHLT_FIRST_GEOMETRY_LINEAR_4ELEMENT 0x0C -#define ACPI_NHLT_PLANAR_LSHAPED_4ELEMENT 0x0D -#define ACPI_NHLT_SECOND_GEOMETRY_LINEAR_4ELEMENT 0x0E -#define ACPI_NHLT_VENDOR_DEFINED 0x0F -#define ACPI_NHLT_ARRAY_TYPE_MASK 0x0F -#define ACPI_NHLT_ARRAY_TYPE_EXT_MASK 0x10 - -#define ACPI_NHLT_NO_EXTENSION 0x0 -#define ACPI_NHLT_MIC_SNR_SENSITIVITY_EXT (1<<4) - -struct acpi_nhlt_vendor_mic_count { - u8 microphone_count; -}; - -struct acpi_nhlt_vendor_mic_config { - u8 type; - u8 panel; - u16 speaker_position_distance; /* mm */ - u16 horizontal_offset; /* mm */ - u16 vertical_offset; /* mm */ - u8 frequency_low_band; /* 5*Hz */ - u8 frequency_high_band; /* 500*Hz */ - u16 direction_angle; /* -180 - + 180 */ - u16 elevation_angle; /* -180 - + 180 */ - u16 work_vertical_angle_begin; /* -180 - + 180 with 2 deg step */ - u16 work_vertical_angle_end; /* -180 - + 180 with 2 deg step */ - u16 work_horizontal_angle_begin; /* -180 - + 180 with 2 deg step */ - u16 work_horizontal_angle_end; /* -180 - + 180 with 2 deg step */ -}; - -/* Values for Type field above */ - -#define ACPI_NHLT_MIC_OMNIDIRECTIONAL 0 -#define ACPI_NHLT_MIC_SUBCARDIOID 1 -#define ACPI_NHLT_MIC_CARDIOID 2 -#define ACPI_NHLT_MIC_SUPER_CARDIOID 3 -#define ACPI_NHLT_MIC_HYPER_CARDIOID 4 -#define ACPI_NHLT_MIC_8_SHAPED 5 -#define ACPI_NHLT_MIC_RESERVED6 6 /* 6 is reserved */ -#define ACPI_NHLT_MIC_VENDOR_DEFINED 7 -#define ACPI_NHLT_MIC_RESERVED 8 /* 8 and above are reserved */ - -/* Values for Panel field above */ - -#define ACPI_NHLT_MIC_POSITION_TOP 0 -#define ACPI_NHLT_MIC_POSITION_BOTTOM 1 -#define ACPI_NHLT_MIC_POSITION_LEFT 2 -#define ACPI_NHLT_MIC_POSITION_RIGHT 3 -#define ACPI_NHLT_MIC_POSITION_FRONT 4 -#define ACPI_NHLT_MIC_POSITION_BACK 5 -#define ACPI_NHLT_MIC_POSITION_RESERVED 6 /* 6 and above are reserved */ - -struct acpi_nhlt_vendor_mic_device_specific_config { - struct acpi_nhlt_mic_device_specific_config mic_array_device_config; - u8 number_of_microphones; - struct acpi_nhlt_vendor_mic_config mic_config[]; /* Indexed by number_of_microphones */ -}; - -/* Microphone SNR and Sensitivity extension */ - -struct acpi_nhlt_mic_snr_sensitivity_extension { - u32 SNR; - u32 sensitivity; -}; - -/* Render device with feedback */ - -struct acpi_nhlt_render_feedback_device_specific_config { - u8 feedback_virtual_slot; /* Render slot in case of capture */ - u16 feedback_channels; /* Informative only */ - u16 feedback_valid_bits_per_sample; -}; - -/* Non documented structures */ - -struct acpi_nhlt_device_info_count { - u8 structure_count; -}; - -struct acpi_nhlt_device_info { - u8 device_id[16]; - u8 device_instance_id; - u8 device_port_id; -}; - /******************************************************************************* * * NHLT - Non HDAudio Link Table -- 2.25.1
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 <cezary.rojewski@intel.com> --- drivers/acpi/Kconfig | 3 + drivers/acpi/Makefile | 1 + drivers/acpi/nhlt.c | 289 ++++++++++++++++++++++++++++++++++++++++++ include/acpi/nhlt.h | 181 ++++++++++++++++++++++++++ 4 files changed, 474 insertions(+) create mode 100644 drivers/acpi/nhlt.c create mode 100644 include/acpi/nhlt.h diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 3c3f8037ebed..c45a4238c5fd 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -484,6 +484,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 12ef8180d272..197e1e7154cb 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 <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#define pr_fmt(fmt) "ACPI: NHLT: " fmt + +#include <linux/acpi.h> +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/minmax.h> +#include <linux/printk.h> +#include <linux/types.h> +#include <acpi/nhlt.h> + +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); diff --git a/include/acpi/nhlt.h b/include/acpi/nhlt.h new file mode 100644 index 000000000000..7c394e7bc2bb --- /dev/null +++ b/include/acpi/nhlt.h @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2023-2024 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#ifndef __ACPI_NHLT_H__ +#define __ACPI_NHLT_H__ + +#include <linux/acpi.h> +#include <linux/kconfig.h> +#include <linux/overflow.h> +#include <linux/types.h> + +#define __acpi_nhlt_endpoint_config(ep) ((void *)((ep) + 1)) +#define __acpi_nhlt_config_caps(cfg) ((void *)((cfg) + 1)) + +/** + * acpi_nhlt_endpoint_fmtscfg - Get the formats configuration space. + * @ep: the endpoint to retrieve the space for. + * + * 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) +{ + struct acpi_nhlt_config *cfg = __acpi_nhlt_endpoint_config(ep); + + return (struct acpi_nhlt2_formats_config *)((u8 *)(cfg + 1) + cfg->capabilities_size); +} + +#define __acpi_nhlt_first_endpoint(tb) \ + ((void *)(tb + 1)) + +#define __acpi_nhlt_next_endpoint(ep) \ + ((void *)((u8 *)(ep) + (ep)->length)) + +#define __acpi_nhlt_get_endpoint(tb, ep, i) \ + ((i) ? __acpi_nhlt_next_endpoint(ep) : __acpi_nhlt_first_endpoint(tb)) + +#define __acpi_nhlt_first_fmtcfg(fmts) \ + ((void *)(fmts + 1)) + +#define __acpi_nhlt_next_fmtcfg(fmt) \ + ((void *)((u8 *)((fmt) + 1) + (fmt)->config.capabilities_size)) + +#define __acpi_nhlt_get_fmtcfg(fmts, fmt, i) \ + ((i) ? __acpi_nhlt_next_fmtcfg(fmt) : __acpi_nhlt_first_fmtcfg(fmts)) + +/* + * The for_each_nhlt_*() macros rely on an iterator to deal with the + * variable length of each endpoint structure and the possible presence + * of an OED-Config used by Windows only. + */ + +/** + * for_each_nhlt_endpoint - Iterate over endpoints in a NHLT table. + * @tb: the pointer to a NHLT table. + * @ep: the pointer to endpoint to use as loop cursor. + */ +#define for_each_nhlt_endpoint(tb, ep) \ + for (unsigned int __i = 0; \ + __i < (tb)->endpoints_count && \ + (ep = __acpi_nhlt_get_endpoint(tb, ep, __i)); \ + __i++) + +/** + * for_each_nhlt_fmtcfg - Iterate over format configurations. + * @fmts: the pointer to formats configuration space. + * @fmt: the pointer to format to use as loop cursor. + */ +#define for_each_nhlt_fmtcfg(fmts, fmt) \ + for (unsigned int __i = 0; \ + __i < (fmts)->formats_count && \ + (fmt = __acpi_nhlt_get_fmtcfg(fmts, fmt, __i)); \ + __i++) + +/** + * for_each_nhlt_endpoint_fmtcfg - Iterate over format configurations in an endpoint. + * @ep: the pointer to an endpoint. + * @fmt: the pointer to format to use as loop cursor. + */ +#define for_each_nhlt_endpoint_fmtcfg(ep, fmt) \ + for_each_nhlt_fmtcfg(acpi_nhlt_endpoint_fmtscfg(ep), fmt) + +#if IS_ENABLED(CONFIG_ACPI_NHLT) + +/* + * System-wide pointer to the first NHLT table. + * + * A sound driver may utilize acpi_nhlt_get/put_gbl_table() on its + * initialization and removal respectively to avoid excessive mapping + * and unmapping of the memory occupied by the table between streaming + * operations. + */ + +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, + 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, + int link_type, int dev_type, int dir, int bus_id); +struct acpi_nhlt2_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, + u16 ch, u32 rate, u16 vbps, u16 bps); +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 vpbs, u16 bps); +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 vpbs, u16 bps); +int acpi_nhlt_endpoint_mic_count(const struct acpi_nhlt2_endpoint *ep); + +#else /* !CONFIG_ACPI_NHLT */ + +static inline acpi_status acpi_nhlt_get_gbl_table(void) +{ + return AE_NOT_FOUND; +} + +static inline void acpi_nhlt_put_gbl_table(void) +{ +} + +static inline bool +acpi_nhlt_endpoint_match(const struct acpi_nhlt2_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, + 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, + 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, + 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) +{ + return 0; +} + +static inline struct acpi_nhlt2_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 * +acpi_nhlt_find_fmtcfg(int link_type, int dev_type, int dir, int bus_id, + u16 ch, u32 rate, u16 vpbs, u16 bps) +{ + return NULL; +} + +#endif /* CONFIG_ACPI_NHLT */ + +#endif /* __ACPI_NHLT_H__ */ -- 2.25.1
ACPICA commit 32260f5ce519e854546ce907fc0cc449e1fe51fe Non HDAudio Link Table (NHLT) is designed to separate hardware-related description (registers) from AudioDSP firmware-related one i.e.: pipelines and modules that together make up the audio stream on Intel DSPs. This task is important as same set of hardware registers can be used with different topologies and vice versa, same topology could be utilized with different set of hardware. As the hardware registers description is directly tied to specific platform, intention is to have such description part of low-level firmware e.g.: BIOS. The initial design has been provided in early Sky Lake (SKL) days. The audio architecture goes by the name cAVS. SKL is a representative of cAVS 1.5. The table helps describe endpoint capabilities ever since. While Raptor Lake (RPL) is the last of cAVS architecture - cAVS 2.5 to be precise - its successor, the ACE architecture which begun with Meteor Lake (MTL) inherited the design for all I2S and PDM configurations. These two configurations are the primary targets for NHLT table. Due to naming conflicts with existing code, several structs are named 'nhlt2' rather than 'nhlt'. Follow up changes clean this up once existing code has no users and is removed. Link: https://github.com/acpica/acpica/pull/912 Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> --- include/acpi/actbl2.h | 189 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 9775384d61c6..8030a1743100 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -2141,6 +2141,195 @@ struct acpi_nhlt_device_info { u8 device_port_id; }; +/******************************************************************************* + * + * NHLT - Non HDAudio Link Table + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_nhlt2 { + struct acpi_table_header header; /* Common ACPI table header */ + u8 endpoints_count; + /* + * struct acpi_nhlt_endpoint endpoints[]; + * struct acpi_nhlt_config oed_config; + */ +}; + +struct acpi_nhlt2_endpoint { + u32 length; + u8 link_type; + u8 instance_id; + u16 vendor_id; + u16 device_id; + u16 revision_id; + u32 subsystem_id; + u8 device_type; + u8 direction; + u8 virtual_bus_id; + /* + * struct acpi_nhlt_config device_config; + * struct acpi_nhlt_formats_config formats_config; + * struct acpi_nhlt_devices_info devices_info; + */ +}; + +/* + * Values for link_type field above + * + * Only types PDM and SSP are used + */ +#define ACPI_NHLT_LINKTYPE_HDA 0 +#define ACPI_NHLT_LINKTYPE_DSP 1 +#define ACPI_NHLT_LINKTYPE_PDM 2 +#define ACPI_NHLT_LINKTYPE_SSP 3 +#define ACPI_NHLT_LINKTYPE_SLIMBUS 4 +#define ACPI_NHLT_LINKTYPE_SDW 5 +#define ACPI_NHLT_LINKTYPE_UAOL 6 + +/* Values for device_id field above */ + +#define ACPI_NHLT_DEVICEID_DMIC 0xAE20 +#define ACPI_NHLT_DEVICEID_BT 0xAE30 +#define ACPI_NHLT_DEVICEID_I2S 0xAE34 + +/* Values for device_type field above */ + +/* + * Device types unique to endpoint of link_type=PDM + * + * Type PDM used for all SKL+ platforms + */ +#define ACPI_NHLT_DEVICETYPE_PDM 0 +#define ACPI_NHLT_DEVICETYPE_PDM_SKL 1 +/* Device types unique to endpoint of link_type=SSP */ +#define ACPI_NHLT_DEVICETYPE_BT 0 +#define ACPI_NHLT_DEVICETYPE_FM 1 +#define ACPI_NHLT_DEVICETYPE_MODEM 2 +#define ACPI_NHLT_DEVICETYPE_CODEC 4 + +/* Values for Direction field above */ + +#define ACPI_NHLT_DIR_RENDER 0 +#define ACPI_NHLT_DIR_CAPTURE 1 + +struct acpi_nhlt_config { + u32 capabilities_size; + u8 capabilities[]; +}; + +struct acpi_nhlt_gendevice_config { + u8 virtual_slot; + u8 config_type; +}; + +/* Values for config_type field above */ + +#define ACPI_NHLT_CONFIGTYPE_GENERIC 0 +#define ACPI_NHLT_CONFIGTYPE_MICARRAY 1 + +struct acpi_nhlt_micdevice_config { + u8 virtual_slot; + u8 config_type; + u8 array_type; +}; + +/* Values for array_type field above */ + +#define ACPI_NHLT_ARRAYTYPE_LINEAR2_SMALL 0xA +#define ACPI_NHLT_ARRAYTYPE_LINEAR2_BIG 0xB +#define ACPI_NHLT_ARRAYTYPE_LINEAR4_GEO1 0xC +#define ACPI_NHLT_ARRAYTYPE_PLANAR4_LSHAPED 0xD +#define ACPI_NHLT_ARRAYTYPE_LINEAR4_GEO2 0xE +#define ACPI_NHLT_ARRAYTYPE_VENDOR 0xF + +struct acpi_nhlt2_vendor_mic_config { + u8 type; + u8 panel; + u16 speaker_position_distance; /* mm */ + u16 horizontal_offset; /* mm */ + u16 vertical_offset; /* mm */ + u8 frequency_low_band; /* 5*Hz */ + u8 frequency_high_band; /* 500*Hz */ + u16 direction_angle; /* -180 - +180 */ + u16 elevation_angle; /* -180 - +180 */ + u16 work_vertical_angle_begin; /* -180 - +180 with 2 deg step */ + u16 work_vertical_angle_end; /* -180 - +180 with 2 deg step */ + u16 work_horizontal_angle_begin; /* -180 - +180 with 2 deg step */ + u16 work_horizontal_angle_end; /* -180 - +180 with 2 deg step */ +}; + +/* Values for Type field above */ + +#define ACPI_NHLT_MICTYPE_OMNIDIRECTIONAL 0 +#define ACPI_NHLT_MICTYPE_SUBCARDIOID 1 +#define ACPI_NHLT_MICTYPE_CARDIOID 2 +#define ACPI_NHLT_MICTYPE_SUPERCARDIOID 3 +#define ACPI_NHLT_MICTYPE_HYPERCARDIOID 4 +#define ACPI_NHLT_MICTYPE_8SHAPED 5 +#define ACPI_NHLT_MICTYPE_RESERVED 6 +#define ACPI_NHLT_MICTYPE_VENDORDEFINED 7 + +/* Values for Panel field above */ + +#define ACPI_NHLT_MICLOCATION_TOP 0 +#define ACPI_NHLT_MICLOCATION_BOTTOM 1 +#define ACPI_NHLT_MICLOCATION_LEFT 2 +#define ACPI_NHLT_MICLOCATION_RIGHT 3 +#define ACPI_NHLT_MICLOCATION_FRONT 4 +#define ACPI_NHLT_MICLOCATION_REAR 5 + +struct acpi_nhlt_vendor_micdevice_config { + u8 virtual_slot; + u8 config_type; + u8 array_type; + u8 mics_count; + struct acpi_nhlt2_vendor_mic_config mics[]; +}; + +union acpi_nhlt_device_config { + u8 virtual_slot; + struct acpi_nhlt_gendevice_config gen; + struct acpi_nhlt_micdevice_config mic; + struct acpi_nhlt_vendor_micdevice_config vendor_mic; +}; + +/* Inherited from Microsoft's WAVEFORMATEXTENSIBLE. */ +struct acpi_nhlt2_wave_formatext { + u16 format_tag; + u16 channel_count; + u32 samples_per_sec; + u32 avg_bytes_per_sec; + u16 block_align; + u16 bits_per_sample; + u16 extra_format_size; + u16 valid_bits_per_sample; + u32 channel_mask; + u8 subformat[16]; +}; + +struct acpi_nhlt2_format_config { + struct acpi_nhlt2_wave_formatext format; + struct acpi_nhlt_config config; +}; + +struct acpi_nhlt2_formats_config { + u8 formats_count; + struct acpi_nhlt2_format_config formats[]; +}; + +struct acpi_nhlt2_device_info { + u8 id[16]; + u8 instance_id; + u8 port_id; +}; + +struct acpi_nhlt_devices_info { + u8 devices_count; + struct acpi_nhlt2_device_info devices[]; +}; + /******************************************************************************* * * PCCT - Platform Communications Channel Table (ACPI 5.0) -- 2.25.1
The goal of this patchset is to refactor existing interface of Non HDAudio Link Table (NHLT) table so it becomes useful for the Intel AudioDSP sound-drivers. Right now the useful duplicate resides in sound/hda/intel-nhlt.c. The API takes form of query functions that help access device or audio-format configuration space. This information can be then utilized by a sound-driver to perform necessary programming and facilitate streaming over I2S/PDM interfaces. Once the series is merged, existing sound-drivers can move from utilizing sound/hda/intel-nhlt.c to this very code and ultimately the former file can be removed. Paired with equivalent change on ACPICA [1]. - Non HDAudio Link Table (NHLT) is designed to separate hardware-related description (registers) from AudioDSP firmware-related one i.e.: pipelines and modules that together make up the audio stream on Intel DSPs. This task is important as same set of hardware registers can be used with different topologies and vice versa, same topology could be utilized with different set of hardware. As the hardware registers description is directly tied to specific platform, intention is to have such description part of low-level firmware e.g.: BIOS. The initial design has been provided in early Sky Lake (SKL) days. The audio architecture goes by the name cAVS. SKL is a representative of cAVS 1.5. The table helps describe endpoint capabilities ever since. While Raptor Lake (RPL) is the last of cAVS architecture - cAVS 2.5 to be precise - its successor, the ACE architecture which begun with Meteor Lake (MTL) inherited the design for all I2S and PDM configurations. These two configurations are the primary targets for NHLT table. Due to naming conflicts with existing code, several structs are named 'nhlt2' rather than 'nhlt'. Last patch cleans the situation up. Changes in v8: - fixed file headers for all added files - commit messages now carry links to ACPICA PRs and relevant commits ids Changes in v7: - added missing headers to nhlt.c/nhlt.h as suggested by Andy Changes in v6: - added comments explaining usage of LINKTYPE and DEVICETYPE constants Changes in v5: - split find_endpoint/fmtcfg() into tb-less and tb-aware variants. This is to make API scale with 2+ NHLTs and removes the need for acpi_gbl_nhlt to be accessible globally. - acpi_nhlt_device_config now a union that encompasses all device_config types. Changes in v4: - relocated ACPI_NHLT kconfig in the drivers/acpi/Kconfig to a more relevant area within the file Changes in v3: - uncapitalized acpi_gbl_NHLT - fixed compilation problems when CONFIG_ACPI_NHLT is disabled - dropped Reviewed-by tags in the 2/4 patch due to above, those were not one-line changes Changes in v2: - minor wording improvements in kernel-doc for patch 3/4 - dropped parentheses around loop cursors in for_each_nhlt_*() macros - readability improvements in compound if-statements within query functions - dropped NULL-checks in query functions [1]: https://github.com/acpica/acpica/pull/912 Cezary Rojewski (4): ACPI: NHLT: Reintroduce types the table consists of ACPI: NHLT: Introduce API for the table ACPI: NHLT: Drop redundant types ACPI: NHLT: Streamline struct naming drivers/acpi/Kconfig | 3 + drivers/acpi/Makefile | 1 + drivers/acpi/nhlt.c | 289 ++++++++++++++++++++++++++++++++++++++++ include/acpi/actbl2.h | 299 +++++++++++++++++------------------------- include/acpi/nhlt.h | 181 +++++++++++++++++++++++++ 5 files changed, 591 insertions(+), 182 deletions(-) create mode 100644 drivers/acpi/nhlt.c create mode 100644 include/acpi/nhlt.h -- 2.25.1
On Mon, Mar 18, 2024 at 11:40:34AM -0700, Drew Fustini wrote: > On Thu, Feb 08, 2024 at 09:14:11AM +0530, Sunil V L wrote: > > This series enables the support for "Collaborative Processor Performance > > Control (CPPC) on ACPI based RISC-V platforms. It depends on the > > encoding of CPPC registers as defined in RISC-V FFH spec [2]. > > > > CPPC is described in the ACPI spec [1]. RISC-V FFH spec required to > > enable this, is available at [2]. > > > > [1] - https://uefi.org/specs/ACPI/6.5/08_Processor_Configuration_and_Control.html#collaborative-processor-performance-control > > [2] - https://github.com/riscv-non-isa/riscv-acpi-ffh/releases/download/v1.0.0/riscv-ffh.pdf > > > > The series is based on the LPI support series. > > Based-on: 20240118062930.245937-1-sunilvl@ventanamicro.com > > (https://lore.kernel.org/lkml/20240118062930.245937-1-sunilvl@ventanamicro.com/) > > Should the https://github.com/vlsunil/qemu/tree/lpi_exp branch also be > used for this CPPC series too? I noticed the ventanamicro qemu repo has a dev-upstream branch [1] which contains 4bb6ba4d0fb9 ("riscv/virt: acpi: Enable CPPC - _CPC and _PSD"). I've built that but I still see 'SBI CPPC extension NOT detected!!' in the Linux boot log. I'm using upstream opensbi. It seems that sbi_cppc_probe() fails because cppc_dev is not set. Nothing in the upstream opensbi repo seems to call sbi_cppc_set_device(), so I am uncertain how it is possible for it to work. Is there an opensbi branch I should be using? Thanks, Drew [1] https://github.com/ventanamicro/qemu/tree/dev-upstream
This makes it possible to support (and/or test) a few drivers that originates from DT World on the x86-64 platform. Originally, those drivers using the of_device_get_match_data() function to get match data. For example, drivers/gpu/drm/bridge/simple-bridge.c and drivers/gpu/drm/bridge/display-connector.c. Those drivers works very well in the DT world, however, there is no counterpart to of_device_get_match_data() when porting them to the x86 platform, because x86 CPUs lack DT support. By replacing it with device_get_match_data() and creating a software graph that mimics the OF graph, everything else works fine, except that there isn't an out-of-box replacement for the of_device_get_match_data() function. Because the software node backend of the fwnode framework lacks an implementation for the device_get_match_data callback. Implement device_get_match_data fwnode callback fwnode callback to fill this gap. Device drivers or platform setup codes are expected to provide a "compatible" string property. The value of this string property is used to match against the compatible entries in the of_device_id table. Which is consistent with the original usage style. Signed-off-by: Sui Jingfeng <sui.jingfeng@linux.dev> --- drivers/base/swnode.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 36512fb75a20..3670094592f2 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -8,6 +8,7 @@ #include <linux/device.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/slab.h> @@ -379,6 +380,30 @@ static void software_node_put(struct fwnode_handle *fwnode) kobject_put(&swnode->kobj); } +static const void * +software_node_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) +{ + struct swnode *swnode = to_swnode(fwnode); + const struct of_device_id *matches = dev->driver->of_match_table; + const char *val = NULL; + int ret; + + ret = property_entry_read_string_array(swnode->node->properties, + "compatible", &val, 1); + if (ret < 0 || !val) + return NULL; + + while (matches && matches->compatible[0]) { + if (!strcmp(matches->compatible, val)) + return matches->data; + + matches++; + } + + return NULL; +} + static bool software_node_property_present(const struct fwnode_handle *fwnode, const char *propname) { @@ -665,6 +690,7 @@ software_node_graph_parse_endpoint(const struct fwnode_handle *fwnode, static const struct fwnode_operations software_node_ops = { .get = software_node_get, .put = software_node_put, + .device_get_match_data = software_node_get_match_data, .property_present = software_node_property_present, .property_read_int_array = software_node_read_int_array, .property_read_string_array = software_node_read_string_array, -- 2.34.1
On 18.03.24 14:30:11, Dan Williams wrote:
> Robert Richter wrote:
> > The CEDT contains similar entries as the SRAT. For diagnostic reasons
> > print the CEDT same style as the SRAT.
>
> I will defer to Rafael here, but with acpica-tools, cxl-cli, and
> /proc/iomem is there much value to adding this to the boot-up logs by
> default?
Compared to the number of SRAT printks there are just a few CEDT
entries. I have added it as CEDT and SRAT entries have the similar
effect to NUMA, so diagnostics should be at the same level.
Thanks,
-Robert
Hi Dan, thanks for the quick review. Yes, this is the 'old' patch. But only the subject was corrected. I will send a v2 anyway. See below. On 18.03.24 14:26:41, Dan Williams wrote: > Robert Richter wrote: > > With kconfig option NUMA_KEEP_MEMINFO disabled the SRAT lookup done > > with numa_fill_memblks() fails returning NUMA_NO_MEMBLK (-1). An > > existing SRAT memory range cannot be found for a CFMWS address range. > > This causes the addition of a duplicate numa_memblk with a different > > node id and a subsequent page fault and kernel crash during boot. > > > > Note that the issue was initially introduced with [1]. But since > > phys_to_target_node() was originally used that returned the valid node > > 0, an additional numa_memblk was not added. Though, the node id was > > wrong too. > > > > Fix this by enabling NUMA_KEEP_MEMINFO for x86 with ACPI and NUMA > > enabled. > > > > [1] fd49f99c1809 ("ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT") > > > > Fixes: 8f1004679987 ("ACPI/NUMA: Apply SRAT proximity domain to entire CFMWS window") > > Cc: Derick Marks <derick.w.marks@intel.com> > > Cc: Dan Williams <dan.j.williams@intel.com> > > Cc: Alison Schofield <alison.schofield@intel.com> > > Signed-off-by: Robert Richter <rrichter@amd.com> > > --- > > drivers/acpi/numa/Kconfig | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/drivers/acpi/numa/Kconfig b/drivers/acpi/numa/Kconfig > > index 849c2bd820b9..2f4ac6ac6768 100644 > > --- a/drivers/acpi/numa/Kconfig > > +++ b/drivers/acpi/numa/Kconfig > > @@ -3,6 +3,7 @@ config ACPI_NUMA > > bool "NUMA support" > > depends on NUMA > > depends on (X86 || ARM64 || LOONGARCH) > > + select NUMA_KEEP_MEMINFO if X86 > > default y if ARM64 > > A fix is needed, yes, but this is the wrong one. NUMA_KEEP_MEMINFO is > only about marking numa_meminfo data as not "__init". Since > numa_fill_memblks() *is* an __init function, it should have no > dependency on NUMA_KEEP_MEMINFO. Right, the option is about just keeping it in non-init mem, but the parsing is durint __init. Will take a look. > > The fix here involves moving the definition of numa_fill_memblks() out > of the "#ifdef CONFIG_NUMA_KEEP_MEMINFO" in > arch/x86/include/asm/sparsemem.h so that it does not fallback to the > default definition in include/linux/numa.h. > > It should also be the case that cxl_acpi needs this: > > diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig > index 67998dbd1d46..1bf25185c35b 100644 > --- a/drivers/cxl/Kconfig > +++ b/drivers/cxl/Kconfig > @@ -6,6 +6,7 @@ menuconfig CXL_BUS > select FW_UPLOAD > select PCI_DOE > select FIRMWARE_TABLE > + select NUMA_KEEP_MEMINFO if NUMA Ok, will take a look here too. Thanks, -Robert > help > CXL is a bus that is electrically compatible with PCI Express, but > layers three protocols on that signalling (CXL.io, CXL.cache, and
Robert Richter wrote:
> On 18.03.24 22:09:00, Robert Richter wrote:
> > With kconfig option NUMA_KEEP_MEMINFO disabled the SRAT lookup done
> > with numa_fill_memblks() fails returning NUMA_NO_MEMBLK (-1). An
> > existing SRAT memory range cannot be found for a CFMWS address range.
> > This causes the addition of a duplicate numa_memblk with a different
> > node id and a subsequent page fault and kernel crash during boot.
> >
> > Note that the issue was initially introduced with [1]. But since
> > phys_to_target_node() was originally used that returned the valid node
> > 0, an additional numa_memblk was not added. Though, the node id was
> > wrong too.
> >
> > Fix this by enabling NUMA_KEEP_MEMINFO for x86 with ACPI and NUMA
> > enabled.
> >
> > [1] fd49f99c1809 ("ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT")
> >
> > Fixes: 8f1004679987 ("ACPI/NUMA: Apply SRAT proximity domain to entire CFMWS window")
> > Cc: Derick Marks <derick.w.marks@intel.com>
> > Cc: Dan Williams <dan.j.williams@intel.com>
> > Cc: Alison Schofield <alison.schofield@intel.com>
> > Signed-off-by: Robert Richter <rrichter@amd.com>
>
> This patch should be dropped in favor of the other 1/3 patch, it is a
> leftover.
What "other" patch? Did I respond to the wrong one?
Robert Richter wrote:
> The CEDT contains similar entries as the SRAT. For diagnostic reasons
> print the CEDT same style as the SRAT.
I will defer to Rafael here, but with acpica-tools, cxl-cli, and
/proc/iomem is there much value to adding this to the boot-up logs by
default?
Robert Richter wrote: > With kconfig option NUMA_KEEP_MEMINFO disabled the SRAT lookup done > with numa_fill_memblks() fails returning NUMA_NO_MEMBLK (-1). An > existing SRAT memory range cannot be found for a CFMWS address range. > This causes the addition of a duplicate numa_memblk with a different > node id and a subsequent page fault and kernel crash during boot. > > Note that the issue was initially introduced with [1]. But since > phys_to_target_node() was originally used that returned the valid node > 0, an additional numa_memblk was not added. Though, the node id was > wrong too. > > Fix this by enabling NUMA_KEEP_MEMINFO for x86 with ACPI and NUMA > enabled. > > [1] fd49f99c1809 ("ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT") > > Fixes: 8f1004679987 ("ACPI/NUMA: Apply SRAT proximity domain to entire CFMWS window") > Cc: Derick Marks <derick.w.marks@intel.com> > Cc: Dan Williams <dan.j.williams@intel.com> > Cc: Alison Schofield <alison.schofield@intel.com> > Signed-off-by: Robert Richter <rrichter@amd.com> > --- > drivers/acpi/numa/Kconfig | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/acpi/numa/Kconfig b/drivers/acpi/numa/Kconfig > index 849c2bd820b9..2f4ac6ac6768 100644 > --- a/drivers/acpi/numa/Kconfig > +++ b/drivers/acpi/numa/Kconfig > @@ -3,6 +3,7 @@ config ACPI_NUMA > bool "NUMA support" > depends on NUMA > depends on (X86 || ARM64 || LOONGARCH) > + select NUMA_KEEP_MEMINFO if X86 > default y if ARM64 A fix is needed, yes, but this is the wrong one. NUMA_KEEP_MEMINFO is only about marking numa_meminfo data as not "__init". Since numa_fill_memblks() *is* an __init function, it should have no dependency on NUMA_KEEP_MEMINFO. The fix here involves moving the definition of numa_fill_memblks() out of the "#ifdef CONFIG_NUMA_KEEP_MEMINFO" in arch/x86/include/asm/sparsemem.h so that it does not fallback to the default definition in include/linux/numa.h. It should also be the case that cxl_acpi needs this: diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig index 67998dbd1d46..1bf25185c35b 100644 --- a/drivers/cxl/Kconfig +++ b/drivers/cxl/Kconfig @@ -6,6 +6,7 @@ menuconfig CXL_BUS select FW_UPLOAD select PCI_DOE select FIRMWARE_TABLE + select NUMA_KEEP_MEMINFO if NUMA help CXL is a bus that is electrically compatible with PCI Express, but layers three protocols on that signalling (CXL.io, CXL.cache, and
On 18.03.24 22:09:00, Robert Richter wrote:
> With kconfig option NUMA_KEEP_MEMINFO disabled the SRAT lookup done
> with numa_fill_memblks() fails returning NUMA_NO_MEMBLK (-1). An
> existing SRAT memory range cannot be found for a CFMWS address range.
> This causes the addition of a duplicate numa_memblk with a different
> node id and a subsequent page fault and kernel crash during boot.
>
> Note that the issue was initially introduced with [1]. But since
> phys_to_target_node() was originally used that returned the valid node
> 0, an additional numa_memblk was not added. Though, the node id was
> wrong too.
>
> Fix this by enabling NUMA_KEEP_MEMINFO for x86 with ACPI and NUMA
> enabled.
>
> [1] fd49f99c1809 ("ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT")
>
> Fixes: 8f1004679987 ("ACPI/NUMA: Apply SRAT proximity domain to entire CFMWS window")
> Cc: Derick Marks <derick.w.marks@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Cc: Alison Schofield <alison.schofield@intel.com>
> Signed-off-by: Robert Richter <rrichter@amd.com>
This patch should be dropped in favor of the other 1/3 patch, it is a
leftover.
Thanks,
-Robert
With the removal of the Itanium architecture [1] the last architecture dependent functions: acpi_numa_slit_init(), acpi_numa_memory_affinity_init() were removed. Remove its remainings in the header files too an make them static. [1] cf8e8658100d arch: Remove Itanium (IA-64) architecture Signed-off-by: Robert Richter <rrichter@amd.com> --- drivers/acpi/numa/srat.c | 68 +++++++++++++--------------------------- include/linux/acpi.h | 5 --- 2 files changed, 21 insertions(+), 52 deletions(-) diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index 50ae8557e8d1..910609a9754b 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -208,16 +208,21 @@ int __init srat_disabled(void) return acpi_numa < 0; } -#if defined(CONFIG_X86) || defined(CONFIG_ARM64) || defined(CONFIG_LOONGARCH) /* * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for * I/O localities since SRAT does not list them. I/O localities are * not supported at this point. */ -void __init acpi_numa_slit_init(struct acpi_table_slit *slit) +static int __init acpi_parse_slit(struct acpi_table_header *table) { + struct acpi_table_slit *slit = (struct acpi_table_slit *)table; int i, j; + if (!slit_valid(slit)) { + pr_info("SLIT table looks invalid. Not used.\n"); + return -EINVAL; + } + for (i = 0; i < slit->locality_count; i++) { const int from_node = pxm_to_node(i); @@ -234,19 +239,25 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) slit->entry[slit->locality_count * i + j]); } } + + return 0; } -/* - * Default callback for parsing of the Proximity Domain <-> Memory - * Area mappings - */ -int __init -acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) +static int __initdata parsed_numa_memblks; + +static int __init +acpi_parse_memory_affinity(union acpi_subtable_headers * header, + const unsigned long table_end) { + struct acpi_srat_mem_affinity *ma; u64 start, end; u32 hotpluggable; int node, pxm; + ma = (struct acpi_srat_mem_affinity *)header; + + acpi_table_print_srat_entry(&header->common); + if (srat_disabled()) goto out_err; if (ma->header.length < sizeof(struct acpi_srat_mem_affinity)) { @@ -293,6 +304,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1)); + parsed_numa_memblks++; + return 0; out_err_bad_srat: bad_srat(); @@ -448,27 +461,6 @@ static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, (*fake_pxm)++; return 0; } -#else -static inline void acpi_table_print_cedt(void) {} -static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, - void *arg, const unsigned long table_end) -{ - return 0; -} -#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */ - -static int __init acpi_parse_slit(struct acpi_table_header *table) -{ - struct acpi_table_slit *slit = (struct acpi_table_slit *)table; - - if (!slit_valid(slit)) { - pr_info("SLIT table looks invalid. Not used.\n"); - return -EINVAL; - } - acpi_numa_slit_init(slit); - - return 0; -} void __init __weak acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) @@ -559,24 +551,6 @@ acpi_parse_gi_affinity(union acpi_subtable_headers *header, } #endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */ -static int __initdata parsed_numa_memblks; - -static int __init -acpi_parse_memory_affinity(union acpi_subtable_headers * header, - const unsigned long end) -{ - struct acpi_srat_mem_affinity *memory_affinity; - - memory_affinity = (struct acpi_srat_mem_affinity *)header; - - acpi_table_print_srat_entry(&header->common); - - /* let architecture-dependent part to do it */ - if (!acpi_numa_memory_affinity_init(memory_affinity)) - parsed_numa_memblks++; - return 0; -} - static int __init acpi_parse_srat(struct acpi_table_header *table) { struct acpi_table_srat *srat = (struct acpi_table_srat *)table; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 2a7c4b90d589..5f6472a7997c 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -242,9 +242,6 @@ static inline bool acpi_gicc_is_usable(struct acpi_madt_generic_interrupt *gicc) return gicc->flags & ACPI_MADT_ENABLED; } -/* the following numa functions are architecture-dependent */ -void acpi_numa_slit_init (struct acpi_table_slit *slit); - #if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); #else @@ -267,8 +264,6 @@ static inline void acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) { } #endif -int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); - #ifndef PHYS_CPUID_INVALID typedef u32 phys_cpuid_t; #define PHYS_CPUID_INVALID (phys_cpuid_t)(-1) -- 2.39.2
The CEDT contains similar entries as the SRAT. For diagnostic reasons print the CEDT same style as the SRAT. Signed-off-by: Robert Richter <rrichter@amd.com> --- drivers/acpi/numa/srat.c | 112 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index e45e64993c50..50ae8557e8d1 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -300,6 +300,114 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) return -EINVAL; } +static int __init +__acpi_table_print_cedt_entry(union acpi_subtable_headers *__header, + void *arg, const unsigned long table_end) +{ + struct acpi_cedt_header *header = (struct acpi_cedt_header *)__header; + + switch (header->type) { + case ACPI_CEDT_TYPE_CHBS: + { + struct acpi_cedt_chbs *p = + (struct acpi_cedt_chbs *)header; + + if (header->length < sizeof(struct acpi_cedt_chbs)) { + pr_warn("CEDT: unsupported CHBS entry: size %d\n", + header->length); + break; + } + + pr_info("CEDT: CHBS (0x%llx length 0x%llx uid %lu) %s (%d)\n", + (unsigned long long)p->base, + (unsigned long long)p->length, + (unsigned long)p->uid, + (p->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) ? + "cxl11" : + (p->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20) ? + "cxl20" : + "unsupported version", + p->cxl_version); + } + break; + case ACPI_CEDT_TYPE_CFMWS: + { + struct acpi_cedt_cfmws *p = + (struct acpi_cedt_cfmws *)header; + int eiw_to_ways[] = {1, 2, 4, 8, 16, 3, 6, 12}; + int targets = -1; + + if (header->length < sizeof(struct acpi_cedt_cfmws)) { + pr_warn("CEDT: unsupported CFMWS entry: size %d\n", + header->length); + break; + } + + if (p->interleave_ways < ARRAY_SIZE(eiw_to_ways)) + targets = eiw_to_ways[p->interleave_ways]; + if (header->length < struct_size( + p, interleave_targets, targets)) + targets = -1; + + pr_info("CEDT: CFMWS (0x%llx length 0x%llx) with %d target%s", + (unsigned long long)p->base_hpa, + (unsigned long long)p->window_size, + targets, targets > 1 ? "s" : ""); + for (int i = 0; i < targets; i++) + pr_cont("%s%lu", i ? ", " : " (", + (unsigned long)p->interleave_targets[i]); + pr_cont("%s%s%s%s%s%s\n", + targets > 0 ? ")" : "", + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE2) ? + " type2" : "", + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE3) ? + " type3" : "", + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE) ? + " volatile" : "", + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM) ? + " pmem" : "", + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED) ? + " fixed" : ""); + } + break; + case ACPI_CEDT_TYPE_CXIMS: + { + struct acpi_cedt_cxims *p = + (struct acpi_cedt_cxims *)header; + + if (header->length < sizeof(struct acpi_cedt_cxims)) { + pr_warn("CEDT: unsupported CXIMS entry: size %d\n", + header->length); + break; + } + + pr_info("CEDT: CXIMS (hbig %u nr_xormaps %u)\n", + (unsigned int)p->hbig, + (unsigned int)p->nr_xormaps); + } + break; + default: + pr_warn("CEDT: Found unsupported entry (type = 0x%x)\n", + header->type); + break; + } + + return 0; +} + +static void __init acpi_table_print_cedt_entry(enum acpi_cedt_type id) +{ + acpi_table_parse_cedt(id, __acpi_table_print_cedt_entry, NULL); +} + +static void __init acpi_table_print_cedt(void) +{ + /* Print only implemented CEDT types */ + acpi_table_print_cedt_entry(ACPI_CEDT_TYPE_CHBS); + acpi_table_print_cedt_entry(ACPI_CEDT_TYPE_CFMWS); + acpi_table_print_cedt_entry(ACPI_CEDT_TYPE_CXIMS); +} + static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, void *arg, const unsigned long table_end) { @@ -341,6 +449,7 @@ static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, return 0; } #else +static inline void acpi_table_print_cedt(void) {} static int __init acpi_parse_cfmws(union acpi_subtable_headers *header, void *arg, const unsigned long table_end) { @@ -526,6 +635,9 @@ int __init acpi_numa_init(void) /* SLIT: System Locality Information Table */ acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); + /* CEDT: CXL Early Discovery Table */ + acpi_table_print_cedt(); + /* * CXL Fixed Memory Window Structures (CFMWS) must be parsed * after the SRAT. Create NUMA Nodes for CXL memory ranges that -- 2.39.2
With kconfig option NUMA_KEEP_MEMINFO disabled the SRAT lookup done with numa_fill_memblks() fails returning NUMA_NO_MEMBLK (-1). An existing SRAT memory range cannot be found for a CFMWS address range. This causes the addition of a duplicate numa_memblk with a different node id and a subsequent page fault and kernel crash during boot. Note that the issue was initially introduced with [1]. But since phys_to_target_node() was originally used that returned the valid node 0, an additional numa_memblk was not added. Though, the node id was wrong too. Fix this by enabling NUMA_KEEP_MEMINFO for x86 with ACPI and NUMA enabled. [1] fd49f99c1809 ("ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT") Fixes: 8f1004679987 ("ACPI/NUMA: Apply SRAT proximity domain to entire CFMWS window") Cc: Derick Marks <derick.w.marks@intel.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Alison Schofield <alison.schofield@intel.com> Signed-off-by: Robert Richter <rrichter@amd.com> --- drivers/acpi/numa/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/numa/Kconfig b/drivers/acpi/numa/Kconfig index 849c2bd820b9..2f4ac6ac6768 100644 --- a/drivers/acpi/numa/Kconfig +++ b/drivers/acpi/numa/Kconfig @@ -3,6 +3,7 @@ config ACPI_NUMA bool "NUMA support" depends on NUMA depends on (X86 || ARM64 || LOONGARCH) + select NUMA_KEEP_MEMINFO if X86 default y if ARM64 config ACPI_HMAT -- 2.39.2
With kconfig option NUMA_KEEP_MEMINFO disabled the SRAT lookup done with numa_fill_memblks() fails returning NUMA_NO_MEMBLK (-1). An existing SRAT memory range cannot be found for a CFMWS address range. This causes the addition of a duplicate numa_memblk with a different node id and a subsequent page fault and kernel crash during boot. Note that the issue was initially introduced with [1]. But since phys_to_target_node() was originally used that returned the valid node 0, an additional numa_memblk was not added. Though, the node id was wrong too. Fix this by enabling NUMA_KEEP_MEMINFO for x86 with ACPI and NUMA enabled. [1] fd49f99c1809 ("ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT") Fixes: 8f1004679987 ("ACPI/NUMA: Apply SRAT proximity domain to entire CFMWS window") Cc: Derick Marks <derick.w.marks@intel.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Alison Schofield <alison.schofield@intel.com> Signed-off-by: Robert Richter <rrichter@amd.com> --- drivers/acpi/numa/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/numa/Kconfig b/drivers/acpi/numa/Kconfig index 849c2bd820b9..2f4ac6ac6768 100644 --- a/drivers/acpi/numa/Kconfig +++ b/drivers/acpi/numa/Kconfig @@ -3,6 +3,7 @@ config ACPI_NUMA bool "NUMA support" depends on NUMA depends on (X86 || ARM64 || LOONGARCH) + select NUMA_KEEP_MEMINFO if X86 default y if ARM64 config ACPI_HMAT -- 2.39.2
Some fixes and updates for SRAT/CEDT parsing code. Patches can be applied individually and are independent. First patch fixes a page fault during boot. It should be marked stable. 2nd patch adds diagnostic printouts for CEDT. 3rd patch removes architectural code no longer needed. Robert Richter (3): x86/numa: Fix SRAT lookup of CFMWS ranges with numa_fill_memblks() ACPI/NUMA: Print CXL Early Discovery Table (CEDT) ACPI/NUMA: Remove architecture dependent remainings drivers/acpi/numa/Kconfig | 1 + drivers/acpi/numa/srat.c | 178 ++++++++++++++++++++++++++++---------- include/linux/acpi.h | 5 -- 3 files changed, 133 insertions(+), 51 deletions(-) -- 2.39.2
I'm working on V3. Thanks for Ying's feedback. cc: sthanneeru@micron.com On Thu, Mar 14, 2024 at 12:54 AM Huang, Ying <ying.huang@intel.com> wrote: > > "Ho-Ren (Jack) Chuang" <horenchuang@bytedance.com> writes: > > > On Tue, Mar 12, 2024 at 2:21 AM Huang, Ying <ying.huang@intel.com> wrote: > >> > >> "Ho-Ren (Jack) Chuang" <horenchuang@bytedance.com> writes: > >> > >> > The current implementation treats emulated memory devices, such as > >> > CXL1.1 type3 memory, as normal DRAM when they are emulated as normal memory > >> > (E820_TYPE_RAM). However, these emulated devices have different > >> > characteristics than traditional DRAM, making it important to > >> > distinguish them. Thus, we modify the tiered memory initialization process > >> > to introduce a delay specifically for CPUless NUMA nodes. This delay > >> > ensures that the memory tier initialization for these nodes is deferred > >> > until HMAT information is obtained during the boot process. Finally, > >> > demotion tables are recalculated at the end. > >> > > >> > * Abstract common functions into `find_alloc_memory_type()` > >> > >> We should move kmem_put_memory_types() (renamed to > >> mt_put_memory_types()?) too. This can be put in a separate patch. > >> > > > > Will do! Thanks, > > > > > >> > >> > Since different memory devices require finding or allocating a memory type, > >> > these common steps are abstracted into a single function, > >> > `find_alloc_memory_type()`, enhancing code scalability and conciseness. > >> > > >> > * Handle cases where there is no HMAT when creating memory tiers > >> > There is a scenario where a CPUless node does not provide HMAT information. > >> > If no HMAT is specified, it falls back to using the default DRAM tier. > >> > > >> > * Change adist calculation code to use another new lock, mt_perf_lock. > >> > In the current implementation, iterating through CPUlist nodes requires > >> > holding the `memory_tier_lock`. However, `mt_calc_adistance()` will end up > >> > trying to acquire the same lock, leading to a potential deadlock. > >> > Therefore, we propose introducing a standalone `mt_perf_lock` to protect > >> > `default_dram_perf`. This approach not only avoids deadlock but also > >> > prevents holding a large lock simultaneously. > >> > > >> > Signed-off-by: Ho-Ren (Jack) Chuang <horenchuang@bytedance.com> > >> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com> > >> > --- > >> > drivers/acpi/numa/hmat.c | 11 ++++++ > >> > drivers/dax/kmem.c | 13 +------ > >> > include/linux/acpi.h | 6 ++++ > >> > include/linux/memory-tiers.h | 8 +++++ > >> > mm/memory-tiers.c | 70 +++++++++++++++++++++++++++++++++--- > >> > 5 files changed, 92 insertions(+), 16 deletions(-) > >> > > >> > diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c > >> > index d6b85f0f6082..28812ec2c793 100644 > >> > --- a/drivers/acpi/numa/hmat.c > >> > +++ b/drivers/acpi/numa/hmat.c > >> > @@ -38,6 +38,8 @@ static LIST_HEAD(targets); > >> > static LIST_HEAD(initiators); > >> > static LIST_HEAD(localities); > >> > > >> > +static LIST_HEAD(hmat_memory_types); > >> > + > >> > >> HMAT isn't a device driver for some memory devices. So I don't think we > >> should manage memory types in HMAT. > > > > I can put it back in memory-tier.c. How about the list? Do we still > > need to keep a separate list for storing late_inited memory nodes? > > And how about the list name if we need to remove the prefix "hmat_"? > > I don't think we need a separate list for memory-less nodes. Just > iterate all memory-less nodes. > Ok. There is no need to keep a list of memory-less nodes. I will only keep a memory_type list to manage created memory types. > > > >> Instead, if the memory_type of a > >> node isn't set by the driver, we should manage it in memory-tier.c as > >> fallback. > >> > > > > Do you mean some device drivers may init memory tiers between > > memory_tier_init() and late_initcall(memory_tier_late_init);? > > And this is the reason why you mention to exclude > > "node_memory_types[nid].memtype != NULL" in memory_tier_late_init(). > > Is my understanding correct? > > Yes. > Thanks. > >> > static DEFINE_MUTEX(target_lock); > >> > > >> > /* > >> > @@ -149,6 +151,12 @@ int acpi_get_genport_coordinates(u32 uid, > >> > } > >> > EXPORT_SYMBOL_NS_GPL(acpi_get_genport_coordinates, CXL); > >> > > >> > +struct memory_dev_type *hmat_find_alloc_memory_type(int adist) > >> > +{ > >> > + return find_alloc_memory_type(adist, &hmat_memory_types); > >> > +} > >> > +EXPORT_SYMBOL_GPL(hmat_find_alloc_memory_type); > >> > + > >> > static __init void alloc_memory_initiator(unsigned int cpu_pxm) > >> > { > >> > struct memory_initiator *initiator; > >> > @@ -1038,6 +1046,9 @@ static __init int hmat_init(void) > >> > if (!hmat_set_default_dram_perf()) > >> > register_mt_adistance_algorithm(&hmat_adist_nb); > >> > > >> > + /* Post-create CPUless memory tiers after getting HMAT info */ > >> > + memory_tier_late_init(); > >> > + > >> > >> This should be called in memory-tier.c via > >> > >> late_initcall(memory_tier_late_init); > >> > >> Then, we don't need hmat to call it. > >> > > > > Thanks. Learned! > > > > > >> > return 0; > >> > out_put: > >> > hmat_free_structures(); > >> > diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c > >> > index 42ee360cf4e3..aee17ab59f4f 100644 > >> > --- a/drivers/dax/kmem.c > >> > +++ b/drivers/dax/kmem.c > >> > @@ -55,21 +55,10 @@ static LIST_HEAD(kmem_memory_types); > >> > > >> > static struct memory_dev_type *kmem_find_alloc_memory_type(int adist) > >> > { > >> > - bool found = false; > >> > struct memory_dev_type *mtype; > >> > > >> > mutex_lock(&kmem_memory_type_lock); > >> > - list_for_each_entry(mtype, &kmem_memory_types, list) { > >> > - if (mtype->adistance == adist) { > >> > - found = true; > >> > - break; > >> > - } > >> > - } > >> > - if (!found) { > >> > - mtype = alloc_memory_type(adist); > >> > - if (!IS_ERR(mtype)) > >> > - list_add(&mtype->list, &kmem_memory_types); > >> > - } > >> > + mtype = find_alloc_memory_type(adist, &kmem_memory_types); > >> > mutex_unlock(&kmem_memory_type_lock); > >> > > >> > return mtype; > >> > diff --git a/include/linux/acpi.h b/include/linux/acpi.h > >> > index b7165e52b3c6..3f927ff01f02 100644 > >> > --- a/include/linux/acpi.h > >> > +++ b/include/linux/acpi.h > >> > @@ -434,12 +434,18 @@ int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp); > >> > > >> > #ifdef CONFIG_ACPI_HMAT > >> > int acpi_get_genport_coordinates(u32 uid, struct access_coordinate *coord); > >> > +struct memory_dev_type *hmat_find_alloc_memory_type(int adist); > >> > #else > >> > static inline int acpi_get_genport_coordinates(u32 uid, > >> > struct access_coordinate *coord) > >> > { > >> > return -EOPNOTSUPP; > >> > } > >> > + > >> > +static inline struct memory_dev_type *hmat_find_alloc_memory_type(int adist) > >> > +{ > >> > + return NULL; > >> > +} > >> > #endif > >> > > >> > #ifdef CONFIG_ACPI_NUMA > >> > diff --git a/include/linux/memory-tiers.h b/include/linux/memory-tiers.h > >> > index 69e781900082..4bc2596c5774 100644 > >> > --- a/include/linux/memory-tiers.h > >> > +++ b/include/linux/memory-tiers.h > >> > @@ -48,6 +48,9 @@ int mt_calc_adistance(int node, int *adist); > >> > int mt_set_default_dram_perf(int nid, struct access_coordinate *perf, > >> > const char *source); > >> > int mt_perf_to_adistance(struct access_coordinate *perf, int *adist); > >> > +struct memory_dev_type *find_alloc_memory_type(int adist, > >> > + struct list_head *memory_types); > >> > +void memory_tier_late_init(void); > >> > #ifdef CONFIG_MIGRATION > >> > int next_demotion_node(int node); > >> > void node_get_allowed_targets(pg_data_t *pgdat, nodemask_t *targets); > >> > @@ -136,5 +139,10 @@ static inline int mt_perf_to_adistance(struct access_coordinate *perf, int *adis > >> > { > >> > return -EIO; > >> > } > >> > + > >> > +static inline void memory_tier_late_init(void) > >> > +{ > >> > + > >> > +} > >> > #endif /* CONFIG_NUMA */ > >> > #endif /* _LINUX_MEMORY_TIERS_H */ > >> > diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c > >> > index 0537664620e5..79f748d60e6f 100644 > >> > --- a/mm/memory-tiers.c > >> > +++ b/mm/memory-tiers.c > >> > @@ -6,6 +6,7 @@ > >> > #include <linux/memory.h> > >> > #include <linux/memory-tiers.h> > >> > #include <linux/notifier.h> > >> > +#include <linux/acpi.h> > >> > > >> > #include "internal.h" > >> > > >> > @@ -35,6 +36,7 @@ struct node_memory_type_map { > >> > }; > >> > > >> > static DEFINE_MUTEX(memory_tier_lock); > >> > +static DEFINE_MUTEX(mt_perf_lock); > >> > >> Please add comments about what it protects. And put it near the data > >> structure it protects. > >> > > > > Where is better for me to add comments for this? Code? Patch description? > > Will put it closer to the protected data. Thanks. > > Just put the comments at the above of the lock in the source code. > Got it. Thanks! > > > > > > >> > static LIST_HEAD(memory_tiers); > >> > static struct node_memory_type_map node_memory_types[MAX_NUMNODES]; > >> > struct memory_dev_type *default_dram_type; > >> > @@ -623,6 +625,58 @@ void clear_node_memory_type(int node, struct memory_dev_type *memtype) > >> > } > >> > EXPORT_SYMBOL_GPL(clear_node_memory_type); > >> > > >> > +struct memory_dev_type *find_alloc_memory_type(int adist, struct list_head *memory_types) > >> > +{ > >> > + bool found = false; > >> > + struct memory_dev_type *mtype; > >> > + > >> > + list_for_each_entry(mtype, memory_types, list) { > >> > + if (mtype->adistance == adist) { > >> > + found = true; > >> > + break; > >> > + } > >> > + } > >> > + if (!found) { > >> > + mtype = alloc_memory_type(adist); > >> > + if (!IS_ERR(mtype)) > >> > + list_add(&mtype->list, memory_types); > >> > + } > >> > + > >> > + return mtype; > >> > +} > >> > +EXPORT_SYMBOL_GPL(find_alloc_memory_type); > >> > + > >> > +static void memory_tier_late_create(int node) > >> > +{ > >> > + struct memory_dev_type *mtype = NULL; > >> > + int adist = MEMTIER_ADISTANCE_DRAM; > >> > + > >> > + mt_calc_adistance(node, &adist); > >> > + if (adist != MEMTIER_ADISTANCE_DRAM) { > >> > >> We can manage default_dram_type() via find_alloc_memory_type() > >> too. > >> > >> And, if "node_memory_types[node].memtype == NULL", we can call > >> mt_calc_adistance(node, &adist) and find_alloc_memory_type() in > >> set_node_memory_tier(). Then, we can cover hotpluged memory node too. > >> > >> > + mtype = hmat_find_alloc_memory_type(adist); > >> > + if (!IS_ERR(mtype)) > >> > + __init_node_memory_type(node, mtype); > >> > + else > >> > + pr_err("Failed to allocate a memory type at %s()\n", __func__); > >> > + } > >> > + > >> > + set_node_memory_tier(node); > >> > +} > >> > + > >> > +void memory_tier_late_init(void) > >> > +{ > >> > + int nid; > >> > + > >> > + mutex_lock(&memory_tier_lock); > >> > + for_each_node_state(nid, N_MEMORY) > >> > + if (!node_state(nid, N_CPU)) > >> > >> We should exclude "node_memory_types[nid].memtype != NULL". Some memory > >> nodes may be onlined by some device drivers and setup memory tiers > >> already. > >> > >> > + memory_tier_late_create(nid); > >> > + > >> > + establish_demotion_targets(); > >> > + mutex_unlock(&memory_tier_lock); > >> > +} > >> > +EXPORT_SYMBOL_GPL(memory_tier_late_init); > >> > + > >> > static void dump_hmem_attrs(struct access_coordinate *coord, const char *prefix) > >> > { > >> > pr_info( > >> > @@ -636,7 +690,7 @@ int mt_set_default_dram_perf(int nid, struct access_coordinate *perf, > >> > { > >> > int rc = 0; > >> > > >> > - mutex_lock(&memory_tier_lock); > >> > + mutex_lock(&mt_perf_lock); > >> > if (default_dram_perf_error) { > >> > rc = -EIO; > >> > goto out; > >> > @@ -684,7 +738,7 @@ int mt_set_default_dram_perf(int nid, struct access_coordinate *perf, > >> > } > >> > > >> > out: > >> > - mutex_unlock(&memory_tier_lock); > >> > + mutex_unlock(&mt_perf_lock); > >> > return rc; > >> > } > >> > > >> > @@ -700,7 +754,7 @@ int mt_perf_to_adistance(struct access_coordinate *perf, int *adist) > >> > perf->read_bandwidth + perf->write_bandwidth == 0) > >> > return -EINVAL; > >> > > >> > - mutex_lock(&memory_tier_lock); > >> > + mutex_lock(&mt_perf_lock); > >> > /* > >> > * The abstract distance of a memory node is in direct proportion to > >> > * its memory latency (read + write) and inversely proportional to its > >> > @@ -713,7 +767,7 @@ int mt_perf_to_adistance(struct access_coordinate *perf, int *adist) > >> > (default_dram_perf.read_latency + default_dram_perf.write_latency) * > >> > (default_dram_perf.read_bandwidth + default_dram_perf.write_bandwidth) / > >> > (perf->read_bandwidth + perf->write_bandwidth); > >> > - mutex_unlock(&memory_tier_lock); > >> > + mutex_unlock(&mt_perf_lock); > >> > > >> > return 0; > >> > } > >> > @@ -836,6 +890,14 @@ static int __init memory_tier_init(void) > >> > * types assigned. > >> > */ > >> > for_each_node_state(node, N_MEMORY) { > >> > + if (!node_state(node, N_CPU)) > >> > + /* > >> > + * Defer memory tier initialization on CPUless numa nodes. > >> > + * These will be initialized when HMAT information is > >> > >> HMAT is platform specific, we should avoid to mention it in general code > >> if possible. > >> > > > > Will fix! Thanks, > > > > > >> > + * available. > >> > + */ > >> > + continue; > >> > + > >> > memtier = set_node_memory_tier(node); > >> > if (IS_ERR(memtier)) > >> > /* > >> > > -- > Best Regards, > Huang, Ying -- Best regards, Ho-Ren (Jack) Chuang 莊賀任
On Thu, Feb 08, 2024 at 09:14:11AM +0530, Sunil V L wrote: > This series enables the support for "Collaborative Processor Performance > Control (CPPC) on ACPI based RISC-V platforms. It depends on the > encoding of CPPC registers as defined in RISC-V FFH spec [2]. > > CPPC is described in the ACPI spec [1]. RISC-V FFH spec required to > enable this, is available at [2]. > > [1] - https://uefi.org/specs/ACPI/6.5/08_Processor_Configuration_and_Control.html#collaborative-processor-performance-control > [2] - https://github.com/riscv-non-isa/riscv-acpi-ffh/releases/download/v1.0.0/riscv-ffh.pdf > > The series is based on the LPI support series. > Based-on: 20240118062930.245937-1-sunilvl@ventanamicro.com > (https://lore.kernel.org/lkml/20240118062930.245937-1-sunilvl@ventanamicro.com/) Should the https://github.com/vlsunil/qemu/tree/lpi_exp branch also be used for this CPPC series too? Thanks, Drew
Summon Hans and Sakari for the ideas and for heads up (MIPI case can be affected as well). On Fri, Mar 15, 2024 at 12:39:03AM +0000, Hamish Martin wrote: > On Thu, 2024-03-14 at 15:18 +0200, andriy.shevchenko@linux.intel.com > wrote: > > On Thu, Mar 14, 2024 at 01:13:31AM +0000, Hamish Martin wrote: > > > On Wed, 2024-03-13 at 13:26 +0200, Andy Shevchenko wrote: ... > > > Removing the setting of the handle to invalid may be the right fix > > > but > > > I don't feel I know the code well enough to make a decision on > > > that. It > > > certainly doesn't resolve things immediately - I saw ref counting > > > warnings output. > > > > Not removing, but moving to the better place? > > Can you share warnings, though? > > > For context here is the current call chain that leads to > acpi_gpiochip_remove(): > > acpi_gpiochip_remove+0x32/0x1a0 > gpiochip_remove+0x39/0x140 > devres_release_group+0xe6/0x160 > i2c_device_remove+0x2d/0x80 > device_release_driver_internal+0x19a/0x200 > bus_remove_device+0xbf/0x100 > device_del+0x157/0x490 > ? __pfx_device_match_fwnode+0x10/0x10 > ? srso_return_thunk+0x5/0x5f > device_unregister+0xd/0x30 > i2c_acpi_notify+0x10e/0x160 > notifier_call_chain+0x58/0xd0 > blocking_notifier_call_chain+0x3a/0x60 > acpi_device_del_work_fn+0x85/0x1d0 > process_one_work+0x134/0x2f0 > worker_thread+0x2f0/0x410 > ? __pfx_worker_thread+0x10/0x10 > kthread+0xe3/0x110 > ? __pfx_kthread+0x10/0x10 > ret_from_fork+0x2f/0x50 > ? __pfx_kthread+0x10/0x10 > ret_from_fork_asm+0x1b/0x30 Right, and with invalid handle it can't process further. And note, that _pointer_ is valid, the content become unavailable. > I removed the setting of adev->handle = INVALID_ACPI_HANDLE from > acpi_scan_drop_device() and shifted it to just after the call to > blocking_notifier_call_chain() in acpi_device_del_work_fn(). > With that it seems things progress further with the call to > acpi_get_data() in acpi_gpiochip_remove() succeeding now. However, > later in acpi_gpiochip_free_regions() we hit this error: > > pca953x i2c-PRP0001:03: Failed to remove GPIO OpRegion handler > > We also get these errors: > ACPI Warning: Obj 00000000ba6a9600, Reference Count is already zero, > cannot decrement > (20230628/utdelete-422) Right, because of ACPICA (not even ACPI glue layer!) the callbacks are called when namespace node (which is acpi_handle) is being removed. I spend a few hours to understand the history of the invalidation of the handle. TBH, it looks like a hack to me, but its presence seems necessary to avoid racing with the hotplug work. It's a lot of functions that run asynchronously there and the validness of some objects is questionable. Here are the commits in question: d783156ea384 ("ACPI / scan: Define non-empty device removal handler") c27b2c33b621 ("ACPI / hotplug: Introduce common hotplug function acpi_device_hotplug()") (It doesn't mean they are bad, it means that this requires more investigation.) That said, from my perspective what should be done/clarified - the scope of ACPI data (Can we use it outside of ACPICA/ACPI glue layer or not?) - clarify in the documentation the scope / life time of the ACPI objects from the ACPICA perspective (Is it already done? Where?) - remove that invalidation hack and find better solution for the race avoidance > > P.S. > > I'm not an expert in ACPICA and low lever of ACPI glue layer in the Linux > > kernel, perhaps Rafael can suggest something better. > > > OK, thanks for your help. Hopefully Rafael can add something to the > discssion. Added more people to harvest the ideas. -- With Best Regards, Andy Shevchenko
On Sun, Mar 17, 2024 at 10:33:15PM -0700, Drew Fustini wrote:
> On Thu, Jan 18, 2024 at 11:59:29AM +0530, Sunil V L wrote:
> > Enable Low Power Idle (LPI) based cpuidle driver for RISC-V platforms.
> > It depends on SBI HSM calls for idle state transitions.
> >
> > Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
> > Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
> > ---
> > drivers/acpi/riscv/Makefile | 3 +-
> > drivers/acpi/riscv/cpuidle.c | 81 ++++++++++++++++++++++++++++++++++++
> > 2 files changed, 83 insertions(+), 1 deletion(-)
> > create mode 100644 drivers/acpi/riscv/cpuidle.c
> >
> > diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
> > index 8b3b126e0b94..7309d92dd477 100644
> > --- a/drivers/acpi/riscv/Makefile
> > +++ b/drivers/acpi/riscv/Makefile
> > @@ -1,2 +1,3 @@
> > # SPDX-License-Identifier: GPL-2.0-only
> > -obj-y += rhct.o
> > +obj-y += rhct.o
> > +obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
> > diff --git a/drivers/acpi/riscv/cpuidle.c b/drivers/acpi/riscv/cpuidle.c
> > new file mode 100644
> > index 000000000000..624f9bbdb58c
> > --- /dev/null
> > +++ b/drivers/acpi/riscv/cpuidle.c
> > @@ -0,0 +1,81 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2024, Ventana Micro Systems Inc
> > + * Author: Sunil V L <sunilvl@ventanamicro.com>
> > + *
> > + */
> > +
> > +#include <linux/acpi.h>
> > +#include <acpi/processor.h>
> > +#include <linux/cpu_pm.h>
> > +#include <linux/cpuidle.h>
> > +#include <linux/suspend.h>
> > +#include <asm/cpuidle.h>
> > +#include <asm/sbi.h>
> > +#include <asm/suspend.h>
> > +
> > +#define RISCV_FFH_LPI_TYPE_MASK GENMASK_ULL(63, 60)
> > +#define RISCV_FFH_LPI_RSVD_MASK GENMASK_ULL(59, 32)
> > +
> > +#define RISCV_FFH_LPI_TYPE_SBI BIT_ULL(60)
> > +
> > +static int acpi_cpu_init_idle(unsigned int cpu)
> > +{
> > + int i;
> > + struct acpi_lpi_state *lpi;
> > + struct acpi_processor *pr = per_cpu(processors, cpu);
> > +
> > + if (unlikely(!pr || !pr->flags.has_lpi))
> > + return -EINVAL;
> > +
> > + if (!riscv_sbi_hsm_is_supported())
> > + return -ENODEV;
> > +
> > + if (pr->power.count <= 1)
> > + return -ENODEV;
> > +
> > + for (i = 1; i < pr->power.count; i++) {
> > + u32 state;
> > +
> > + lpi = &pr->power.lpi_states[i];
> > +
> > + /*
> > + * Validate Entry Method as per FFH spec.
> > + * bits[63:60] should be 0x1
> > + * bits[59:32] should be 0x0
> > + * bits[31:0] represent a SBI power_state
> > + */
> > + if (((lpi->address & RISCV_FFH_LPI_TYPE_MASK) != RISCV_FFH_LPI_TYPE_SBI) ||
> > + (lpi->address & RISCV_FFH_LPI_RSVD_MASK)) {
> > + pr_warn("Invalid LPI entry method %#llx\n", lpi->address);
> > + return -EINVAL;
> > + }
> > +
> > + state = lpi->address;
>
> It seems that acpi_lpi_state.address is u64, so shouldn't state be u64
> instead of u32?
>
SBI suspend state is only 32 bits represented by lower 32 bits of
lpi->address.
Thanks,
Sunil
On Thu, Jan 18, 2024 at 11:59:29AM +0530, Sunil V L wrote:
> Enable Low Power Idle (LPI) based cpuidle driver for RISC-V platforms.
> It depends on SBI HSM calls for idle state transitions.
>
> Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
> Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
> ---
> drivers/acpi/riscv/Makefile | 3 +-
> drivers/acpi/riscv/cpuidle.c | 81 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 83 insertions(+), 1 deletion(-)
> create mode 100644 drivers/acpi/riscv/cpuidle.c
>
> diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
> index 8b3b126e0b94..7309d92dd477 100644
> --- a/drivers/acpi/riscv/Makefile
> +++ b/drivers/acpi/riscv/Makefile
> @@ -1,2 +1,3 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-y += rhct.o
> +obj-y += rhct.o
> +obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
> diff --git a/drivers/acpi/riscv/cpuidle.c b/drivers/acpi/riscv/cpuidle.c
> new file mode 100644
> index 000000000000..624f9bbdb58c
> --- /dev/null
> +++ b/drivers/acpi/riscv/cpuidle.c
> @@ -0,0 +1,81 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2024, Ventana Micro Systems Inc
> + * Author: Sunil V L <sunilvl@ventanamicro.com>
> + *
> + */
> +
> +#include <linux/acpi.h>
> +#include <acpi/processor.h>
> +#include <linux/cpu_pm.h>
> +#include <linux/cpuidle.h>
> +#include <linux/suspend.h>
> +#include <asm/cpuidle.h>
> +#include <asm/sbi.h>
> +#include <asm/suspend.h>
> +
> +#define RISCV_FFH_LPI_TYPE_MASK GENMASK_ULL(63, 60)
> +#define RISCV_FFH_LPI_RSVD_MASK GENMASK_ULL(59, 32)
> +
> +#define RISCV_FFH_LPI_TYPE_SBI BIT_ULL(60)
> +
> +static int acpi_cpu_init_idle(unsigned int cpu)
> +{
> + int i;
> + struct acpi_lpi_state *lpi;
> + struct acpi_processor *pr = per_cpu(processors, cpu);
> +
> + if (unlikely(!pr || !pr->flags.has_lpi))
> + return -EINVAL;
> +
> + if (!riscv_sbi_hsm_is_supported())
> + return -ENODEV;
> +
> + if (pr->power.count <= 1)
> + return -ENODEV;
> +
> + for (i = 1; i < pr->power.count; i++) {
> + u32 state;
> +
> + lpi = &pr->power.lpi_states[i];
> +
> + /*
> + * Validate Entry Method as per FFH spec.
> + * bits[63:60] should be 0x1
> + * bits[59:32] should be 0x0
> + * bits[31:0] represent a SBI power_state
> + */
> + if (((lpi->address & RISCV_FFH_LPI_TYPE_MASK) != RISCV_FFH_LPI_TYPE_SBI) ||
> + (lpi->address & RISCV_FFH_LPI_RSVD_MASK)) {
> + pr_warn("Invalid LPI entry method %#llx\n", lpi->address);
> + return -EINVAL;
> + }
> +
> + state = lpi->address;
It seems that acpi_lpi_state.address is u64, so shouldn't state be u64
instead of u32?
thanks,
drew
The pull request you sent on Fri, 15 Mar 2024 15:24:08 -0700: > git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl tags/cxl-for-6.9 has been merged into torvalds/linux.git: https://git.kernel.org/torvalds/c/02c163e959b72059ce409a8516170dc40193001f Thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/prtracker.html
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git bleeding-edge branch HEAD: 0d98d467155d782b8b31be48f73cf47a088d8929 Merge branch 'acpi-misc' into bleeding-edge elapsed time: 720m configs tested: 155 configs skipped: 3 The following configs have been built successfully. More configs may be tested in the coming days. tested configs: alpha allnoconfig gcc alpha allyesconfig gcc alpha defconfig gcc arc allmodconfig gcc arc allnoconfig gcc arc allyesconfig gcc arc defconfig gcc arc randconfig-001-20240315 gcc arc randconfig-002-20240315 gcc arm allmodconfig gcc arm allnoconfig clang arm allyesconfig gcc arm am200epdkit_defconfig gcc arm davinci_all_defconfig clang arm defconfig clang arm lpc18xx_defconfig clang arm randconfig-001-20240315 clang arm randconfig-002-20240315 gcc arm randconfig-003-20240315 gcc arm randconfig-004-20240315 gcc arm socfpga_defconfig gcc arm sunxi_defconfig gcc arm64 allmodconfig clang arm64 allnoconfig gcc arm64 defconfig gcc arm64 randconfig-001-20240315 gcc arm64 randconfig-002-20240315 gcc arm64 randconfig-003-20240315 gcc arm64 randconfig-004-20240315 gcc csky allmodconfig gcc csky allnoconfig gcc csky allyesconfig gcc csky defconfig gcc csky randconfig-001-20240315 gcc csky randconfig-002-20240315 gcc hexagon allmodconfig clang hexagon allnoconfig clang hexagon allyesconfig clang hexagon defconfig clang hexagon randconfig-001-20240315 clang hexagon randconfig-002-20240315 clang i386 allmodconfig gcc i386 allnoconfig gcc i386 allyesconfig gcc i386 buildonly-randconfig-001-20240315 clang i386 buildonly-randconfig-002-20240315 clang i386 buildonly-randconfig-003-20240315 gcc i386 buildonly-randconfig-004-20240315 clang i386 buildonly-randconfig-005-20240315 gcc i386 buildonly-randconfig-006-20240315 gcc i386 defconfig clang i386 randconfig-001-20240315 gcc i386 randconfig-002-20240315 clang i386 randconfig-003-20240315 clang i386 randconfig-004-20240315 clang i386 randconfig-005-20240315 gcc i386 randconfig-006-20240315 clang i386 randconfig-011-20240315 clang i386 randconfig-012-20240315 gcc i386 randconfig-013-20240315 gcc i386 randconfig-014-20240315 clang i386 randconfig-015-20240315 gcc i386 randconfig-016-20240315 clang loongarch allmodconfig gcc loongarch allnoconfig gcc loongarch defconfig gcc loongarch randconfig-001-20240315 gcc loongarch randconfig-002-20240315 gcc m68k allmodconfig gcc m68k allnoconfig gcc m68k allyesconfig gcc m68k amcore_defconfig gcc m68k defconfig gcc microblaze allmodconfig gcc microblaze allnoconfig gcc microblaze allyesconfig gcc microblaze defconfig gcc microblaze mmu_defconfig gcc mips allnoconfig gcc mips allyesconfig gcc mips ip32_defconfig clang mips loongson3_defconfig gcc nios2 allmodconfig gcc nios2 allnoconfig gcc nios2 allyesconfig gcc nios2 defconfig gcc nios2 randconfig-001-20240315 gcc nios2 randconfig-002-20240315 gcc openrisc allnoconfig gcc openrisc allyesconfig gcc openrisc defconfig gcc parisc allmodconfig gcc parisc allnoconfig gcc parisc allyesconfig gcc parisc defconfig gcc parisc generic-32bit_defconfig gcc parisc randconfig-001-20240315 gcc parisc randconfig-002-20240315 gcc parisc64 defconfig gcc powerpc allmodconfig gcc powerpc allnoconfig gcc powerpc allyesconfig clang powerpc amigaone_defconfig gcc powerpc mpc8313_rdb_defconfig gcc powerpc ps3_defconfig gcc powerpc randconfig-001-20240315 clang powerpc randconfig-002-20240315 gcc powerpc randconfig-003-20240315 clang powerpc stx_gp3_defconfig clang powerpc walnut_defconfig gcc powerpc64 randconfig-001-20240315 clang powerpc64 randconfig-002-20240315 gcc powerpc64 randconfig-003-20240315 gcc riscv allmodconfig clang riscv allnoconfig gcc riscv allyesconfig clang riscv defconfig clang riscv randconfig-001-20240315 clang riscv randconfig-002-20240315 clang s390 allmodconfig clang s390 allnoconfig clang s390 allyesconfig gcc s390 defconfig clang s390 randconfig-001-20240315 gcc s390 randconfig-002-20240315 clang sh allmodconfig gcc sh allnoconfig gcc sh allyesconfig gcc sh defconfig gcc sh randconfig-001-20240315 gcc sh randconfig-002-20240315 gcc sh shx3_defconfig gcc sparc allmodconfig gcc sparc allnoconfig gcc sparc defconfig gcc sparc64 allmodconfig gcc sparc64 allyesconfig gcc sparc64 defconfig gcc sparc64 randconfig-001-20240315 gcc sparc64 randconfig-002-20240315 gcc um allmodconfig clang um allnoconfig clang um allyesconfig gcc um defconfig clang um i386_defconfig gcc um randconfig-001-20240315 gcc um randconfig-002-20240315 clang um x86_64_defconfig clang x86_64 allnoconfig clang x86_64 allyesconfig clang x86_64 defconfig gcc x86_64 rhel-8.3-rust clang xtensa allnoconfig gcc xtensa randconfig-001-20240315 gcc xtensa randconfig-002-20240315 gcc -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki