aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--srcpkgs/linux6.9/files/arm64-dotconfig83
-rw-r--r--srcpkgs/linux6.9/patches/soc-qcom-add-in-kernel-pd-mapper-implementation.patch1951
-rw-r--r--srcpkgs/linux6.9/template2
3 files changed, 2012 insertions, 24 deletions
diff --git a/srcpkgs/linux6.9/files/arm64-dotconfig b/srcpkgs/linux6.9/files/arm64-dotconfig
index f17c05f71ce..70428d6dc8e 100644
--- a/srcpkgs/linux6.9/files/arm64-dotconfig
+++ b/srcpkgs/linux6.9/files/arm64-dotconfig
@@ -2,7 +2,7 @@
# Automatically generated file; DO NOT EDIT.
# Linux/arm64 6.9.7 Kernel Configuration
#
-CONFIG_CC_VERSION_TEXT="aarch64-linux-musl-gcc (GCC) 13.2.0"
+CONFIG_CC_VERSION_TEXT="aarch64-linux-gnu-gcc (GCC) 13.2.0"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=130200
CONFIG_CLANG_VERSION=0
@@ -29,7 +29,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
CONFIG_INIT_ENV_ARG_LIMIT=32
# CONFIG_COMPILE_TEST is not set
# CONFIG_WERROR is not set
-CONFIG_LOCALVERSION="_1"
+CONFIG_LOCALVERSION="_2"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_BUILD_SALT=""
CONFIG_DEFAULT_INIT=""
@@ -602,7 +602,7 @@ CONFIG_DPM_WATCHDOG=y
CONFIG_DPM_WATCHDOG_TIMEOUT=60
CONFIG_PM_CLK=y
CONFIG_PM_GENERIC_DOMAINS=y
-# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
CONFIG_PM_GENERIC_DOMAINS_OF=y
CONFIG_CPU_PM=y
@@ -2379,7 +2379,7 @@ CONFIG_SOC_BUS=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_SPI=y
-CONFIG_REGMAP_SPMI=m
+CONFIG_REGMAP_SPMI=y
CONFIG_REGMAP_W1=m
CONFIG_REGMAP_MMIO=y
CONFIG_REGMAP_IRQ=y
@@ -2447,7 +2447,7 @@ CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE=y
CONFIG_ARM_SCMI_POWER_CONTROL=m
# end of ARM System Control and Management Interface Protocol
-CONFIG_ARM_SCPI_PROTOCOL=m
+CONFIG_ARM_SCPI_PROTOCOL=y
CONFIG_ARM_SDE_INTERFACE=y
CONFIG_FIRMWARE_MEMMAP=y
CONFIG_DMIID=y
@@ -2503,7 +2503,8 @@ CONFIG_ARM_PSCI_FW=y
#
CONFIG_QCOM_SCM=y
# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set
-# CONFIG_QCOM_QSEECOM is not set
+CONFIG_QCOM_QSEECOM=y
+CONFIG_QCOM_QSEECOM_UEFISECAPP=y
# end of Qualcomm firmware drivers
CONFIG_HAVE_ARM_SMCCC=y
@@ -4921,7 +4922,7 @@ CONFIG_XILLYUSB=m
CONFIG_I2C=y
CONFIG_ACPI_I2C_OPREGION=y
CONFIG_I2C_BOARDINFO=y
-# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=m
CONFIG_I2C_MUX=m
@@ -5150,7 +5151,7 @@ CONFIG_SPI_SLAVE=y
CONFIG_SPI_SLAVE_TIME=m
CONFIG_SPI_SLAVE_SYSTEM_CONTROL=m
CONFIG_SPI_DYNAMIC=y
-CONFIG_SPMI=m
+CONFIG_SPMI=y
CONFIG_SPMI_HISI3670=m
CONFIG_SPMI_MSM_PMIC_ARB=m
CONFIG_SPMI_MTK_PMIF=m
@@ -5323,7 +5324,7 @@ CONFIG_PINCTRL_SA8775P=m
CONFIG_PINCTRL_SC7180=m
CONFIG_PINCTRL_SC7280=m
CONFIG_PINCTRL_SC8180X=m
-CONFIG_PINCTRL_SC8280XP=m
+CONFIG_PINCTRL_SC8280XP=y
# CONFIG_PINCTRL_SDM660 is not set
CONFIG_PINCTRL_SDM670=m
CONFIG_PINCTRL_SDM845=m
@@ -5341,7 +5342,7 @@ CONFIG_PINCTRL_SM8450=m
CONFIG_PINCTRL_SM8550=m
# CONFIG_PINCTRL_SM8650 is not set
# CONFIG_PINCTRL_X1E80100 is not set
-CONFIG_PINCTRL_QCOM_SPMI_PMIC=m
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_PINCTRL_QCOM_SSBI_PMIC=m
CONFIG_PINCTRL_LPASS_LPI=m
# CONFIG_PINCTRL_SC7280_LPASS_LPI is not set
@@ -5938,12 +5939,13 @@ CONFIG_THERMAL_OF=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
# CONFIG_THERMAL_DEFAULT_GOV_BANG_BANG is not set
CONFIG_THERMAL_GOV_FAIR_SHARE=y
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_BANG_BANG=y
CONFIG_THERMAL_GOV_USER_SPACE=y
-# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
CONFIG_CPU_THERMAL=y
CONFIG_CPU_FREQ_THERMAL=y
# CONFIG_CPU_IDLE_THERMAL is not set
@@ -6001,7 +6003,7 @@ CONFIG_GENERIC_ADC_THERMAL=m
#
CONFIG_QCOM_TSENS=m
CONFIG_QCOM_SPMI_ADC_TM5=m
-# CONFIG_QCOM_SPMI_TEMP_ALARM is not set
+CONFIG_QCOM_SPMI_TEMP_ALARM=m
CONFIG_QCOM_LMH=m
# end of Qualcomm thermal drivers
@@ -6040,7 +6042,7 @@ CONFIG_XILINX_WATCHDOG=m
CONFIG_ZIIRAVE_WATCHDOG=m
CONFIG_MLX_WDT=m
CONFIG_SL28CPLD_WATCHDOG=m
-# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_SP805_WATCHDOG=y
CONFIG_ARM_SBSA_WATCHDOG=m
CONFIG_ARMADA_37XX_WATCHDOG=m
CONFIG_CADENCE_WATCHDOG=m
@@ -6053,7 +6055,7 @@ CONFIG_IMX2_WDT=m
CONFIG_IMX_SC_WDT=m
CONFIG_IMX7ULP_WDT=m
CONFIG_TEGRA_WATCHDOG=m
-# CONFIG_QCOM_WDT is not set
+CONFIG_QCOM_WDT=m
CONFIG_MESON_GXBB_WATCHDOG=m
CONFIG_MESON_WATCHDOG=m
CONFIG_MEDIATEK_WATCHDOG=m
@@ -9368,7 +9370,7 @@ CONFIG_SCSI_UFSHCD_PCI=m
CONFIG_SCSI_UFSHCD_PLATFORM=m
CONFIG_SCSI_UFS_CDNS_PLATFORM=m
# CONFIG_SCSI_UFS_DWC_TC_PLATFORM is not set
-# CONFIG_SCSI_UFS_QCOM is not set
+CONFIG_SCSI_UFS_QCOM=m
CONFIG_SCSI_UFS_MEDIATEK=m
CONFIG_SCSI_UFS_HISI=m
CONFIG_SCSI_UFS_EXYNOS=m
@@ -10392,7 +10394,7 @@ CONFIG_QCM_GCC_2290=m
CONFIG_QCS_GCC_404=m
CONFIG_SC_CAMCC_7180=m
CONFIG_SC_CAMCC_7280=m
-# CONFIG_SC_CAMCC_8280XP is not set
+CONFIG_SC_CAMCC_8280XP=m
CONFIG_SC_DISPCC_7180=m
CONFIG_SC_DISPCC_7280=m
CONFIG_SC_DISPCC_8280XP=m
@@ -10404,9 +10406,9 @@ CONFIG_SC_GCC_8180X=m
CONFIG_SC_GCC_8280XP=m
CONFIG_SC_GPUCC_7180=m
CONFIG_SC_GPUCC_7280=m
-# CONFIG_SC_GPUCC_8280XP is not set
+CONFIG_SC_GPUCC_8280XP=m
CONFIG_SC_LPASSCC_7280=m
-# CONFIG_SC_LPASSCC_8280XP is not set
+CONFIG_SC_LPASSCC_8280XP=m
CONFIG_SC_LPASS_CORECC_7180=m
CONFIG_SC_LPASS_CORECC_7280=m
CONFIG_SC_VIDEOCC_7180=m
@@ -10463,7 +10465,7 @@ CONFIG_SM_TCSRCC_8550=m
# CONFIG_SM_TCSRCC_8650 is not set
CONFIG_SM_VIDEOCC_8150=m
CONFIG_SM_VIDEOCC_8250=m
-# CONFIG_SM_VIDEOCC_8350 is not set
+CONFIG_SM_VIDEOCC_8350=m
# CONFIG_SM_VIDEOCC_8550 is not set
CONFIG_SPMI_PMIC_CLKDIV=m
CONFIG_QCOM_HFPLL=m
@@ -10541,7 +10543,7 @@ CONFIG_TIMER_IMX_SYS_CTR=y
# end of Clock Source drivers
CONFIG_MAILBOX=y
-# CONFIG_ARM_MHU is not set
+CONFIG_ARM_MHU=y
CONFIG_ARM_MHU_V2=m
CONFIG_IMX_MBOX=m
CONFIG_PLATFORM_MHU=m
@@ -10583,8 +10585,8 @@ CONFIG_IOMMU_IO_PGTABLE_DART=y
# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
-# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set
-CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y
+CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
+# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_OF_IOMMU=y
CONFIG_IOMMU_DMA=y
CONFIG_IOMMU_SVA=y
@@ -10744,7 +10746,9 @@ CONFIG_QCOM_LLCC=m
CONFIG_QCOM_KRYO_L2_ACCESSORS=y
CONFIG_QCOM_MDT_LOADER=m
CONFIG_QCOM_OCMEM=m
+CONFIG_QCOM_PD_MAPPER=m
CONFIG_QCOM_PDR_HELPERS=m
+CONFIG_QCOM_PDR_MSG=m
# CONFIG_QCOM_PMIC_PDCHARGER_ULOG is not set
CONFIG_QCOM_PMIC_GLINK=m
CONFIG_QCOM_QMI_HELPERS=m
@@ -11990,7 +11994,40 @@ CONFIG_INTERCONNECT_IMX8MM=m
CONFIG_INTERCONNECT_IMX8MN=m
CONFIG_INTERCONNECT_IMX8MQ=m
CONFIG_INTERCONNECT_IMX8MP=m
-# CONFIG_INTERCONNECT_QCOM is not set
+CONFIG_INTERCONNECT_QCOM=y
+CONFIG_INTERCONNECT_QCOM_BCM_VOTER=y
+# CONFIG_INTERCONNECT_QCOM_MSM8909 is not set
+# CONFIG_INTERCONNECT_QCOM_MSM8916 is not set
+# CONFIG_INTERCONNECT_QCOM_MSM8939 is not set
+# CONFIG_INTERCONNECT_QCOM_MSM8974 is not set
+# CONFIG_INTERCONNECT_QCOM_MSM8996 is not set
+CONFIG_INTERCONNECT_QCOM_OSM_L3=m
+# CONFIG_INTERCONNECT_QCOM_QCM2290 is not set
+# CONFIG_INTERCONNECT_QCOM_QCS404 is not set
+# CONFIG_INTERCONNECT_QCOM_QDU1000 is not set
+CONFIG_INTERCONNECT_QCOM_RPMH_POSSIBLE=y
+CONFIG_INTERCONNECT_QCOM_RPMH=y
+# CONFIG_INTERCONNECT_QCOM_SA8775P is not set
+# CONFIG_INTERCONNECT_QCOM_SC7180 is not set
+# CONFIG_INTERCONNECT_QCOM_SC7280 is not set
+# CONFIG_INTERCONNECT_QCOM_SC8180X is not set
+CONFIG_INTERCONNECT_QCOM_SC8280XP=y
+# CONFIG_INTERCONNECT_QCOM_SDM660 is not set
+# CONFIG_INTERCONNECT_QCOM_SDM670 is not set
+# CONFIG_INTERCONNECT_QCOM_SDM845 is not set
+# CONFIG_INTERCONNECT_QCOM_SDX55 is not set
+# CONFIG_INTERCONNECT_QCOM_SDX65 is not set
+# CONFIG_INTERCONNECT_QCOM_SDX75 is not set
+# CONFIG_INTERCONNECT_QCOM_SM6115 is not set
+# CONFIG_INTERCONNECT_QCOM_SM6350 is not set
+# CONFIG_INTERCONNECT_QCOM_SM7150 is not set
+# CONFIG_INTERCONNECT_QCOM_SM8150 is not set
+# CONFIG_INTERCONNECT_QCOM_SM8250 is not set
+# CONFIG_INTERCONNECT_QCOM_SM8350 is not set
+# CONFIG_INTERCONNECT_QCOM_SM8450 is not set
+# CONFIG_INTERCONNECT_QCOM_SM8550 is not set
+# CONFIG_INTERCONNECT_QCOM_SM8650 is not set
+# CONFIG_INTERCONNECT_QCOM_X1E80100 is not set
CONFIG_INTERCONNECT_SAMSUNG=y
CONFIG_INTERCONNECT_EXYNOS=m
CONFIG_INTERCONNECT_CLK=m
diff --git a/srcpkgs/linux6.9/patches/soc-qcom-add-in-kernel-pd-mapper-implementation.patch b/srcpkgs/linux6.9/patches/soc-qcom-add-in-kernel-pd-mapper-implementation.patch
new file mode 100644
index 00000000000..794ac2f2d77
--- /dev/null
+++ b/srcpkgs/linux6.9/patches/soc-qcom-add-in-kernel-pd-mapper-implementation.patch
@@ -0,0 +1,1951 @@
+https://patchwork.kernel.org/project/linux-arm-msm/cover/20240622-qcom-pd-mapper-v9-0-a84ee3591c8e@linaro.org/
+
+accepted upstream, expected mainline in 6.11
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Date: Sat, 22 Jun 2024 01:03:40 +0300
+Subject: [PATCH v9 1/5] soc: qcom: pdr: protect locator_addr with the main
+ mutex
+
+If the service locator server is restarted fast enough, the PDR can
+rewrite locator_addr fields concurrently. Protect them by placing
+modification of those fields under the main pdr->lock.
+
+Fixes: fbe639b44a82 ("soc: qcom: Introduce Protection Domain Restart helpers")
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Tested-by: Steev Klimaszewski <steev@kali.org>
+Tested-by: Alexey Minnekhanov <alexeymin@postmarketos.org>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Reviewed-by: Chris Lew <quic_clew@quicinc.com>
+---
+ drivers/soc/qcom/pdr_interface.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c
+index a1b6a4081dea..76a62c2ecc58 100644
+--- a/drivers/soc/qcom/pdr_interface.c
++++ b/drivers/soc/qcom/pdr_interface.c
+@@ -76,12 +76,12 @@ static int pdr_locator_new_server(struct qmi_handle *qmi,
+ locator_hdl);
+ struct pdr_service *pds;
+
++ mutex_lock(&pdr->lock);
+ /* Create a local client port for QMI communication */
+ pdr->locator_addr.sq_family = AF_QIPCRTR;
+ pdr->locator_addr.sq_node = svc->node;
+ pdr->locator_addr.sq_port = svc->port;
+
+- mutex_lock(&pdr->lock);
+ pdr->locator_init_complete = true;
+ mutex_unlock(&pdr->lock);
+
+@@ -104,10 +104,10 @@ static void pdr_locator_del_server(struct qmi_handle *qmi,
+
+ mutex_lock(&pdr->lock);
+ pdr->locator_init_complete = false;
+- mutex_unlock(&pdr->lock);
+
+ pdr->locator_addr.sq_node = 0;
+ pdr->locator_addr.sq_port = 0;
++ mutex_unlock(&pdr->lock);
+ }
+
+ static const struct qmi_ops pdr_locator_ops = {
+@@ -365,12 +365,14 @@ static int pdr_get_domain_list(struct servreg_get_domain_list_req *req,
+ if (ret < 0)
+ return ret;
+
++ mutex_lock(&pdr->lock);
+ ret = qmi_send_request(&pdr->locator_hdl,
+ &pdr->locator_addr,
+ &txn, SERVREG_GET_DOMAIN_LIST_REQ,
+ SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN,
+ servreg_get_domain_list_req_ei,
+ req);
++ mutex_unlock(&pdr->lock);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ return ret;
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Date: Sat, 22 Jun 2024 01:03:41 +0300
+Subject: [PATCH v9 2/5] soc: qcom: pdr: fix parsing of domains lists
+
+While parsing the domains list, start offsets from 0 rather than from
+domains_read. The domains_read is equal to the total count of the
+domains we have seen, while the domains list in the message starts from
+offset 0.
+
+Fixes: fbe639b44a82 ("soc: qcom: Introduce Protection Domain Restart helpers")
+Tested-by: Steev Klimaszewski <steev@kali.org>
+Tested-by: Alexey Minnekhanov <alexeymin@postmarketos.org>
+Reviewed-by: Chris Lew <quic_clew@quicinc.com>
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+---
+ drivers/soc/qcom/pdr_interface.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c
+index 76a62c2ecc58..216166e98fae 100644
+--- a/drivers/soc/qcom/pdr_interface.c
++++ b/drivers/soc/qcom/pdr_interface.c
+@@ -417,7 +417,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds)
+ if (ret < 0)
+ goto out;
+
+- for (i = domains_read; i < resp->domain_list_len; i++) {
++ for (i = 0; i < resp->domain_list_len; i++) {
+ entry = &resp->domain_list[i];
+
+ if (strnlen(entry->name, sizeof(entry->name)) == sizeof(entry->name))
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Date: Sat, 22 Jun 2024 01:03:42 +0300
+Subject: [PATCH v9 3/5] soc: qcom: pdr: extract PDR message marshalling
+ data
+
+The in-kernel PD mapper is going to use same message structures as the
+QCOM_PDR_HELPERS module. Extract message marshalling data to separate
+module that can be used by both PDR helpers and by PD mapper.
+
+Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+Tested-by: Steev Klimaszewski <steev@kali.org>
+Tested-by: Alexey Minnekhanov <alexeymin@postmarketos.org>
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+---
+ drivers/soc/qcom/Kconfig | 4 +
+ drivers/soc/qcom/Makefile | 1 +
+ drivers/soc/qcom/pdr_internal.h | 306 ++------------------------------------
+ drivers/soc/qcom/qcom_pdr_msg.c | 319 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 334 insertions(+), 296 deletions(-)
+
+diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
+index 5af33b0e3470..95973c6b828f 100644
+--- a/drivers/soc/qcom/Kconfig
++++ b/drivers/soc/qcom/Kconfig
+@@ -75,8 +75,12 @@ config QCOM_OCMEM
+ config QCOM_PDR_HELPERS
+ tristate
+ select QCOM_QMI_HELPERS
++ select QCOM_PDR_MSG
+ depends on NET
+
++config QCOM_PDR_MSG
++ tristate
++
+ config QCOM_PMIC_PDCHARGER_ULOG
+ tristate "Qualcomm PMIC PDCharger ULOG driver"
+ depends on RPMSG
+diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
+index ca0bece0dfff..3110ac3288bc 100644
+--- a/drivers/soc/qcom/Makefile
++++ b/drivers/soc/qcom/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
+ obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
+ obj-$(CONFIG_QCOM_OCMEM) += ocmem.o
+ obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o
++obj-$(CONFIG_QCOM_PDR_MSG) += qcom_pdr_msg.o
+ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
+ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
+ obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
+diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h
+index 03c282b7f17e..7e5bb5a95275 100644
+--- a/drivers/soc/qcom/pdr_internal.h
++++ b/drivers/soc/qcom/pdr_internal.h
+@@ -28,83 +28,12 @@ struct servreg_location_entry {
+ u32 instance;
+ };
+
+-static const struct qmi_elem_info servreg_location_entry_ei[] = {
+- {
+- .data_type = QMI_STRING,
+- .elem_len = SERVREG_NAME_LENGTH + 1,
+- .elem_size = sizeof(char),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0,
+- .offset = offsetof(struct servreg_location_entry,
+- name),
+- },
+- {
+- .data_type = QMI_UNSIGNED_4_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u32),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0,
+- .offset = offsetof(struct servreg_location_entry,
+- instance),
+- },
+- {
+- .data_type = QMI_UNSIGNED_1_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0,
+- .offset = offsetof(struct servreg_location_entry,
+- service_data_valid),
+- },
+- {
+- .data_type = QMI_UNSIGNED_4_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u32),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0,
+- .offset = offsetof(struct servreg_location_entry,
+- service_data),
+- },
+- {}
+-};
+-
+ struct servreg_get_domain_list_req {
+ char service_name[SERVREG_NAME_LENGTH + 1];
+ u8 domain_offset_valid;
+ u32 domain_offset;
+ };
+
+-static const struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
+- {
+- .data_type = QMI_STRING,
+- .elem_len = SERVREG_NAME_LENGTH + 1,
+- .elem_size = sizeof(char),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x01,
+- .offset = offsetof(struct servreg_get_domain_list_req,
+- service_name),
+- },
+- {
+- .data_type = QMI_OPT_FLAG,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x10,
+- .offset = offsetof(struct servreg_get_domain_list_req,
+- domain_offset_valid),
+- },
+- {
+- .data_type = QMI_UNSIGNED_4_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u32),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x10,
+- .offset = offsetof(struct servreg_get_domain_list_req,
+- domain_offset),
+- },
+- {}
+-};
+-
+ struct servreg_get_domain_list_resp {
+ struct qmi_response_type_v01 resp;
+ u8 total_domains_valid;
+@@ -116,264 +45,49 @@ struct servreg_get_domain_list_resp {
+ struct servreg_location_entry domain_list[SERVREG_DOMAIN_LIST_LENGTH];
+ };
+
+-static const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
+- {
+- .data_type = QMI_STRUCT,
+- .elem_len = 1,
+- .elem_size = sizeof(struct qmi_response_type_v01),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x02,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- resp),
+- .ei_array = qmi_response_type_v01_ei,
+- },
+- {
+- .data_type = QMI_OPT_FLAG,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x10,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- total_domains_valid),
+- },
+- {
+- .data_type = QMI_UNSIGNED_2_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u16),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x10,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- total_domains),
+- },
+- {
+- .data_type = QMI_OPT_FLAG,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x11,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- db_rev_count_valid),
+- },
+- {
+- .data_type = QMI_UNSIGNED_2_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u16),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x11,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- db_rev_count),
+- },
+- {
+- .data_type = QMI_OPT_FLAG,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x12,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- domain_list_valid),
+- },
+- {
+- .data_type = QMI_DATA_LEN,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x12,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- domain_list_len),
+- },
+- {
+- .data_type = QMI_STRUCT,
+- .elem_len = SERVREG_DOMAIN_LIST_LENGTH,
+- .elem_size = sizeof(struct servreg_location_entry),
+- .array_type = VAR_LEN_ARRAY,
+- .tlv_type = 0x12,
+- .offset = offsetof(struct servreg_get_domain_list_resp,
+- domain_list),
+- .ei_array = servreg_location_entry_ei,
+- },
+- {}
+-};
+-
+ struct servreg_register_listener_req {
+ u8 enable;
+ char service_path[SERVREG_NAME_LENGTH + 1];
+ };
+
+-static const struct qmi_elem_info servreg_register_listener_req_ei[] = {
+- {
+- .data_type = QMI_UNSIGNED_1_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x01,
+- .offset = offsetof(struct servreg_register_listener_req,
+- enable),
+- },
+- {
+- .data_type = QMI_STRING,
+- .elem_len = SERVREG_NAME_LENGTH + 1,
+- .elem_size = sizeof(char),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x02,
+- .offset = offsetof(struct servreg_register_listener_req,
+- service_path),
+- },
+- {}
+-};
+-
+ struct servreg_register_listener_resp {
+ struct qmi_response_type_v01 resp;
+ u8 curr_state_valid;
+ enum servreg_service_state curr_state;
+ };
+
+-static const struct qmi_elem_info servreg_register_listener_resp_ei[] = {
+- {
+- .data_type = QMI_STRUCT,
+- .elem_len = 1,
+- .elem_size = sizeof(struct qmi_response_type_v01),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x02,
+- .offset = offsetof(struct servreg_register_listener_resp,
+- resp),
+- .ei_array = qmi_response_type_v01_ei,
+- },
+- {
+- .data_type = QMI_OPT_FLAG,
+- .elem_len = 1,
+- .elem_size = sizeof(u8),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x10,
+- .offset = offsetof(struct servreg_register_listener_resp,
+- curr_state_valid),
+- },
+- {
+- .data_type = QMI_SIGNED_4_BYTE_ENUM,
+- .elem_len = 1,
+- .elem_size = sizeof(enum servreg_service_state),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x10,
+- .offset = offsetof(struct servreg_register_listener_resp,
+- curr_state),
+- },
+- {}
+-};
+-
+ struct servreg_restart_pd_req {
+ char service_path[SERVREG_NAME_LENGTH + 1];
+ };
+
+-static const struct qmi_elem_info servreg_restart_pd_req_ei[] = {
+- {
+- .data_type = QMI_STRING,
+- .elem_len = SERVREG_NAME_LENGTH + 1,
+- .elem_size = sizeof(char),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x01,
+- .offset = offsetof(struct servreg_restart_pd_req,
+- service_path),
+- },
+- {}
+-};
+-
+ struct servreg_restart_pd_resp {
+ struct qmi_response_type_v01 resp;
+ };
+
+-static const struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
+- {
+- .data_type = QMI_STRUCT,
+- .elem_len = 1,
+- .elem_size = sizeof(struct qmi_response_type_v01),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x02,
+- .offset = offsetof(struct servreg_restart_pd_resp,
+- resp),
+- .ei_array = qmi_response_type_v01_ei,
+- },
+- {}
+-};
+-
+ struct servreg_state_updated_ind {
+ enum servreg_service_state curr_state;
+ char service_path[SERVREG_NAME_LENGTH + 1];
+ u16 transaction_id;
+ };
+
+-static const struct qmi_elem_info servreg_state_updated_ind_ei[] = {
+- {
+- .data_type = QMI_SIGNED_4_BYTE_ENUM,
+- .elem_len = 1,
+- .elem_size = sizeof(u32),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x01,
+- .offset = offsetof(struct servreg_state_updated_ind,
+- curr_state),
+- },
+- {
+- .data_type = QMI_STRING,
+- .elem_len = SERVREG_NAME_LENGTH + 1,
+- .elem_size = sizeof(char),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x02,
+- .offset = offsetof(struct servreg_state_updated_ind,
+- service_path),
+- },
+- {
+- .data_type = QMI_UNSIGNED_2_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u16),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x03,
+- .offset = offsetof(struct servreg_state_updated_ind,
+- transaction_id),
+- },
+- {}
+-};
+-
+ struct servreg_set_ack_req {
+ char service_path[SERVREG_NAME_LENGTH + 1];
+ u16 transaction_id;
+ };
+
+-static const struct qmi_elem_info servreg_set_ack_req_ei[] = {
+- {
+- .data_type = QMI_STRING,
+- .elem_len = SERVREG_NAME_LENGTH + 1,
+- .elem_size = sizeof(char),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x01,
+- .offset = offsetof(struct servreg_set_ack_req,
+- service_path),
+- },
+- {
+- .data_type = QMI_UNSIGNED_2_BYTE,
+- .elem_len = 1,
+- .elem_size = sizeof(u16),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x02,
+- .offset = offsetof(struct servreg_set_ack_req,
+- transaction_id),
+- },
+- {}
+-};
+-
+ struct servreg_set_ack_resp {
+ struct qmi_response_type_v01 resp;
+ };
+
+-static const struct qmi_elem_info servreg_set_ack_resp_ei[] = {
+- {
+- .data_type = QMI_STRUCT,
+- .elem_len = 1,
+- .elem_size = sizeof(struct qmi_response_type_v01),
+- .array_type = NO_ARRAY,
+- .tlv_type = 0x02,
+- .offset = offsetof(struct servreg_set_ack_resp,
+- resp),
+- .ei_array = qmi_response_type_v01_ei,
+- },
+- {}
+-};
++extern const struct qmi_elem_info servreg_location_entry_ei[];
++extern const struct qmi_elem_info servreg_get_domain_list_req_ei[];
++extern const struct qmi_elem_info servreg_get_domain_list_resp_ei[];
++extern const struct qmi_elem_info servreg_register_listener_req_ei[];
++extern const struct qmi_elem_info servreg_register_listener_resp_ei[];
++extern const struct qmi_elem_info servreg_restart_pd_req_ei[];
++extern const struct qmi_elem_info servreg_restart_pd_resp_ei[];
++extern const struct qmi_elem_info servreg_state_updated_ind_ei[];
++extern const struct qmi_elem_info servreg_set_ack_req_ei[];
++extern const struct qmi_elem_info servreg_set_ack_resp_ei[];
+
+ #endif
+diff --git a/drivers/soc/qcom/qcom_pdr_msg.c b/drivers/soc/qcom/qcom_pdr_msg.c
+new file mode 100644
+index 000000000000..9b46f42aa146
+--- /dev/null
++++ b/drivers/soc/qcom/qcom_pdr_msg.c
+@@ -0,0 +1,319 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2020 The Linux Foundation. All rights reserved.
++ */
++
++#include <linux/module.h>
++#include <linux/soc/qcom/qmi.h>
++
++#include "pdr_internal.h"
++
++const struct qmi_elem_info servreg_location_entry_ei[] = {
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0,
++ .offset = offsetof(struct servreg_location_entry,
++ name),
++ },
++ {
++ .data_type = QMI_UNSIGNED_4_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u32),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0,
++ .offset = offsetof(struct servreg_location_entry,
++ instance),
++ },
++ {
++ .data_type = QMI_UNSIGNED_1_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0,
++ .offset = offsetof(struct servreg_location_entry,
++ service_data_valid),
++ },
++ {
++ .data_type = QMI_UNSIGNED_4_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u32),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0,
++ .offset = offsetof(struct servreg_location_entry,
++ service_data),
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_location_entry_ei);
++
++const struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x01,
++ .offset = offsetof(struct servreg_get_domain_list_req,
++ service_name),
++ },
++ {
++ .data_type = QMI_OPT_FLAG,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x10,
++ .offset = offsetof(struct servreg_get_domain_list_req,
++ domain_offset_valid),
++ },
++ {
++ .data_type = QMI_UNSIGNED_4_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u32),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x10,
++ .offset = offsetof(struct servreg_get_domain_list_req,
++ domain_offset),
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_get_domain_list_req_ei);
++
++const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
++ {
++ .data_type = QMI_STRUCT,
++ .elem_len = 1,
++ .elem_size = sizeof(struct qmi_response_type_v01),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ resp),
++ .ei_array = qmi_response_type_v01_ei,
++ },
++ {
++ .data_type = QMI_OPT_FLAG,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x10,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ total_domains_valid),
++ },
++ {
++ .data_type = QMI_UNSIGNED_2_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u16),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x10,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ total_domains),
++ },
++ {
++ .data_type = QMI_OPT_FLAG,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x11,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ db_rev_count_valid),
++ },
++ {
++ .data_type = QMI_UNSIGNED_2_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u16),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x11,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ db_rev_count),
++ },
++ {
++ .data_type = QMI_OPT_FLAG,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x12,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ domain_list_valid),
++ },
++ {
++ .data_type = QMI_DATA_LEN,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x12,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ domain_list_len),
++ },
++ {
++ .data_type = QMI_STRUCT,
++ .elem_len = SERVREG_DOMAIN_LIST_LENGTH,
++ .elem_size = sizeof(struct servreg_location_entry),
++ .array_type = VAR_LEN_ARRAY,
++ .tlv_type = 0x12,
++ .offset = offsetof(struct servreg_get_domain_list_resp,
++ domain_list),
++ .ei_array = servreg_location_entry_ei,
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_get_domain_list_resp_ei);
++
++const struct qmi_elem_info servreg_register_listener_req_ei[] = {
++ {
++ .data_type = QMI_UNSIGNED_1_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x01,
++ .offset = offsetof(struct servreg_register_listener_req,
++ enable),
++ },
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_register_listener_req,
++ service_path),
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_register_listener_req_ei);
++
++const struct qmi_elem_info servreg_register_listener_resp_ei[] = {
++ {
++ .data_type = QMI_STRUCT,
++ .elem_len = 1,
++ .elem_size = sizeof(struct qmi_response_type_v01),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_register_listener_resp,
++ resp),
++ .ei_array = qmi_response_type_v01_ei,
++ },
++ {
++ .data_type = QMI_OPT_FLAG,
++ .elem_len = 1,
++ .elem_size = sizeof(u8),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x10,
++ .offset = offsetof(struct servreg_register_listener_resp,
++ curr_state_valid),
++ },
++ {
++ .data_type = QMI_SIGNED_4_BYTE_ENUM,
++ .elem_len = 1,
++ .elem_size = sizeof(enum servreg_service_state),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x10,
++ .offset = offsetof(struct servreg_register_listener_resp,
++ curr_state),
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_register_listener_resp_ei);
++
++const struct qmi_elem_info servreg_restart_pd_req_ei[] = {
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x01,
++ .offset = offsetof(struct servreg_restart_pd_req,
++ service_path),
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_restart_pd_req_ei);
++
++const struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
++ {
++ .data_type = QMI_STRUCT,
++ .elem_len = 1,
++ .elem_size = sizeof(struct qmi_response_type_v01),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_restart_pd_resp,
++ resp),
++ .ei_array = qmi_response_type_v01_ei,
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_restart_pd_resp_ei);
++
++const struct qmi_elem_info servreg_state_updated_ind_ei[] = {
++ {
++ .data_type = QMI_SIGNED_4_BYTE_ENUM,
++ .elem_len = 1,
++ .elem_size = sizeof(u32),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x01,
++ .offset = offsetof(struct servreg_state_updated_ind,
++ curr_state),
++ },
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_state_updated_ind,
++ service_path),
++ },
++ {
++ .data_type = QMI_UNSIGNED_2_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u16),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x03,
++ .offset = offsetof(struct servreg_state_updated_ind,
++ transaction_id),
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_state_updated_ind_ei);
++
++const struct qmi_elem_info servreg_set_ack_req_ei[] = {
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x01,
++ .offset = offsetof(struct servreg_set_ack_req,
++ service_path),
++ },
++ {
++ .data_type = QMI_UNSIGNED_2_BYTE,
++ .elem_len = 1,
++ .elem_size = sizeof(u16),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_set_ack_req,
++ transaction_id),
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_set_ack_req_ei);
++
++const struct qmi_elem_info servreg_set_ack_resp_ei[] = {
++ {
++ .data_type = QMI_STRUCT,
++ .elem_len = 1,
++ .elem_size = sizeof(struct qmi_response_type_v01),
++ .array_type = NO_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_set_ack_resp,
++ resp),
++ .ei_array = qmi_response_type_v01_ei,
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_set_ack_resp_ei);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Qualcomm Protection Domain messages data");
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Date: Sat, 22 Jun 2024 01:03:43 +0300
+Subject: [PATCH v9 4/5] soc: qcom: add pd-mapper implementation
+
+Existing userspace protection domain mapper implementation has several
+issue. It doesn't play well with CONFIG_EXTRA_FIRMWARE, it doesn't
+reread JSON files if firmware location is changed (or if firmware was
+not available at the time pd-mapper was started but the corresponding
+directory is mounted later), etc.
+
+Provide in-kernel service implementing protection domain mapping
+required to work with several services, which are provided by the DSP
+firmware.
+
+This module is loaded automatically by the remoteproc drivers when
+necessary via the symbol dependency. It uses a root node to match a
+protection domains map for a particular board. It is not possible to
+implement it as a 'driver' as there is no corresponding device.
+
+Tested-by: Steev Klimaszewski <steev@kali.org>
+Tested-by: Alexey Minnekhanov <alexeymin@postmarketos.org>
+Reviewed-by: Chris Lew <quic_clew@quicinc.com>
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+---
+ drivers/soc/qcom/Kconfig | 11 +
+ drivers/soc/qcom/Makefile | 1 +
+ drivers/soc/qcom/pdr_internal.h | 14 +
+ drivers/soc/qcom/qcom_pd_mapper.c | 676 ++++++++++++++++++++++++++++++++++++++
+ drivers/soc/qcom/qcom_pdr_msg.c | 34 ++
+ 5 files changed, 736 insertions(+)
+
+diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
+index 95973c6b828f..0a2f2bfd7863 100644
+--- a/drivers/soc/qcom/Kconfig
++++ b/drivers/soc/qcom/Kconfig
+@@ -72,6 +72,17 @@ config QCOM_OCMEM
+ requirements. This is typically used by the GPU, camera/video, and
+ audio components on some Snapdragon SoCs.
+
++config QCOM_PD_MAPPER
++ tristate "Qualcomm Protection Domain Mapper"
++ select QCOM_QMI_HELPERS
++ depends on NET && QRTR
++ default QCOM_RPROC_COMMON
++ help
++ The Protection Domain Mapper maps registered services to the domains
++ and instances handled by the remote DSPs. This is a kernel-space
++ implementation of the service. It is a simpler alternative to the
++ userspace daemon.
++
+ config QCOM_PDR_HELPERS
+ tristate
+ select QCOM_QMI_HELPERS
+diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
+index 3110ac3288bc..d3560f861085 100644
+--- a/drivers/soc/qcom/Makefile
++++ b/drivers/soc/qcom/Makefile
+@@ -7,6 +7,7 @@ obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
+ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
+ obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
+ obj-$(CONFIG_QCOM_OCMEM) += ocmem.o
++obj-$(CONFIG_QCOM_PD_MAPPER) += qcom_pd_mapper.o
+ obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o
+ obj-$(CONFIG_QCOM_PDR_MSG) += qcom_pdr_msg.o
+ obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
+diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h
+index 7e5bb5a95275..8d17f7fb79e7 100644
+--- a/drivers/soc/qcom/pdr_internal.h
++++ b/drivers/soc/qcom/pdr_internal.h
+@@ -13,6 +13,8 @@
+ #define SERVREG_SET_ACK_REQ 0x23
+ #define SERVREG_RESTART_PD_REQ 0x24
+
++#define SERVREG_LOC_PFR_REQ 0x24
++
+ #define SERVREG_DOMAIN_LIST_LENGTH 32
+ #define SERVREG_RESTART_PD_REQ_MAX_LEN 67
+ #define SERVREG_REGISTER_LISTENER_REQ_LEN 71
+@@ -20,6 +22,7 @@
+ #define SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN 74
+ #define SERVREG_STATE_UPDATED_IND_MAX_LEN 79
+ #define SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN 2389
++#define SERVREG_LOC_PFR_RESP_MAX_LEN 10
+
+ struct servreg_location_entry {
+ char name[SERVREG_NAME_LENGTH + 1];
+@@ -79,6 +82,15 @@ struct servreg_set_ack_resp {
+ struct qmi_response_type_v01 resp;
+ };
+
++struct servreg_loc_pfr_req {
++ char service[SERVREG_NAME_LENGTH + 1];
++ char reason[257];
++};
++
++struct servreg_loc_pfr_resp {
++ struct qmi_response_type_v01 rsp;
++};
++
+ extern const struct qmi_elem_info servreg_location_entry_ei[];
+ extern const struct qmi_elem_info servreg_get_domain_list_req_ei[];
+ extern const struct qmi_elem_info servreg_get_domain_list_resp_ei[];
+@@ -89,5 +101,7 @@ extern const struct qmi_elem_info servreg_restart_pd_resp_ei[];
+ extern const struct qmi_elem_info servreg_state_updated_ind_ei[];
+ extern const struct qmi_elem_info servreg_set_ack_req_ei[];
+ extern const struct qmi_elem_info servreg_set_ack_resp_ei[];
++extern const struct qmi_elem_info servreg_loc_pfr_req_ei[];
++extern const struct qmi_elem_info servreg_loc_pfr_resp_ei[];
+
+ #endif
+diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c
+new file mode 100644
+index 000000000000..ecb64f06527f
+--- /dev/null
++++ b/drivers/soc/qcom/qcom_pd_mapper.c
+@@ -0,0 +1,676 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Qualcomm Protection Domain mapper
++ *
++ * Copyright (c) 2023 Linaro Ltd.
++ */
++
++#include <linux/auxiliary_bus.h>
++#include <linux/kernel.h>
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/refcount.h>
++#include <linux/soc/qcom/qmi.h>
++
++#include "pdr_internal.h"
++
++#define SERVREG_QMI_VERSION 0x101
++#define SERVREG_QMI_INSTANCE 0
++
++#define TMS_SERVREG_SERVICE "tms/servreg"
++
++struct qcom_pdm_domain_data {
++ const char *domain;
++ u32 instance_id;
++ /* NULL-terminated array */
++ const char * services[];
++};
++
++struct qcom_pdm_domain {
++ struct list_head list;
++ const char *name;
++ u32 instance_id;
++};
++
++struct qcom_pdm_service {
++ struct list_head list;
++ struct list_head domains;
++ const char *name;
++};
++
++struct qcom_pdm_data {
++ refcount_t refcnt;
++ struct qmi_handle handle;
++ struct list_head services;
++};
++
++static DEFINE_MUTEX(qcom_pdm_mutex); /* protects __qcom_pdm_data */
++static struct qcom_pdm_data *__qcom_pdm_data;
++
++static struct qcom_pdm_service *qcom_pdm_find(struct qcom_pdm_data *data,
++ const char *name)
++{
++ struct qcom_pdm_service *service;
++
++ list_for_each_entry(service, &data->services, list) {
++ if (!strcmp(service->name, name))
++ return service;
++ }
++
++ return NULL;
++}
++
++static int qcom_pdm_add_service_domain(struct qcom_pdm_data *data,
++ const char *service_name,
++ const char *domain_name,
++ u32 instance_id)
++{
++ struct qcom_pdm_service *service;
++ struct qcom_pdm_domain *domain;
++
++ service = qcom_pdm_find(data, service_name);
++ if (service) {
++ list_for_each_entry(domain, &service->domains, list) {
++ if (!strcmp(domain->name, domain_name))
++ return -EBUSY;
++ }
++ } else {
++ service = kzalloc(sizeof(*service), GFP_KERNEL);
++ if (!service)
++ return -ENOMEM;
++
++ INIT_LIST_HEAD(&service->domains);
++ service->name = service_name;
++
++ list_add_tail(&service->list, &data->services);
++ }
++
++ domain = kzalloc(sizeof(*domain), GFP_KERNEL);
++ if (!domain) {
++ if (list_empty(&service->domains)) {
++ list_del(&service->list);
++ kfree(service);
++ }
++
++ return -ENOMEM;
++ }
++
++ domain->name = domain_name;
++ domain->instance_id = instance_id;
++ list_add_tail(&domain->list, &service->domains);
++
++ return 0;
++}
++
++static int qcom_pdm_add_domain(struct qcom_pdm_data *data,
++ const struct qcom_pdm_domain_data *domain)
++{
++ int ret;
++ int i;
++
++ ret = qcom_pdm_add_service_domain(data,
++ TMS_SERVREG_SERVICE,
++ domain->domain,
++ domain->instance_id);
++ if (ret)
++ return ret;
++
++ for (i = 0; domain->services[i]; i++) {
++ ret = qcom_pdm_add_service_domain(data,
++ domain->services[i],
++ domain->domain,
++ domain->instance_id);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++
++}
++
++static void qcom_pdm_free_domains(struct qcom_pdm_data *data)
++{
++ struct qcom_pdm_service *service, *tservice;
++ struct qcom_pdm_domain *domain, *tdomain;
++
++ list_for_each_entry_safe(service, tservice, &data->services, list) {
++ list_for_each_entry_safe(domain, tdomain, &service->domains, list) {
++ list_del(&domain->list);
++ kfree(domain);
++ }
++
++ list_del(&service->list);
++ kfree(service);
++ }
++}
++
++static void qcom_pdm_get_domain_list(struct qmi_handle *qmi,
++ struct sockaddr_qrtr *sq,
++ struct qmi_txn *txn,
++ const void *decoded)
++{
++ struct qcom_pdm_data *data = container_of(qmi, struct qcom_pdm_data, handle);
++ const struct servreg_get_domain_list_req *req = decoded;
++ struct servreg_get_domain_list_resp *rsp;
++ struct qcom_pdm_service *service;
++ u32 offset;
++ int ret;
++
++ rsp = kzalloc(sizeof(*rsp), GFP_KERNEL);
++ if (!rsp)
++ return;
++
++ offset = req->domain_offset_valid ? req->domain_offset : 0;
++
++ rsp->resp.result = QMI_RESULT_SUCCESS_V01;
++ rsp->resp.error = QMI_ERR_NONE_V01;
++
++ rsp->db_rev_count_valid = true;
++ rsp->db_rev_count = 1;
++
++ rsp->total_domains_valid = true;
++ rsp->total_domains = 0;
++
++ mutex_lock(&qcom_pdm_mutex);
++
++ service = qcom_pdm_find(data, req->service_name);
++ if (service) {
++ struct qcom_pdm_domain *domain;
++
++ rsp->domain_list_valid = true;
++ rsp->domain_list_len = 0;
++
++ list_for_each_entry(domain, &service->domains, list) {
++ u32 i = rsp->total_domains++;
++
++ if (i >= offset && i < SERVREG_DOMAIN_LIST_LENGTH) {
++ u32 j = rsp->domain_list_len++;
++
++ strscpy(rsp->domain_list[j].name, domain->name,
++ sizeof(rsp->domain_list[i].name));
++ rsp->domain_list[j].instance = domain->instance_id;
++
++ pr_debug("PDM: found %s / %d\n", domain->name,
++ domain->instance_id);
++ }
++ }
++ }
++
++ pr_debug("PDM: service '%s' offset %d returning %d domains (of %d)\n", req->service_name,
++ req->domain_offset_valid ? req->domain_offset : -1, rsp->domain_list_len, rsp->total_domains);
++
++ ret = qmi_send_response(qmi, sq, txn, SERVREG_GET_DOMAIN_LIST_REQ,
++ SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN,
++ servreg_get_domain_list_resp_ei, rsp);
++ if (ret)
++ pr_err("Error sending servreg response: %d\n", ret);
++
++ mutex_unlock(&qcom_pdm_mutex);
++
++ kfree(rsp);
++}
++
++static void qcom_pdm_pfr(struct qmi_handle *qmi,
++ struct sockaddr_qrtr *sq,
++ struct qmi_txn *txn,
++ const void *decoded)
++{
++ const struct servreg_loc_pfr_req *req = decoded;
++ struct servreg_loc_pfr_resp rsp = {};
++ int ret;
++
++ pr_warn_ratelimited("PDM: service '%s' crash: '%s'\n", req->service, req->reason);
++
++ rsp.rsp.result = QMI_RESULT_SUCCESS_V01;
++ rsp.rsp.error = QMI_ERR_NONE_V01;
++
++ ret = qmi_send_response(qmi, sq, txn, SERVREG_LOC_PFR_REQ,
++ SERVREG_LOC_PFR_RESP_MAX_LEN,
++ servreg_loc_pfr_resp_ei, &rsp);
++ if (ret)
++ pr_err("Error sending servreg response: %d\n", ret);
++}
++
++static const struct qmi_msg_handler qcom_pdm_msg_handlers[] = {
++ {
++ .type = QMI_REQUEST,
++ .msg_id = SERVREG_GET_DOMAIN_LIST_REQ,
++ .ei = servreg_get_domain_list_req_ei,
++ .decoded_size = sizeof(struct servreg_get_domain_list_req),
++ .fn = qcom_pdm_get_domain_list,
++ },
++ {
++ .type = QMI_REQUEST,
++ .msg_id = SERVREG_LOC_PFR_REQ,
++ .ei = servreg_loc_pfr_req_ei,
++ .decoded_size = sizeof(struct servreg_loc_pfr_req),
++ .fn = qcom_pdm_pfr,
++ },
++ { },
++};
++
++static const struct qcom_pdm_domain_data adsp_audio_pd = {
++ .domain = "msm/adsp/audio_pd",
++ .instance_id = 74,
++ .services = {
++ "avs/audio",
++ NULL,
++ },
++};
++
++static const struct qcom_pdm_domain_data adsp_charger_pd = {
++ .domain = "msm/adsp/charger_pd",
++ .instance_id = 74,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data adsp_root_pd = {
++ .domain = "msm/adsp/root_pd",
++ .instance_id = 74,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data adsp_root_pd_pdr = {
++ .domain = "msm/adsp/root_pd",
++ .instance_id = 74,
++ .services = {
++ "tms/pdr_enabled",
++ NULL,
++ },
++};
++
++static const struct qcom_pdm_domain_data adsp_sensor_pd = {
++ .domain = "msm/adsp/sensor_pd",
++ .instance_id = 74,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data msm8996_adsp_audio_pd = {
++ .domain = "msm/adsp/audio_pd",
++ .instance_id = 4,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data msm8996_adsp_root_pd = {
++ .domain = "msm/adsp/root_pd",
++ .instance_id = 4,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data cdsp_root_pd = {
++ .domain = "msm/cdsp/root_pd",
++ .instance_id = 76,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data slpi_root_pd = {
++ .domain = "msm/slpi/root_pd",
++ .instance_id = 90,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data slpi_sensor_pd = {
++ .domain = "msm/slpi/sensor_pd",
++ .instance_id = 90,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data mpss_root_pd = {
++ .domain = "msm/modem/root_pd",
++ .instance_id = 180,
++ .services = {
++ NULL,
++ },
++};
++
++static const struct qcom_pdm_domain_data mpss_root_pd_gps = {
++ .domain = "msm/modem/root_pd",
++ .instance_id = 180,
++ .services = {
++ "gps/gps_service",
++ NULL,
++ },
++};
++
++static const struct qcom_pdm_domain_data mpss_root_pd_gps_pdr = {
++ .domain = "msm/modem/root_pd",
++ .instance_id = 180,
++ .services = {
++ "gps/gps_service",
++ "tms/pdr_enabled",
++ NULL,
++ },
++};
++
++static const struct qcom_pdm_domain_data msm8996_mpss_root_pd = {
++ .domain = "msm/modem/root_pd",
++ .instance_id = 100,
++ .services = { NULL },
++};
++
++static const struct qcom_pdm_domain_data mpss_wlan_pd = {
++ .domain = "msm/modem/wlan_pd",
++ .instance_id = 180,
++ .services = {
++ "kernel/elf_loader",
++ "wlan/fw",
++ NULL,
++ },
++};
++
++static const struct qcom_pdm_domain_data *msm8996_domains[] = {
++ &msm8996_adsp_audio_pd,
++ &msm8996_adsp_root_pd,
++ &msm8996_mpss_root_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *msm8998_domains[] = {
++ &mpss_root_pd,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *qcm2290_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &adsp_sensor_pd,
++ &mpss_root_pd_gps,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *qcs404_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &adsp_sensor_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sc7180_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd_pdr,
++ &adsp_sensor_pd,
++ &mpss_root_pd_gps_pdr,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sc7280_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd_pdr,
++ &adsp_charger_pd,
++ &adsp_sensor_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd_gps_pdr,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sc8180x_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &adsp_charger_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd_gps,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sc8280xp_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd_pdr,
++ &adsp_charger_pd,
++ &cdsp_root_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sdm660_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &adsp_sensor_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sdm670_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sdm845_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd,
++ &mpss_wlan_pd,
++ &slpi_root_pd,
++ &slpi_sensor_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sm6115_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &adsp_sensor_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd_gps,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sm6350_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &adsp_sensor_pd,
++ &cdsp_root_pd,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sm8150_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd_gps,
++ &mpss_wlan_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sm8250_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &cdsp_root_pd,
++ &slpi_root_pd,
++ &slpi_sensor_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sm8350_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd_pdr,
++ &adsp_charger_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd_gps,
++ &slpi_root_pd,
++ &slpi_sensor_pd,
++ NULL,
++};
++
++static const struct qcom_pdm_domain_data *sm8550_domains[] = {
++ &adsp_audio_pd,
++ &adsp_root_pd,
++ &adsp_charger_pd,
++ &adsp_sensor_pd,
++ &cdsp_root_pd,
++ &mpss_root_pd_gps,
++ NULL,
++};
++
++static const struct of_device_id qcom_pdm_domains[] = {
++ { .compatible = "qcom,apq8064", .data = NULL, },
++ { .compatible = "qcom,apq8074", .data = NULL, },
++ { .compatible = "qcom,apq8084", .data = NULL, },
++ { .compatible = "qcom,apq8096", .data = msm8996_domains, },
++ { .compatible = "qcom,msm8226", .data = NULL, },
++ { .compatible = "qcom,msm8974", .data = NULL, },
++ { .compatible = "qcom,msm8996", .data = msm8996_domains, },
++ { .compatible = "qcom,msm8998", .data = msm8998_domains, },
++ { .compatible = "qcom,qcm2290", .data = qcm2290_domains, },
++ { .compatible = "qcom,qcs404", .data = qcs404_domains, },
++ { .compatible = "qcom,sc7180", .data = sc7180_domains, },
++ { .compatible = "qcom,sc7280", .data = sc7280_domains, },
++ { .compatible = "qcom,sc8180x", .data = sc8180x_domains, },
++ { .compatible = "qcom,sc8280xp", .data = sc8280xp_domains, },
++ { .compatible = "qcom,sda660", .data = sdm660_domains, },
++ { .compatible = "qcom,sdm660", .data = sdm660_domains, },
++ { .compatible = "qcom,sdm670", .data = sdm670_domains, },
++ { .compatible = "qcom,sdm845", .data = sdm845_domains, },
++ { .compatible = "qcom,sm4250", .data = sm6115_domains, },
++ { .compatible = "qcom,sm6115", .data = sm6115_domains, },
++ { .compatible = "qcom,sm6350", .data = sm6350_domains, },
++ { .compatible = "qcom,sm8150", .data = sm8150_domains, },
++ { .compatible = "qcom,sm8250", .data = sm8250_domains, },
++ { .compatible = "qcom,sm8350", .data = sm8350_domains, },
++ { .compatible = "qcom,sm8450", .data = sm8350_domains, },
++ { .compatible = "qcom,sm8550", .data = sm8550_domains, },
++ { .compatible = "qcom,sm8650", .data = sm8550_domains, },
++ {},
++};
++
++static void qcom_pdm_stop(struct qcom_pdm_data *data)
++{
++ qcom_pdm_free_domains(data);
++
++ /* The server is removed automatically */
++ qmi_handle_release(&data->handle);
++
++ kfree(data);
++}
++
++static struct qcom_pdm_data *qcom_pdm_start(void)
++{
++ const struct qcom_pdm_domain_data * const *domains;
++ const struct of_device_id *match;
++ struct qcom_pdm_data *data;
++ struct device_node *root;
++ int ret, i;
++
++ root = of_find_node_by_path("/");
++ if (!root)
++ return ERR_PTR(-ENODEV);
++
++ match = of_match_node(qcom_pdm_domains, root);
++ of_node_put(root);
++ if (!match) {
++ pr_notice("PDM: no support for the platform, userspace daemon might be required.\n");
++ return ERR_PTR(-ENODEV);
++ }
++
++ domains = match->data;
++ if (!domains) {
++ pr_debug("PDM: no domains\n");
++ return ERR_PTR(-ENODEV);
++ }
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return ERR_PTR(-ENOMEM);
++
++ INIT_LIST_HEAD(&data->services);
++
++ ret = qmi_handle_init(&data->handle, SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN,
++ NULL, qcom_pdm_msg_handlers);
++ if (ret) {
++ kfree(data);
++ return ERR_PTR(ret);
++ }
++
++ refcount_set(&data->refcnt, 1);
++
++ for (i = 0; domains[i]; i++) {
++ ret = qcom_pdm_add_domain(data, domains[i]);
++ if (ret)
++ goto err_stop;
++ }
++
++ ret = qmi_add_server(&data->handle, SERVREG_LOCATOR_SERVICE,
++ SERVREG_QMI_VERSION, SERVREG_QMI_INSTANCE);
++ if (ret) {
++ pr_err("PDM: error adding server %d\n", ret);
++ goto err_stop;
++ }
++
++ return data;
++
++err_stop:
++ qcom_pdm_stop(data);
++
++ return ERR_PTR(ret);
++}
++
++static int qcom_pdm_probe(struct auxiliary_device *auxdev,
++ const struct auxiliary_device_id *id)
++
++{
++ struct qcom_pdm_data *data;
++ int ret = 0;
++
++ mutex_lock(&qcom_pdm_mutex);
++
++ if (!__qcom_pdm_data) {
++ data = qcom_pdm_start();
++
++ if (IS_ERR(data))
++ ret = PTR_ERR(data);
++ else
++ __qcom_pdm_data = data;
++ }
++
++ auxiliary_set_drvdata(auxdev, __qcom_pdm_data);
++
++ mutex_unlock(&qcom_pdm_mutex);
++
++ return ret;
++}
++
++static void qcom_pdm_remove(struct auxiliary_device *auxdev)
++{
++ struct qcom_pdm_data *data;
++
++ data = auxiliary_get_drvdata(auxdev);
++ if (!data)
++ return;
++
++ if (refcount_dec_and_mutex_lock(&data->refcnt, &qcom_pdm_mutex)) {
++ __qcom_pdm_data = NULL;
++ qcom_pdm_stop(data);
++ mutex_unlock(&qcom_pdm_mutex);
++ }
++}
++
++static const struct auxiliary_device_id qcom_pdm_table[] = {
++ { .name = "qcom_common.pd-mapper" },
++ {},
++};
++MODULE_DEVICE_TABLE(auxiliary, qcom_pdm_table);
++
++static struct auxiliary_driver qcom_pdm_drv = {
++ .name = "qcom-pdm-mapper",
++ .id_table = qcom_pdm_table,
++ .probe = qcom_pdm_probe,
++ .remove = qcom_pdm_remove,
++};
++module_auxiliary_driver(qcom_pdm_drv);
++
++MODULE_DESCRIPTION("Qualcomm Protection Domain Mapper");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/soc/qcom/qcom_pdr_msg.c b/drivers/soc/qcom/qcom_pdr_msg.c
+index 9b46f42aa146..bf3e4a47165e 100644
+--- a/drivers/soc/qcom/qcom_pdr_msg.c
++++ b/drivers/soc/qcom/qcom_pdr_msg.c
+@@ -315,5 +315,39 @@ const struct qmi_elem_info servreg_set_ack_resp_ei[] = {
+ };
+ EXPORT_SYMBOL_GPL(servreg_set_ack_resp_ei);
+
++const struct qmi_elem_info servreg_loc_pfr_req_ei[] = {
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = VAR_LEN_ARRAY,
++ .tlv_type = 0x01,
++ .offset = offsetof(struct servreg_loc_pfr_req, service)
++ },
++ {
++ .data_type = QMI_STRING,
++ .elem_len = SERVREG_NAME_LENGTH + 1,
++ .elem_size = sizeof(char),
++ .array_type = VAR_LEN_ARRAY,
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_loc_pfr_req, reason)
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_loc_pfr_req_ei);
++
++const struct qmi_elem_info servreg_loc_pfr_resp_ei[] = {
++ {
++ .data_type = QMI_STRUCT,
++ .elem_len = 1,
++ .elem_size = sizeof_field(struct servreg_loc_pfr_resp, rsp),
++ .tlv_type = 0x02,
++ .offset = offsetof(struct servreg_loc_pfr_resp, rsp),
++ .ei_array = qmi_response_type_v01_ei,
++ },
++ {}
++};
++EXPORT_SYMBOL_GPL(servreg_loc_pfr_resp_ei);
++
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("Qualcomm Protection Domain messages data");
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Date: Sat, 22 Jun 2024 01:03:44 +0300
+Subject: [PATCH v9 5/5] remoteproc: qcom: enable in-kernel PD mapper
+
+Request in-kernel protection domain mapper to be started before starting
+Qualcomm DSP and release it once DSP is stopped. Once all DSPs are
+stopped, the PD mapper will be stopped too.
+
+Reviewed-by: Chris Lew <quic_clew@quicinc.com>
+Tested-by: Steev Klimaszewski <steev@kali.org>
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+---
+ drivers/remoteproc/qcom_common.c | 87 +++++++++++++++++++++++++++++++++++++
+ drivers/remoteproc/qcom_common.h | 10 +++++
+ drivers/remoteproc/qcom_q6v5_adsp.c | 3 ++
+ drivers/remoteproc/qcom_q6v5_mss.c | 3 ++
+ drivers/remoteproc/qcom_q6v5_pas.c | 3 ++
+ drivers/remoteproc/qcom_q6v5_wcss.c | 3 ++
+ 6 files changed, 109 insertions(+)
+
+diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c
+index 03e5f5d533eb..8c8688f99f0a 100644
+--- a/drivers/remoteproc/qcom_common.c
++++ b/drivers/remoteproc/qcom_common.c
+@@ -13,6 +13,7 @@
+ #include <linux/notifier.h>
+ #include <linux/remoteproc.h>
+ #include <linux/remoteproc/qcom_rproc.h>
++#include <linux/auxiliary_bus.h>
+ #include <linux/rpmsg/qcom_glink.h>
+ #include <linux/rpmsg/qcom_smd.h>
+ #include <linux/slab.h>
+@@ -25,6 +26,7 @@
+ #define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev)
+ #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev)
+ #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev)
++#define to_pdm_subdev(d) container_of(d, struct qcom_rproc_pdm, subdev)
+
+ #define MAX_NUM_OF_SS 10
+ #define MAX_REGION_NAME_LENGTH 16
+@@ -519,5 +521,90 @@ void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr)
+ }
+ EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev);
+
++static void pdm_dev_release(struct device *dev)
++{
++ struct auxiliary_device *adev = to_auxiliary_dev(dev);
++
++ kfree(adev);
++}
++
++static int pdm_notify_prepare(struct rproc_subdev *subdev)
++{
++ struct qcom_rproc_pdm *pdm = to_pdm_subdev(subdev);
++ struct auxiliary_device *adev;
++ int ret;
++
++ adev = kzalloc(sizeof(*adev), GFP_KERNEL);
++ if (!adev)
++ return -ENOMEM;
++
++ adev->dev.parent = pdm->dev;
++ adev->dev.release = pdm_dev_release;
++ adev->name = "pd-mapper";
++ adev->id = pdm->index;
++
++ ret = auxiliary_device_init(adev);
++ if (ret) {
++ kfree(adev);
++ return ret;
++ }
++
++ ret = auxiliary_device_add(adev);
++ if (ret) {
++ auxiliary_device_uninit(adev);
++ return ret;
++ }
++
++ pdm->adev = adev;
++
++ return 0;
++}
++
++
++static void pdm_notify_unprepare(struct rproc_subdev *subdev)
++{
++ struct qcom_rproc_pdm *pdm = to_pdm_subdev(subdev);
++
++ if (!pdm->adev)
++ return;
++
++ auxiliary_device_delete(pdm->adev);
++ auxiliary_device_uninit(pdm->adev);
++ pdm->adev = NULL;
++}
++
++/**
++ * qcom_add_pdm_subdev() - register PD Mapper subdevice
++ * @rproc: rproc handle
++ * @pdm: PDM subdevice handle
++ *
++ * Register @pdm so that Protection Device mapper service is started when the
++ * DSP is started too.
++ */
++void qcom_add_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm)
++{
++ pdm->dev = &rproc->dev;
++ pdm->index = rproc->index;
++
++ pdm->subdev.prepare = pdm_notify_prepare;
++ pdm->subdev.unprepare = pdm_notify_unprepare;
++
++ rproc_add_subdev(rproc, &pdm->subdev);
++}
++EXPORT_SYMBOL_GPL(qcom_add_pdm_subdev);
++
++/**
++ * qcom_remove_pdm_subdev() - remove PD Mapper subdevice
++ * @rproc: rproc handle
++ * @pdm: PDM subdevice handle
++ *
++ * Remove the PD Mapper subdevice.
++ */
++void qcom_remove_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm)
++{
++ rproc_remove_subdev(rproc, &pdm->subdev);
++}
++EXPORT_SYMBOL_GPL(qcom_remove_pdm_subdev);
++
+ MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver");
+ MODULE_LICENSE("GPL v2");
+diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h
+index 9ef4449052a9..b07fbaa091a0 100644
+--- a/drivers/remoteproc/qcom_common.h
++++ b/drivers/remoteproc/qcom_common.h
+@@ -34,6 +34,13 @@ struct qcom_rproc_ssr {
+ struct qcom_ssr_subsystem *info;
+ };
+
++struct qcom_rproc_pdm {
++ struct rproc_subdev subdev;
++ struct device *dev;
++ int index;
++ struct auxiliary_device *adev;
++};
++
+ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
+ void (*rproc_dumpfn_t)(struct rproc *rproc,
+ struct rproc_dump_segment *segment, void *dest, size_t offset,
+@@ -52,6 +59,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
+ const char *ssr_name);
+ void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr);
+
++void qcom_add_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm);
++void qcom_remove_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm);
++
+ #if IS_ENABLED(CONFIG_QCOM_SYSMON)
+ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
+ const char *name,
+diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
+index 1d24c9b656a8..572dcb0f055b 100644
+--- a/drivers/remoteproc/qcom_q6v5_adsp.c
++++ b/drivers/remoteproc/qcom_q6v5_adsp.c
+@@ -112,6 +112,7 @@ struct qcom_adsp {
+ struct dev_pm_domain_list *pd_list;
+
+ struct qcom_rproc_glink glink_subdev;
++ struct qcom_rproc_pdm pdm_subdev;
+ struct qcom_rproc_ssr ssr_subdev;
+ struct qcom_sysmon *sysmon;
+
+@@ -726,6 +727,7 @@ static int adsp_probe(struct platform_device *pdev)
+ goto disable_pm;
+
+ qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
++ qcom_add_pdm_subdev(rproc, &adsp->pdm_subdev);
+ qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
+ adsp->sysmon = qcom_add_sysmon_subdev(rproc,
+ desc->sysmon_name,
+@@ -755,6 +757,7 @@ static void adsp_remove(struct platform_device *pdev)
+
+ qcom_q6v5_deinit(&adsp->q6v5);
+ qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
++ qcom_remove_pdm_subdev(adsp->rproc, &adsp->pdm_subdev);
+ qcom_remove_sysmon_subdev(adsp->sysmon);
+ qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
+ qcom_rproc_pds_detach(adsp);
+diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
+index 1779fc890e10..2a42215ce8e0 100644
+--- a/drivers/remoteproc/qcom_q6v5_mss.c
++++ b/drivers/remoteproc/qcom_q6v5_mss.c
+@@ -228,6 +228,7 @@ struct q6v5 {
+
+ struct qcom_rproc_glink glink_subdev;
+ struct qcom_rproc_subdev smd_subdev;
++ struct qcom_rproc_pdm pdm_subdev;
+ struct qcom_rproc_ssr ssr_subdev;
+ struct qcom_sysmon *sysmon;
+ struct platform_device *bam_dmux;
+@@ -2102,6 +2103,7 @@ static int q6v5_probe(struct platform_device *pdev)
+ qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS);
+ qcom_add_glink_subdev(rproc, &qproc->glink_subdev, "mpss");
+ qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
++ qcom_add_pdm_subdev(rproc, &qproc->pdm_subdev);
+ qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
+ qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
+ if (IS_ERR(qproc->sysmon)) {
+@@ -2143,6 +2145,7 @@ static void q6v5_remove(struct platform_device *pdev)
+ qcom_q6v5_deinit(&qproc->q6v5);
+ qcom_remove_sysmon_subdev(qproc->sysmon);
+ qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev);
++ qcom_remove_pdm_subdev(rproc, &qproc->pdm_subdev);
+ qcom_remove_smd_subdev(rproc, &qproc->smd_subdev);
+ qcom_remove_glink_subdev(rproc, &qproc->glink_subdev);
+
+diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
+index 8458bcfe9e19..88e7b84f223c 100644
+--- a/drivers/remoteproc/qcom_q6v5_pas.c
++++ b/drivers/remoteproc/qcom_q6v5_pas.c
+@@ -111,6 +111,7 @@ struct qcom_adsp {
+
+ struct qcom_rproc_glink glink_subdev;
+ struct qcom_rproc_subdev smd_subdev;
++ struct qcom_rproc_pdm pdm_subdev;
+ struct qcom_rproc_ssr ssr_subdev;
+ struct qcom_sysmon *sysmon;
+
+@@ -777,6 +778,7 @@ static int adsp_probe(struct platform_device *pdev)
+
+ qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
+ qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
++ qcom_add_pdm_subdev(rproc, &adsp->pdm_subdev);
+ adsp->sysmon = qcom_add_sysmon_subdev(rproc,
+ desc->sysmon_name,
+ desc->ssctl_id);
+@@ -811,6 +813,7 @@ static void adsp_remove(struct platform_device *pdev)
+ qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
+ qcom_remove_sysmon_subdev(adsp->sysmon);
+ qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
++ qcom_remove_pdm_subdev(adsp->rproc, &adsp->pdm_subdev);
+ qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
+ adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+ device_init_wakeup(adsp->dev, false);
+diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
+index 94f68c919ee6..e913dabae992 100644
+--- a/drivers/remoteproc/qcom_q6v5_wcss.c
++++ b/drivers/remoteproc/qcom_q6v5_wcss.c
+@@ -148,6 +148,7 @@ struct q6v5_wcss {
+ bool requires_force_stop;
+
+ struct qcom_rproc_glink glink_subdev;
++ struct qcom_rproc_pdm pdm_subdev;
+ struct qcom_rproc_ssr ssr_subdev;
+ };
+
+@@ -1052,6 +1053,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev)
+ return ret;
+
+ qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
++ qcom_add_pdm_subdev(rproc, &wcss->pdm_subdev);
+ qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
+
+ if (desc->ssctl_id)
+@@ -1074,6 +1076,7 @@ static void q6v5_wcss_remove(struct platform_device *pdev)
+ struct q6v5_wcss *wcss = rproc->priv;
+
+ qcom_q6v5_deinit(&wcss->q6v5);
++ qcom_remove_pdm_subdev(rproc, &wcss->pdm_subdev);
+ rproc_del(rproc);
+ }
+
diff --git a/srcpkgs/linux6.9/template b/srcpkgs/linux6.9/template
index 48d279faa64..a107ed8f6b5 100644
--- a/srcpkgs/linux6.9/template
+++ b/srcpkgs/linux6.9/template
@@ -1,7 +1,7 @@
# Template file for 'linux6.9'
pkgname=linux6.9
version=6.9.8
-revision=1
+revision=2
short_desc="Linux kernel and modules (${version%.*} series)"
maintainer="Duncaen <duncaen@voidlinux.org>"
license="GPL-2.0-only"