@@ -209,4 +209,12 @@ config QCOM_APR
application processor and QDSP6. APR is
used by audio driver to configure QDSP6
ASM, ADM and AFE modules.
+
+config QCOM_MEMSHARE_QMI_SERVICE
+ select QCOM_QMI_HELPERS
+ tristate "Qualcomm QMI Shared Memory Service (MEMSHARE)"
+ help
+ This service provides additional memory regions on request from
+ remote processors. On some platforms it is used for GPS by
+ the location service in the modem subsystem.
endmenu
@@ -26,3 +26,5 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
+obj-$(CONFIG_QCOM_MEMSHARE_QMI_SERVICE) += qcom_memshare.o
+qcom_memshare-y := memshare.o memshare_qmi_msg.o
new file mode 100644
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/net.h>
+#include <linux/soc/qcom/qmi.h>
+
+#include "memshare_qmi_msg.h"
+
+#define MEMSHARE_MAX_CLIENTS 10
+
+struct memshare_client {
+ u32 id;
+ u32 proc_id;
+ u32 qrtr_node;
+ u32 size;
+ phys_addr_t phy_addr;
+};
+
+struct memshare {
+ struct device *dev;
+ struct qmi_handle qmi;
+ unsigned int client_cnt;
+ struct memshare_client *legacy_client;
+ struct memshare_client *clients[MEMSHARE_MAX_CLIENTS];
+};
+
+static struct memshare_client *memshare_get_client(struct memshare *share, u32 id, u32 proc_id)
+{
+ int i;
+
+ for (i = 0; i < share->client_cnt; i++)
+ if (share->clients[i]->id == id && share->clients[i]->proc_id == proc_id)
+ return share->clients[i];
+
+ return NULL;
+}
+
+static void memshare_alloc_req_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct memshare *share = container_of(qmi, struct memshare, qmi);
+ const struct mem_alloc_req_msg_v01 *req = data;
+ struct mem_alloc_resp_msg_v01 resp = { .resp = QMI_RESULT_FAILURE_V01 };
+ struct memshare_client *client = share->legacy_client;
+ int ret;
+
+ dev_dbg(share->dev,
+ "alloc_req: num_bytes=%d, block_alignment_valid=%d, block_alignment=%d, node=%d\n",
+ req->num_bytes,
+ req->block_alignment_valid,
+ req->block_alignment,
+ sq->sq_node
+ );
+
+ if (!client) {
+ dev_err(share->dev, "Unknown request from legacy client (size=%d, node=%d)\n",
+ req->num_bytes, sq->sq_node);
+ goto send_response;
+ }
+
+ if (sq->sq_node != client->qrtr_node) {
+ dev_err(share->dev, "Request from node %d but %d expected\n",
+ sq->sq_node, client->qrtr_node);
+ goto send_response;
+ }
+
+ if (client->size && client->size != req->num_bytes) {
+ dev_err(share->dev, "Got a request with wrong size (size=%d)\n",
+ req->num_bytes);
+ goto send_response;
+ }
+
+ if (req->block_alignment_valid)
+ if (client->phy_addr % MEM_BLOCK_ALIGN_TO_BYTES(req->block_alignment) != 0)
+ dev_warn(share->dev, "Memory region is not aligned by %d bytes\n",
+ MEM_BLOCK_ALIGN_TO_BYTES(req->block_alignment));
+
+ if (!client->phy_addr) {
+ dev_info(share->dev,
+ "Client sent a request but no memory is configured (size=%d, node=%d)\n",
+ req->num_bytes, sq->sq_node);
+ goto send_response;
+ }
+
+ resp.resp = QMI_RESULT_SUCCESS_V01;
+ resp.handle_valid = true;
+ resp.handle = client->phy_addr;
+ resp.num_bytes_valid = true;
+ resp.num_bytes = client->size;
+
+send_response:
+ ret = qmi_send_response(qmi, sq, txn, MEM_ALLOC_MSG_V01, MEM_MAX_MSG_LEN_V01,
+ mem_alloc_resp_msg_data_v01_ei, &resp);
+ if (ret < 0)
+ dev_err(share->dev, "Failed to send response: %d\n", ret);
+}
+
+static void memshare_free_req_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct memshare *share = container_of(qmi, struct memshare, qmi);
+ const struct mem_free_req_msg_v01 *req = data;
+ struct mem_free_resp_msg_v01 resp = { .resp = QMI_RESULT_FAILURE_V01 };
+ struct memshare_client *client = share->legacy_client;
+ int ret;
+
+ dev_dbg(share->dev, "free_req: node=%d\n", sq->sq_node);
+
+ if (!client) {
+ dev_err(share->dev, "Unknown request from legacy client\n");
+ goto send_response;
+ }
+
+ if (sq->sq_node != client->qrtr_node) {
+ dev_err(share->dev, "Request from node %d but %d expected\n",
+ sq->sq_node, client->qrtr_node);
+ goto send_response;
+ }
+
+ if (client->phy_addr != req->handle) {
+ dev_err(share->dev, "Got a request with wrong address\n");
+ goto send_response;
+ }
+
+ resp.resp = QMI_RESULT_SUCCESS_V01;
+
+send_response:
+ ret = qmi_send_response(qmi, sq, txn, MEM_FREE_MSG_V01, MEM_MAX_MSG_LEN_V01,
+ mem_free_resp_msg_data_v01_ei, &resp);
+ if (ret < 0)
+ dev_err(share->dev, "Failed to send response: %d\n", ret);
+}
+
+static void memshare_alloc_generic_req_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct memshare *share = container_of(qmi, struct memshare, qmi);
+ const struct mem_alloc_generic_req_msg_v01 *req = data;
+ struct mem_alloc_generic_resp_msg_v01 *resp;
+ struct memshare_client *client;
+ int ret;
+
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+ if (!resp)
+ return;
+
+ resp->resp.result = QMI_RESULT_FAILURE_V01;
+ resp->resp.error = QMI_ERR_INTERNAL_V01;
+
+ dev_dbg(share->dev,
+ "alloc_generic_req: num_bytes=%d, client_id=%d, proc_id=%d, sequence_id=%d, "
+ "alloc_contiguous_valid=%d, alloc_contiguous=%d, block_alignment_valid=%d, "
+ "block_alignment=%d, node=%d\n",
+ req->num_bytes,
+ req->client_id,
+ req->proc_id,
+ req->sequence_id,
+ req->alloc_contiguous_valid,
+ req->alloc_contiguous,
+ req->block_alignment_valid,
+ req->block_alignment,
+ sq->sq_node
+ );
+
+ client = memshare_get_client(share, req->client_id, req->proc_id);
+ if (!client) {
+ dev_err(share->dev,
+ "Got a request from unknown client (id=%d, proc=%d, size=%d, node=%d)\n",
+ req->client_id, req->proc_id, req->num_bytes, sq->sq_node);
+ goto send_response;
+ }
+
+ if (sq->sq_node != client->qrtr_node) {
+ dev_err(share->dev, "Request from node %d but %d expected\n",
+ sq->sq_node, client->qrtr_node);
+ goto send_response;
+ }
+
+ if (!client->phy_addr) {
+ dev_info(share->dev,
+ "Client sent a request but no memory is configured "
+ "(id=%d, proc=%d, size=%d, node=%d)\n",
+ req->client_id, req->proc_id, req->num_bytes, sq->sq_node);
+ goto send_response;
+ }
+
+ if (client->size != req->num_bytes) {
+ dev_err(share->dev,
+ "Got a request with wrong size (id=%d, proc=%d, size=%d)\n",
+ req->client_id, req->proc_id, req->num_bytes);
+ goto send_response;
+ }
+
+ if (req->block_alignment_valid)
+ if (client->phy_addr % MEM_BLOCK_ALIGN_TO_BYTES(req->block_alignment) != 0)
+ dev_warn(share->dev, "Memory region is not aligned by %d bytes\n",
+ MEM_BLOCK_ALIGN_TO_BYTES(req->block_alignment));
+
+ resp->resp.result = QMI_RESULT_SUCCESS_V01;
+ resp->resp.error = QMI_ERR_NONE_V01;
+ resp->sequence_id_valid = true;
+ resp->sequence_id = req->sequence_id;
+ resp->dhms_mem_alloc_addr_info_valid = true;
+ resp->dhms_mem_alloc_addr_info_len = 1;
+ resp->dhms_mem_alloc_addr_info[0].phy_addr = client->phy_addr;
+ resp->dhms_mem_alloc_addr_info[0].num_bytes = client->size;
+
+send_response:
+ ret = qmi_send_response(qmi, sq, txn, MEM_ALLOC_GENERIC_MSG_V01, MEM_MAX_MSG_LEN_V01,
+ mem_alloc_generic_resp_msg_data_v01_ei, resp);
+ if (ret < 0)
+ dev_err(share->dev, "Failed to send response: %d\n", ret);
+
+ kfree(resp);
+}
+
+static void memshare_free_generic_req_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct memshare *share = container_of(qmi, struct memshare, qmi);
+ const struct mem_free_generic_req_msg_v01 *req = data;
+ struct mem_free_generic_resp_msg_v01 resp = {
+ .resp.result = QMI_RESULT_FAILURE_V01,
+ .resp.error = QMI_ERR_INTERNAL_V01,
+ };
+ struct memshare_client *client;
+ int ret;
+
+ dev_dbg(share->dev,
+ "free_generic_req: dhms_mem_alloc_addr_info_len=%d, client_id_valid=%d, "
+ "client_id=%d, proc_id_valid=%d, proc_id=%d, node=%d\n",
+ req->dhms_mem_alloc_addr_info_len,
+ req->client_id_valid,
+ req->client_id,
+ req->proc_id_valid,
+ req->proc_id,
+ sq->sq_node
+ );
+
+ if (req->dhms_mem_alloc_addr_info_len != 1) {
+ dev_err(share->dev, "addr_info_len = %d is unexpected\n",
+ req->dhms_mem_alloc_addr_info_len);
+ goto send_response;
+ }
+
+ if (!req->client_id_valid || !req->proc_id_valid) {
+ dev_err(share->dev, "Got a request from unknown client\n");
+ goto send_response;
+ }
+
+ client = memshare_get_client(share, req->client_id, req->proc_id);
+ if (!client) {
+ dev_err(share->dev, "Got a request from unknown client (id=%d, proc=%d)\n",
+ req->client_id, req->proc_id);
+ goto send_response;
+ }
+
+ if (req->dhms_mem_alloc_addr_info[0].phy_addr != client->phy_addr) {
+ dev_err(share->dev, "Client sent invalid handle\n");
+ goto send_response;
+ }
+
+ if (sq->sq_node != client->qrtr_node) {
+ dev_err(share->dev, "Request from node %d but %d expected\n",
+ sq->sq_node, client->qrtr_node);
+ goto send_response;
+ }
+
+ resp.resp.result = QMI_RESULT_SUCCESS_V01;
+ resp.resp.error = QMI_ERR_NONE_V01;
+
+send_response:
+ ret = qmi_send_response(qmi, sq, txn, MEM_FREE_GENERIC_MSG_V01, MEM_MAX_MSG_LEN_V01,
+ mem_free_generic_resp_msg_data_v01_ei, &resp);
+ if (ret < 0)
+ dev_err(share->dev, "Failed to send response: %d\n", ret);
+}
+
+static void memshare_query_size_req_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct memshare *share = container_of(qmi, struct memshare, qmi);
+ const struct mem_query_size_req_msg_v01 *req = data;
+ struct mem_query_size_rsp_msg_v01 resp = {
+ .resp.result = QMI_RESULT_FAILURE_V01,
+ .resp.error = QMI_ERR_INTERNAL_V01,
+ };
+ struct memshare_client *client;
+ int ret;
+
+ dev_dbg(share->dev,
+ "query_size_req: client_id=%d, proc_id_valid=%d, proc_id=%d, node=%d\n",
+ req->client_id,
+ req->proc_id_valid,
+ req->proc_id,
+ sq->sq_node
+ );
+
+ client = memshare_get_client(share, req->client_id, req->proc_id);
+ if (!client) {
+ dev_err(share->dev, "Got a request from unknown client (id=%d, proc=%d)\n",
+ req->client_id, req->proc_id);
+ goto send_response;
+ }
+
+ if (sq->sq_node != client->qrtr_node) {
+ dev_err(share->dev, "Request from node %d but %d expected\n",
+ sq->sq_node, client->qrtr_node);
+ goto send_response;
+ }
+
+ if (!client->phy_addr)
+ goto send_response;
+
+ resp.resp.result = QMI_RESULT_SUCCESS_V01;
+ resp.resp.error = QMI_ERR_NONE_V01;
+ resp.size_valid = true;
+ resp.size = client->size;
+
+send_response:
+ ret = qmi_send_response(qmi, sq, txn, MEM_QUERY_SIZE_MSG_V01, MEM_MAX_MSG_LEN_V01,
+ mem_query_size_resp_msg_data_v01_ei, &resp);
+ if (ret < 0)
+ dev_err(share->dev, "Failed to send response: %d\n", ret);
+}
+
+static struct qmi_msg_handler memshare_handlers[] = {
+ {
+ .type = QMI_REQUEST,
+ .msg_id = MEM_ALLOC_MSG_V01,
+ .ei = mem_alloc_req_msg_data_v01_ei,
+ .decoded_size = sizeof(struct mem_alloc_req_msg_v01),
+ .fn = memshare_alloc_req_handler,
+ },
+ {
+ .type = QMI_REQUEST,
+ .msg_id = MEM_FREE_MSG_V01,
+ .ei = mem_free_req_msg_data_v01_ei,
+ .decoded_size = sizeof(struct mem_free_req_msg_v01),
+ .fn = memshare_free_req_handler,
+ },
+ {
+ .type = QMI_REQUEST,
+ .msg_id = MEM_ALLOC_GENERIC_MSG_V01,
+ .ei = mem_alloc_generic_req_msg_data_v01_ei,
+ .decoded_size = sizeof(struct mem_alloc_generic_req_msg_v01),
+ .fn = memshare_alloc_generic_req_handler,
+ },
+ {
+ .type = QMI_REQUEST,
+ .msg_id = MEM_FREE_GENERIC_MSG_V01,
+ .ei = mem_free_generic_req_msg_data_v01_ei,
+ .decoded_size = sizeof(struct mem_free_generic_req_msg_v01),
+ .fn = memshare_free_generic_req_handler,
+ },
+ {
+ .type = QMI_REQUEST,
+ .msg_id = MEM_QUERY_SIZE_MSG_V01,
+ .ei = mem_query_size_req_msg_data_v01_ei,
+ .decoded_size = sizeof(struct mem_query_size_req_msg_v01),
+ .fn = memshare_query_size_req_handler,
+ },
+ { /* sentinel */ }
+};
+
+static int memshare_probe_dt(struct memshare *share)
+{
+ struct device_node *np = share->dev->of_node;
+ struct device_node *proc_node = NULL, *client_node = NULL, *mem_node = NULL;
+ int ret = 0;
+ u32 proc_id, qrtr_node;
+ struct memshare_client *client;
+ phandle legacy_client = 0;
+ struct resource reserved_memory;
+
+ ret = of_property_read_u32(np, "qcom,legacy-client", &legacy_client);
+ if (ret && ret != -EINVAL)
+ return ret;
+
+ for_each_available_child_of_node(np, proc_node) {
+ ret = of_property_read_u32(proc_node, "reg", &proc_id);
+ if (ret)
+ goto error;
+
+ ret = of_property_read_u32(proc_node, "qcom,qrtr-node", &qrtr_node);
+ if (ret)
+ goto error;
+
+ for_each_available_child_of_node(proc_node, client_node) {
+ if (share->client_cnt >= MEMSHARE_MAX_CLIENTS) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ client = devm_kzalloc(share->dev, sizeof(*client), GFP_KERNEL);
+ if (!client) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = of_property_read_u32(client_node, "reg", &client->id);
+ if (ret)
+ goto error;
+
+ client->proc_id = proc_id;
+ client->qrtr_node = qrtr_node;
+
+ mem_node = of_parse_phandle(client_node, "memory-region", 0);
+ if (mem_node) {
+ ret = of_address_to_resource(mem_node, 0, &reserved_memory);
+ of_node_put(mem_node);
+ if (ret)
+ goto error;
+
+ client->phy_addr = reserved_memory.start;
+ client->size = resource_size(&reserved_memory);
+ }
+
+ if (client_node->phandle == legacy_client)
+ share->legacy_client = client;
+
+ share->clients[share->client_cnt] = client;
+ share->client_cnt++;
+ }
+ }
+
+ return 0;
+
+error:
+ of_node_put(client_node);
+ of_node_put(proc_node);
+ return ret;
+}
+
+static int memshare_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct memshare *share;
+ int ret;
+
+ share = devm_kzalloc(&pdev->dev, sizeof(*share), GFP_KERNEL);
+ if (!share)
+ return -ENOMEM;
+
+ share->dev = dev;
+ dev_set_drvdata(&pdev->dev, share);
+
+ ret = qmi_handle_init(&share->qmi, MEM_MAX_MSG_LEN_V01, NULL, memshare_handlers);
+ if (ret < 0)
+ return ret;
+
+ ret = memshare_probe_dt(share);
+ if (ret < 0)
+ goto error;
+
+ ret = qmi_add_server(&share->qmi, MEM_SERVICE_SVC_ID,
+ MEM_SERVICE_VER, MEM_SERVICE_INS_ID);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ qmi_handle_release(&share->qmi);
+ return ret;
+}
+
+static int memshare_remove(struct platform_device *pdev)
+{
+ struct memshare *share = dev_get_drvdata(&pdev->dev);
+
+ qmi_handle_release(&share->qmi);
+
+ return 0;
+}
+
+static const struct of_device_id memshare_of_match[] = {
+ { .compatible = "qcom,memshare", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, memshare_of_match);
+
+static struct platform_driver memshare_driver = {
+ .probe = memshare_probe,
+ .remove = memshare_remove,
+ .driver = {
+ .name = "qcom-memshare",
+ .of_match_table = of_match_ptr(memshare_of_match),
+ },
+};
+module_platform_driver(memshare_driver);
+
+MODULE_DESCRIPTION("Qualcomm Memory Share Service");
+MODULE_AUTHOR("Nikita Travkin <nikitos.tr@gmail.com>");
+MODULE_LICENSE("GPL v2");
new file mode 100644
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights reserved.
+
+#include <linux/stddef.h>
+#include <linux/soc/qcom/qmi.h>
+
+#include "memshare_qmi_msg.h"
+
+struct qmi_elem_info mem_alloc_req_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_req_msg_v01, num_bytes),
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_alloc_req_msg_v01, num_bytes),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_req_msg_v01, block_alignment_valid),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_req_msg_v01, block_alignment_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_req_msg_v01, block_alignment),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_req_msg_v01, block_alignment),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_alloc_resp_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_2_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_resp_msg_v01, resp),
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_alloc_resp_msg_v01, resp),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_resp_msg_v01, handle_valid),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_resp_msg_v01, handle_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_resp_msg_v01, handle),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_resp_msg_v01, handle),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_resp_msg_v01, num_bytes_valid),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_alloc_resp_msg_v01, num_bytes_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_resp_msg_v01, num_bytes),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_alloc_resp_msg_v01, num_bytes),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_free_req_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_req_msg_v01, handle),
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_free_req_msg_v01, handle),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_free_resp_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_2_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_resp_msg_v01, resp),
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_free_resp_msg_v01, resp),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info dhms_mem_alloc_addr_info_type_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct dhms_mem_alloc_addr_info_type_v01, phy_addr),
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ .offset = offsetof(struct dhms_mem_alloc_addr_info_type_v01, phy_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct dhms_mem_alloc_addr_info_type_v01, num_bytes),
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ .offset = offsetof(struct dhms_mem_alloc_addr_info_type_v01, num_bytes),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_alloc_generic_req_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01, num_bytes),
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01, num_bytes),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01, client_id),
+ .tlv_type = 0x02,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01, client_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01, proc_id),
+ .tlv_type = 0x03,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01, proc_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01, sequence_id),
+ .tlv_type = 0x04,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01, sequence_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01,
+ alloc_contiguous_valid),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01,
+ alloc_contiguous_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01,
+ alloc_contiguous),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01, alloc_contiguous),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01,
+ block_alignment_valid),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01,
+ block_alignment_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_req_msg_v01,
+ block_alignment),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_alloc_generic_req_msg_v01, block_alignment),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_alloc_generic_resp_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_resp_msg_v01, resp),
+ .tlv_type = 0x02,
+ .offset = offsetof(struct mem_alloc_generic_resp_msg_v01, resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_resp_msg_v01,
+ sequence_id_valid),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_generic_resp_msg_v01, sequence_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_resp_msg_v01, sequence_id),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_alloc_generic_resp_msg_v01, sequence_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_resp_msg_v01,
+ dhms_mem_alloc_addr_info_valid),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_alloc_generic_resp_msg_v01,
+ dhms_mem_alloc_addr_info_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_alloc_generic_resp_msg_v01,
+ dhms_mem_alloc_addr_info_len),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_alloc_generic_resp_msg_v01,
+ dhms_mem_alloc_addr_info_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = MAX_ARR_CNT_V01,
+ .elem_size = sizeof_field(struct mem_alloc_generic_resp_msg_v01,
+ dhms_mem_alloc_addr_info),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_alloc_generic_resp_msg_v01,
+ dhms_mem_alloc_addr_info),
+ .ei_array = dhms_mem_alloc_addr_info_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_free_generic_req_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_generic_req_msg_v01,
+ dhms_mem_alloc_addr_info_len),
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_free_generic_req_msg_v01,
+ dhms_mem_alloc_addr_info_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = MAX_ARR_CNT_V01,
+ .elem_size = sizeof_field(struct mem_free_generic_req_msg_v01,
+ dhms_mem_alloc_addr_info),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_free_generic_req_msg_v01,
+ dhms_mem_alloc_addr_info),
+ .ei_array = dhms_mem_alloc_addr_info_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_generic_req_msg_v01, client_id_valid),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_free_generic_req_msg_v01, client_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_generic_req_msg_v01, client_id),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_free_generic_req_msg_v01, client_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_generic_req_msg_v01, proc_id_valid),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_free_generic_req_msg_v01, proc_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_generic_req_msg_v01, proc_id),
+ .tlv_type = 0x11,
+ .offset = offsetof(struct mem_free_generic_req_msg_v01, proc_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_free_generic_resp_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_free_generic_resp_msg_v01, resp),
+ .tlv_type = 0x02,
+ .offset = offsetof(struct mem_free_generic_resp_msg_v01, resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_query_size_req_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_query_size_req_msg_v01, client_id),
+ .tlv_type = 0x01,
+ .offset = offsetof(struct mem_query_size_req_msg_v01, client_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_query_size_req_msg_v01, proc_id_valid),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_query_size_req_msg_v01, proc_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_query_size_req_msg_v01, proc_id),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_query_size_req_msg_v01, proc_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
+struct qmi_elem_info mem_query_size_resp_msg_data_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_query_size_rsp_msg_v01, resp),
+ .tlv_type = 0x02,
+ .offset = offsetof(struct mem_query_size_rsp_msg_v01, resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_query_size_rsp_msg_v01, size_valid),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_query_size_rsp_msg_v01, size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct mem_query_size_rsp_msg_v01, size),
+ .tlv_type = 0x10,
+ .offset = offsetof(struct mem_query_size_rsp_msg_v01, size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
new file mode 100644
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights reserved. */
+
+#ifndef HEAP_MEM_EXT_SERVICE_01_H
+#define HEAP_MEM_EXT_SERVICE_01_H
+
+#include <linux/types.h>
+#include <linux/soc/qcom/qmi.h>
+
+#define MEM_SERVICE_SVC_ID 0x00000034
+#define MEM_SERVICE_INS_ID 1
+#define MEM_SERVICE_VER 1
+
+/* Service Message Definition */
+#define MEM_ALLOC_MSG_V01 0x0020
+#define MEM_FREE_MSG_V01 0x0021
+#define MEM_ALLOC_GENERIC_MSG_V01 0x0022
+#define MEM_FREE_GENERIC_MSG_V01 0x0023
+#define MEM_QUERY_SIZE_MSG_V01 0x0024
+
+#define MEM_MAX_MSG_LEN_V01 255
+#define MAX_ARR_CNT_V01 64
+
+#define MEM_BLOCK_ALIGN_TO_BYTES(x) (2 << (x)) /* 0..11 */
+
+/**
+ * Unless stated otherwise, any property X that is paired with X_valid
+ * property is an optional property. Other properties are mandatory.
+ */
+
+/**
+ * struct dhms_mem_alloc_addr_info_type_v01 - Element of memory block array.
+ * @phy_addr: Physical address of memory block.
+ * @num_bytes: Size of memory block.
+ */
+struct dhms_mem_alloc_addr_info_type_v01 {
+ u64 phy_addr;
+ u32 num_bytes;
+};
+
+/**
+ * struct mem_alloc_req_msg_v01 - Legacy memory allocation request.
+ * @num_bytes: Requested size.
+ * @block_alignment_valid: Must be set to true if block_alignment is being passed.
+ * @block_alignment: The block alignment for the memory block to be allocated.
+ *
+ * Request Message.
+ * This command is used for getting the multiple physically contiguous memory
+ * blocks from the server memory subsystem.
+ */
+struct mem_alloc_req_msg_v01 {
+ u32 num_bytes;
+ u8 block_alignment_valid;
+ u32 block_alignment;
+};
+
+/**
+ * struct mem_alloc_resp_msg_v01 - Response for legacy allocation memory request.
+ * @resp: Result Code. The result of the requested memory operation.
+ * @handle_valid: Must be set to true if handle is being passed.
+ * @handle: Memory Block Handle. The physical address of the memory allocated on the HLOS.
+ * @num_bytes_valid: Must be set to true if num_bytes is being passed.
+ * @num_bytes: Memory block size. The number of bytes actually allocated for the request.
+ * This value can be smaller than the size requested in QMI_DHMS_MEM_ALLOC_REQ_MSG.
+ *
+ * Response Message.
+ * This command is used for getting the multiple physically contiguous memory
+ * blocks from the server memory subsystem
+ */
+struct mem_alloc_resp_msg_v01 {
+ u16 resp;
+ u8 handle_valid;
+ u64 handle;
+ u8 num_bytes_valid;
+ u32 num_bytes;
+};
+
+/**
+ * struct mem_free_req_msg_v01 - Legacy memory free request.
+ * @handle: Physical address of memory to be freed.
+ *
+ * Request Message.
+ * This command is used for releasing the multiple physically contiguous memory
+ * blocks to the server memory subsystem.
+ */
+struct mem_free_req_msg_v01 {
+ u64 handle;
+};
+
+/**
+ * struct mem_free_resp_msg_v01 - Response for legacy memory free request.
+ * @resp: Result of the requested memory operation.
+ *
+ * Response Message.
+ * This command is used for releasing the multiple physically contiguous memory
+ * blocks to the server memory subsystem.
+ */
+struct mem_free_resp_msg_v01 {
+ u16 resp;
+};
+
+/**
+ * struct mem_alloc_generic_req_msg_v01 - Memory allocation request.
+ * @num_bytes: Requested size.
+ * @client_id: Client ID.
+ * @proc_id: Peripheral ID.
+ * @sequence_id: Sequence ID.
+ * @alloc_contiguous_valid: Must be set to true if alloc_contiguous is being passed.
+ * @alloc_contiguous: alloc_contiguous is used to identify that clients are requesting
+ * for contiguous or non contiguous memory, default is contiguous.
+ * 0 = non contiguous else contiguous.
+ * @block_alignment_valid: Must be set to true if block_alignment is being passed.
+ * @block_alignment: The block alignment for the memory block to be allocated.
+ *
+ * Request Message.
+ * This command is used for getting the multiple physically contiguous memory
+ * blocks from the server memory subsystem
+ */
+struct mem_alloc_generic_req_msg_v01 {
+ u32 num_bytes;
+ u32 client_id;
+ u32 proc_id;
+ u32 sequence_id;
+ u8 alloc_contiguous_valid;
+ u8 alloc_contiguous;
+ u8 block_alignment_valid;
+ u32 block_alignment;
+};
+
+/**
+ * struct mem_alloc_generic_resp_msg_v01 - Response for memory allocation request.
+ * @resp: Result Code. The result of the requested memory operation.
+ * @sequence_id_valid: Must be set to true if sequence_id is being passed.
+ * @sequence_id: Sequence ID. This property is marked as mandatory.
+ * @dhms_mem_alloc_addr_info_valid: Must be set to true if handle is being passed.
+ * @dhms_mem_alloc_addr_info_len: Handle Size.
+ * @dhms_mem_alloc_addr_info: Memory Block Handle. The physical address of the
+ * memory allocated on the HLOS.
+ *
+ * Response Message.
+ * This command is used for getting the multiple physically contiguous memory
+ * blocks from the server memory subsystem
+ */
+struct mem_alloc_generic_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 sequence_id_valid;
+ u32 sequence_id;
+ u8 dhms_mem_alloc_addr_info_valid;
+ u8 dhms_mem_alloc_addr_info_len;
+ struct dhms_mem_alloc_addr_info_type_v01 dhms_mem_alloc_addr_info[MAX_ARR_CNT_V01];
+};
+
+/**
+ * struct mem_free_generic_req_msg_v01 - Memory free request.
+ * @dhms_mem_alloc_addr_info_len: Must be set to # of elments in array.
+ * @dhms_mem_alloc_addr_info: Physical address and size of the memory allocated
+ * on the HLOS to be freed.
+ * @client_id_valid: Must be set to true if client_id is being passed.
+ * @client_id: Client ID.
+ * @proc_id_valid: Must be set to true if proc_id is being passed.
+ * @proc_id: Peripheral ID.
+ *
+ * Request Message.
+ * This command is used for releasing the multiple physically contiguous memory
+ * blocks to the server memory subsystem
+ */
+struct mem_free_generic_req_msg_v01 {
+ u8 dhms_mem_alloc_addr_info_len;
+ struct dhms_mem_alloc_addr_info_type_v01 dhms_mem_alloc_addr_info[MAX_ARR_CNT_V01];
+ u8 client_id_valid;
+ u32 client_id;
+ u8 proc_id_valid;
+ u32 proc_id;
+};
+
+/**
+ * struct mem_free_generic_resp_msg_v01 - Response for memory free request.
+ * @resp: Result of the requested memory operation.
+ *
+ * Response Message.
+ * This command is used for releasing the multiple physically contiguous memory
+ * blocks to the server memory subsystem
+ */
+struct mem_free_generic_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+/**
+ * struct mem_query_size_req_msg_v01 - Size query request.
+ * @client_id: Client ID.
+ * @proc_id_valid: proc_id_valid must be set to true if proc_id is being passed.
+ * @proc_id: Proc ID.
+ *
+ * Request Message.
+ */
+struct mem_query_size_req_msg_v01 {
+ u32 client_id;
+ u8 proc_id_valid;
+ u32 proc_id;
+};
+
+/**
+ * struct mem_query_size_rsp_msg_v01 - Response for Size query request.
+ * @resp: Result Code.
+ * @size_valid: size_valid must be set to true if size is being passed.
+ * @size: Size.
+ *
+ * Response Message.
+ */
+struct mem_query_size_rsp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 size_valid;
+ u32 size;
+};
+
+/* Message structure definitions defined in "memshare_qmi_msg.c" */
+extern struct qmi_elem_info mem_alloc_req_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_alloc_resp_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_free_req_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_free_resp_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_alloc_generic_req_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_alloc_generic_resp_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_free_generic_req_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_free_generic_resp_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_query_size_req_msg_data_v01_ei[];
+extern struct qmi_elem_info mem_query_size_resp_msg_data_v01_ei[];
+
+#endif