aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2017-12-05 12:43:06 -0500
committerAndy Gross <andy.gross@linaro.org>2017-12-20 16:38:34 -0500
commit9b8a11e82615274d4133aab3cf5aa1c59191f0a2 (patch)
tree46d63ee16127074c9e2bdf30f4cac6544afdd60f
parent29ff62f7db108854cd98f5cdc92d15ccb37e81d1 (diff)
soc: qcom: Introduce QMI encoder/decoder
Add the helper library for encoding and decoding QMI encoded messages. The implementation is taken from lib/qmi_encdec.c of the Qualcomm kernel (msm-3.18). Modifications has been made to the public API, source buffers has been made const and the debug-logging part was omitted, for now. Acked-by: Chris Lew <clew@codeaurora.org> Tested-by: Chris Lew <clew@codeaurora.org> Tested-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Signed-off-by: Andy Gross <andy.gross@linaro.org>
-rw-r--r--drivers/soc/qcom/Kconfig9
-rw-r--r--drivers/soc/qcom/Makefile2
-rw-r--r--drivers/soc/qcom/qmi_encdec.c816
-rw-r--r--include/linux/soc/qcom/qmi.h106
4 files changed, 933 insertions, 0 deletions
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 40c711583f0d..e050eb83341d 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -35,6 +35,15 @@ config QCOM_PM
35 modes. It interface with various system drivers to put the cores in 35 modes. It interface with various system drivers to put the cores in
36 low power modes. 36 low power modes.
37 37
38config QCOM_QMI_HELPERS
39 tristate
40 depends on ARCH_QCOM
41 help
42 Helper library for handling QMI encoded messages. QMI encoded
43 messages are used in communication between the majority of QRTR
44 clients and this helpers provide the common functionality needed for
45 doing this from a kernel driver.
46
38config QCOM_RMTFS_MEM 47config QCOM_RMTFS_MEM
39 tristate "Qualcomm Remote Filesystem memory driver" 48 tristate "Qualcomm Remote Filesystem memory driver"
40 depends on ARCH_QCOM 49 depends on ARCH_QCOM
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 40c56f67e94a..37f85b45d0a1 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -3,6 +3,8 @@ obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o
3obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o 3obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
4obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o 4obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
5obj-$(CONFIG_QCOM_PM) += spm.o 5obj-$(CONFIG_QCOM_PM) += spm.o
6obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
7qmi_helpers-y += qmi_encdec.o
6obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o 8obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
7obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o 9obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
8obj-$(CONFIG_QCOM_SMEM) += smem.o 10obj-$(CONFIG_QCOM_SMEM) += smem.o
diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c
new file mode 100644
index 000000000000..3aaab71d1b2c
--- /dev/null
+++ b/drivers/soc/qcom/qmi_encdec.c
@@ -0,0 +1,816 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2017 Linaro Ltd.
5 */
6#include <linux/slab.h>
7#include <linux/uaccess.h>
8#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/errno.h>
11#include <linux/string.h>
12#include <linux/soc/qcom/qmi.h>
13
14#define QMI_ENCDEC_ENCODE_TLV(type, length, p_dst) do { \
15 *p_dst++ = type; \
16 *p_dst++ = ((u8)((length) & 0xFF)); \
17 *p_dst++ = ((u8)(((length) >> 8) & 0xFF)); \
18} while (0)
19
20#define QMI_ENCDEC_DECODE_TLV(p_type, p_length, p_src) do { \
21 *p_type = (u8)*p_src++; \
22 *p_length = (u8)*p_src++; \
23 *p_length |= ((u8)*p_src) << 8; \
24} while (0)
25
26#define QMI_ENCDEC_ENCODE_N_BYTES(p_dst, p_src, size) \
27do { \
28 memcpy(p_dst, p_src, size); \
29 p_dst = (u8 *)p_dst + size; \
30 p_src = (u8 *)p_src + size; \
31} while (0)
32
33#define QMI_ENCDEC_DECODE_N_BYTES(p_dst, p_src, size) \
34do { \
35 memcpy(p_dst, p_src, size); \
36 p_dst = (u8 *)p_dst + size; \
37 p_src = (u8 *)p_src + size; \
38} while (0)
39
40#define UPDATE_ENCODE_VARIABLES(temp_si, buf_dst, \
41 encoded_bytes, tlv_len, encode_tlv, rc) \
42do { \
43 buf_dst = (u8 *)buf_dst + rc; \
44 encoded_bytes += rc; \
45 tlv_len += rc; \
46 temp_si = temp_si + 1; \
47 encode_tlv = 1; \
48} while (0)
49
50#define UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc) \
51do { \
52 buf_src = (u8 *)buf_src + rc; \
53 decoded_bytes += rc; \
54} while (0)
55
56#define TLV_LEN_SIZE sizeof(u16)
57#define TLV_TYPE_SIZE sizeof(u8)
58#define OPTIONAL_TLV_TYPE_START 0x10
59
60static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
61 const void *in_c_struct, u32 out_buf_len,
62 int enc_level);
63
64static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
65 const void *in_buf, u32 in_buf_len, int dec_level);
66
67/**
68 * skip_to_next_elem() - Skip to next element in the structure to be encoded
69 * @ei_array: Struct info describing the element to be skipped.
70 * @level: Depth level of encoding/decoding to identify nested structures.
71 *
72 * This function is used while encoding optional elements. If the flag
73 * corresponding to an optional element is not set, then encoding the
74 * optional element can be skipped. This function can be used to perform
75 * that operation.
76 *
77 * Return: struct info of the next element that can be encoded.
78 */
79static struct qmi_elem_info *skip_to_next_elem(struct qmi_elem_info *ei_array,
80 int level)
81{
82 struct qmi_elem_info *temp_ei = ei_array;
83 u8 tlv_type;
84
85 if (level > 1) {
86 temp_ei = temp_ei + 1;
87 } else {
88 do {
89 tlv_type = temp_ei->tlv_type;
90 temp_ei = temp_ei + 1;
91 } while (tlv_type == temp_ei->tlv_type);
92 }
93
94 return temp_ei;
95}
96
97/**
98 * qmi_calc_min_msg_len() - Calculate the minimum length of a QMI message
99 * @ei_array: Struct info array describing the structure.
100 * @level: Level to identify the depth of the nested structures.
101 *
102 * Return: Expected minimum length of the QMI message or 0 on error.
103 */
104static int qmi_calc_min_msg_len(struct qmi_elem_info *ei_array,
105 int level)
106{
107 int min_msg_len = 0;
108 struct qmi_elem_info *temp_ei = ei_array;
109
110 if (!ei_array)
111 return min_msg_len;
112
113 while (temp_ei->data_type != QMI_EOTI) {
114 /* Optional elements do not count in minimum length */
115 if (temp_ei->data_type == QMI_OPT_FLAG) {
116 temp_ei = skip_to_next_elem(temp_ei, level);
117 continue;
118 }
119
120 if (temp_ei->data_type == QMI_DATA_LEN) {
121 min_msg_len += (temp_ei->elem_size == sizeof(u8) ?
122 sizeof(u8) : sizeof(u16));
123 temp_ei++;
124 continue;
125 } else if (temp_ei->data_type == QMI_STRUCT) {
126 min_msg_len += qmi_calc_min_msg_len(temp_ei->ei_array,
127 (level + 1));
128 temp_ei++;
129 } else if (temp_ei->data_type == QMI_STRING) {
130 if (level > 1)
131 min_msg_len += temp_ei->elem_len <= U8_MAX ?
132 sizeof(u8) : sizeof(u16);
133 min_msg_len += temp_ei->elem_len * temp_ei->elem_size;
134 temp_ei++;
135 } else {
136 min_msg_len += (temp_ei->elem_len * temp_ei->elem_size);
137 temp_ei++;
138 }
139
140 /*
141 * Type & Length info. not prepended for elements in the
142 * nested structure.
143 */
144 if (level == 1)
145 min_msg_len += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
146 }
147
148 return min_msg_len;
149}
150
151/**
152 * qmi_encode_basic_elem() - Encodes elements of basic/primary data type
153 * @buf_dst: Buffer to store the encoded information.
154 * @buf_src: Buffer containing the elements to be encoded.
155 * @elem_len: Number of elements, in the buf_src, to be encoded.
156 * @elem_size: Size of a single instance of the element to be encoded.
157 *
158 * This function encodes the "elem_len" number of data elements, each of
159 * size "elem_size" bytes from the source buffer "buf_src" and stores the
160 * encoded information in the destination buffer "buf_dst". The elements are
161 * of primary data type which include u8 - u64 or similar. This
162 * function returns the number of bytes of encoded information.
163 *
164 * Return: The number of bytes of encoded information.
165 */
166static int qmi_encode_basic_elem(void *buf_dst, const void *buf_src,
167 u32 elem_len, u32 elem_size)
168{
169 u32 i, rc = 0;
170
171 for (i = 0; i < elem_len; i++) {
172 QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, elem_size);
173 rc += elem_size;
174 }
175
176 return rc;
177}
178
179/**
180 * qmi_encode_struct_elem() - Encodes elements of struct data type
181 * @ei_array: Struct info array descibing the struct element.
182 * @buf_dst: Buffer to store the encoded information.
183 * @buf_src: Buffer containing the elements to be encoded.
184 * @elem_len: Number of elements, in the buf_src, to be encoded.
185 * @out_buf_len: Available space in the encode buffer.
186 * @enc_level: Depth of the nested structure from the main structure.
187 *
188 * This function encodes the "elem_len" number of struct elements, each of
189 * size "ei_array->elem_size" bytes from the source buffer "buf_src" and
190 * stores the encoded information in the destination buffer "buf_dst". The
191 * elements are of struct data type which includes any C structure. This
192 * function returns the number of bytes of encoded information.
193 *
194 * Return: The number of bytes of encoded information on success or negative
195 * errno on error.
196 */
197static int qmi_encode_struct_elem(struct qmi_elem_info *ei_array,
198 void *buf_dst, const void *buf_src,
199 u32 elem_len, u32 out_buf_len,
200 int enc_level)
201{
202 int i, rc, encoded_bytes = 0;
203 struct qmi_elem_info *temp_ei = ei_array;
204
205 for (i = 0; i < elem_len; i++) {
206 rc = qmi_encode(temp_ei->ei_array, buf_dst, buf_src,
207 out_buf_len - encoded_bytes, enc_level);
208 if (rc < 0) {
209 pr_err("%s: STRUCT Encode failure\n", __func__);
210 return rc;
211 }
212 buf_dst = buf_dst + rc;
213 buf_src = buf_src + temp_ei->elem_size;
214 encoded_bytes += rc;
215 }
216
217 return encoded_bytes;
218}
219
220/**
221 * qmi_encode_string_elem() - Encodes elements of string data type
222 * @ei_array: Struct info array descibing the string element.
223 * @buf_dst: Buffer to store the encoded information.
224 * @buf_src: Buffer containing the elements to be encoded.
225 * @out_buf_len: Available space in the encode buffer.
226 * @enc_level: Depth of the string element from the main structure.
227 *
228 * This function encodes a string element of maximum length "ei_array->elem_len"
229 * bytes from the source buffer "buf_src" and stores the encoded information in
230 * the destination buffer "buf_dst". This function returns the number of bytes
231 * of encoded information.
232 *
233 * Return: The number of bytes of encoded information on success or negative
234 * errno on error.
235 */
236static int qmi_encode_string_elem(struct qmi_elem_info *ei_array,
237 void *buf_dst, const void *buf_src,
238 u32 out_buf_len, int enc_level)
239{
240 int rc;
241 int encoded_bytes = 0;
242 struct qmi_elem_info *temp_ei = ei_array;
243 u32 string_len = 0;
244 u32 string_len_sz = 0;
245
246 string_len = strlen(buf_src);
247 string_len_sz = temp_ei->elem_len <= U8_MAX ?
248 sizeof(u8) : sizeof(u16);
249 if (string_len > temp_ei->elem_len) {
250 pr_err("%s: String to be encoded is longer - %d > %d\n",
251 __func__, string_len, temp_ei->elem_len);
252 return -EINVAL;
253 }
254
255 if (enc_level == 1) {
256 if (string_len + TLV_LEN_SIZE + TLV_TYPE_SIZE >
257 out_buf_len) {
258 pr_err("%s: Output len %d > Out Buf len %d\n",
259 __func__, string_len, out_buf_len);
260 return -ETOOSMALL;
261 }
262 } else {
263 if (string_len + string_len_sz > out_buf_len) {
264 pr_err("%s: Output len %d > Out Buf len %d\n",
265 __func__, string_len, out_buf_len);
266 return -ETOOSMALL;
267 }
268 rc = qmi_encode_basic_elem(buf_dst, &string_len,
269 1, string_len_sz);
270 encoded_bytes += rc;
271 }
272
273 rc = qmi_encode_basic_elem(buf_dst + encoded_bytes, buf_src,
274 string_len, temp_ei->elem_size);
275 encoded_bytes += rc;
276
277 return encoded_bytes;
278}
279
280/**
281 * qmi_encode() - Core Encode Function
282 * @ei_array: Struct info array describing the structure to be encoded.
283 * @out_buf: Buffer to hold the encoded QMI message.
284 * @in_c_struct: Pointer to the C structure to be encoded.
285 * @out_buf_len: Available space in the encode buffer.
286 * @enc_level: Encode level to indicate the depth of the nested structure,
287 * within the main structure, being encoded.
288 *
289 * Return: The number of bytes of encoded information on success or negative
290 * errno on error.
291 */
292static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
293 const void *in_c_struct, u32 out_buf_len,
294 int enc_level)
295{
296 struct qmi_elem_info *temp_ei = ei_array;
297 u8 opt_flag_value = 0;
298 u32 data_len_value = 0, data_len_sz;
299 u8 *buf_dst = (u8 *)out_buf;
300 u8 *tlv_pointer;
301 u32 tlv_len;
302 u8 tlv_type;
303 u32 encoded_bytes = 0;
304 const void *buf_src;
305 int encode_tlv = 0;
306 int rc;
307
308 if (!ei_array)
309 return 0;
310
311 tlv_pointer = buf_dst;
312 tlv_len = 0;
313 if (enc_level == 1)
314 buf_dst = buf_dst + (TLV_LEN_SIZE + TLV_TYPE_SIZE);
315
316 while (temp_ei->data_type != QMI_EOTI) {
317 buf_src = in_c_struct + temp_ei->offset;
318 tlv_type = temp_ei->tlv_type;
319
320 if (temp_ei->array_type == NO_ARRAY) {
321 data_len_value = 1;
322 } else if (temp_ei->array_type == STATIC_ARRAY) {
323 data_len_value = temp_ei->elem_len;
324 } else if (data_len_value <= 0 ||
325 temp_ei->elem_len < data_len_value) {
326 pr_err("%s: Invalid data length\n", __func__);
327 return -EINVAL;
328 }
329
330 switch (temp_ei->data_type) {
331 case QMI_OPT_FLAG:
332 rc = qmi_encode_basic_elem(&opt_flag_value, buf_src,
333 1, sizeof(u8));
334 if (opt_flag_value)
335 temp_ei = temp_ei + 1;
336 else
337 temp_ei = skip_to_next_elem(temp_ei, enc_level);
338 break;
339
340 case QMI_DATA_LEN:
341 memcpy(&data_len_value, buf_src, temp_ei->elem_size);
342 data_len_sz = temp_ei->elem_size == sizeof(u8) ?
343 sizeof(u8) : sizeof(u16);
344 /* Check to avoid out of range buffer access */
345 if ((data_len_sz + encoded_bytes + TLV_LEN_SIZE +
346 TLV_TYPE_SIZE) > out_buf_len) {
347 pr_err("%s: Too Small Buffer @DATA_LEN\n",
348 __func__);
349 return -ETOOSMALL;
350 }
351 rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
352 1, data_len_sz);
353 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
354 encoded_bytes, tlv_len,
355 encode_tlv, rc);
356 if (!data_len_value)
357 temp_ei = skip_to_next_elem(temp_ei, enc_level);
358 else
359 encode_tlv = 0;
360 break;
361
362 case QMI_UNSIGNED_1_BYTE:
363 case QMI_UNSIGNED_2_BYTE:
364 case QMI_UNSIGNED_4_BYTE:
365 case QMI_UNSIGNED_8_BYTE:
366 case QMI_SIGNED_2_BYTE_ENUM:
367 case QMI_SIGNED_4_BYTE_ENUM:
368 /* Check to avoid out of range buffer access */
369 if (((data_len_value * temp_ei->elem_size) +
370 encoded_bytes + TLV_LEN_SIZE + TLV_TYPE_SIZE) >
371 out_buf_len) {
372 pr_err("%s: Too Small Buffer @data_type:%d\n",
373 __func__, temp_ei->data_type);
374 return -ETOOSMALL;
375 }
376 rc = qmi_encode_basic_elem(buf_dst, buf_src,
377 data_len_value,
378 temp_ei->elem_size);
379 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
380 encoded_bytes, tlv_len,
381 encode_tlv, rc);
382 break;
383
384 case QMI_STRUCT:
385 rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
386 data_len_value,
387 out_buf_len - encoded_bytes,
388 enc_level + 1);
389 if (rc < 0)
390 return rc;
391 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
392 encoded_bytes, tlv_len,
393 encode_tlv, rc);
394 break;
395
396 case QMI_STRING:
397 rc = qmi_encode_string_elem(temp_ei, buf_dst, buf_src,
398 out_buf_len - encoded_bytes,
399 enc_level);
400 if (rc < 0)
401 return rc;
402 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
403 encoded_bytes, tlv_len,
404 encode_tlv, rc);
405 break;
406 default:
407 pr_err("%s: Unrecognized data type\n", __func__);
408 return -EINVAL;
409 }
410
411 if (encode_tlv && enc_level == 1) {
412 QMI_ENCDEC_ENCODE_TLV(tlv_type, tlv_len, tlv_pointer);
413 encoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
414 tlv_pointer = buf_dst;
415 tlv_len = 0;
416 buf_dst = buf_dst + TLV_LEN_SIZE + TLV_TYPE_SIZE;
417 encode_tlv = 0;
418 }
419 }
420
421 return encoded_bytes;
422}
423
424/**
425 * qmi_decode_basic_elem() - Decodes elements of basic/primary data type
426 * @buf_dst: Buffer to store the decoded element.
427 * @buf_src: Buffer containing the elements in QMI wire format.
428 * @elem_len: Number of elements to be decoded.
429 * @elem_size: Size of a single instance of the element to be decoded.
430 *
431 * This function decodes the "elem_len" number of elements in QMI wire format,
432 * each of size "elem_size" bytes from the source buffer "buf_src" and stores
433 * the decoded elements in the destination buffer "buf_dst". The elements are
434 * of primary data type which include u8 - u64 or similar. This
435 * function returns the number of bytes of decoded information.
436 *
437 * Return: The total size of the decoded data elements, in bytes.
438 */
439static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src,
440 u32 elem_len, u32 elem_size)
441{
442 u32 i, rc = 0;
443
444 for (i = 0; i < elem_len; i++) {
445 QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size);
446 rc += elem_size;
447 }
448
449 return rc;
450}
451
452/**
453 * qmi_decode_struct_elem() - Decodes elements of struct data type
454 * @ei_array: Struct info array descibing the struct element.
455 * @buf_dst: Buffer to store the decoded element.
456 * @buf_src: Buffer containing the elements in QMI wire format.
457 * @elem_len: Number of elements to be decoded.
458 * @tlv_len: Total size of the encoded inforation corresponding to
459 * this struct element.
460 * @dec_level: Depth of the nested structure from the main structure.
461 *
462 * This function decodes the "elem_len" number of elements in QMI wire format,
463 * each of size "(tlv_len/elem_len)" bytes from the source buffer "buf_src"
464 * and stores the decoded elements in the destination buffer "buf_dst". The
465 * elements are of struct data type which includes any C structure. This
466 * function returns the number of bytes of decoded information.
467 *
468 * Return: The total size of the decoded data elements on success, negative
469 * errno on error.
470 */
471static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array,
472 void *buf_dst, const void *buf_src,
473 u32 elem_len, u32 tlv_len,
474 int dec_level)
475{
476 int i, rc, decoded_bytes = 0;
477 struct qmi_elem_info *temp_ei = ei_array;
478
479 for (i = 0; i < elem_len && decoded_bytes < tlv_len; i++) {
480 rc = qmi_decode(temp_ei->ei_array, buf_dst, buf_src,
481 tlv_len - decoded_bytes, dec_level);
482 if (rc < 0)
483 return rc;
484 buf_src = buf_src + rc;
485 buf_dst = buf_dst + temp_ei->elem_size;
486 decoded_bytes += rc;
487 }
488
489 if ((dec_level <= 2 && decoded_bytes != tlv_len) ||
490 (dec_level > 2 && (i < elem_len || decoded_bytes > tlv_len))) {
491 pr_err("%s: Fault in decoding: dl(%d), db(%d), tl(%d), i(%d), el(%d)\n",
492 __func__, dec_level, decoded_bytes, tlv_len,
493 i, elem_len);
494 return -EFAULT;
495 }
496
497 return decoded_bytes;
498}
499
500/**
501 * qmi_decode_string_elem() - Decodes elements of string data type
502 * @ei_array: Struct info array descibing the string element.
503 * @buf_dst: Buffer to store the decoded element.
504 * @buf_src: Buffer containing the elements in QMI wire format.
505 * @tlv_len: Total size of the encoded inforation corresponding to
506 * this string element.
507 * @dec_level: Depth of the string element from the main structure.
508 *
509 * This function decodes the string element of maximum length
510 * "ei_array->elem_len" from the source buffer "buf_src" and puts it into
511 * the destination buffer "buf_dst". This function returns number of bytes
512 * decoded from the input buffer.
513 *
514 * Return: The total size of the decoded data elements on success, negative
515 * errno on error.
516 */
517static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
518 void *buf_dst, const void *buf_src,
519 u32 tlv_len, int dec_level)
520{
521 int rc;
522 int decoded_bytes = 0;
523 u32 string_len = 0;
524 u32 string_len_sz = 0;
525 struct qmi_elem_info *temp_ei = ei_array;
526
527 if (dec_level == 1) {
528 string_len = tlv_len;
529 } else {
530 string_len_sz = temp_ei->elem_len <= U8_MAX ?
531 sizeof(u8) : sizeof(u16);
532 rc = qmi_decode_basic_elem(&string_len, buf_src,
533 1, string_len_sz);
534 decoded_bytes += rc;
535 }
536
537 if (string_len > temp_ei->elem_len) {
538 pr_err("%s: String len %d > Max Len %d\n",
539 __func__, string_len, temp_ei->elem_len);
540 return -ETOOSMALL;
541 } else if (string_len > tlv_len) {
542 pr_err("%s: String len %d > Input Buffer Len %d\n",
543 __func__, string_len, tlv_len);
544 return -EFAULT;
545 }
546
547 rc = qmi_decode_basic_elem(buf_dst, buf_src + decoded_bytes,
548 string_len, temp_ei->elem_size);
549 *((char *)buf_dst + string_len) = '\0';
550 decoded_bytes += rc;
551
552 return decoded_bytes;
553}
554
555/**
556 * find_ei() - Find element info corresponding to TLV Type
557 * @ei_array: Struct info array of the message being decoded.
558 * @type: TLV Type of the element being searched.
559 *
560 * Every element that got encoded in the QMI message will have a type
561 * information associated with it. While decoding the QMI message,
562 * this function is used to find the struct info regarding the element
563 * that corresponds to the type being decoded.
564 *
565 * Return: Pointer to struct info, if found
566 */
567static struct qmi_elem_info *find_ei(struct qmi_elem_info *ei_array,
568 u32 type)
569{
570 struct qmi_elem_info *temp_ei = ei_array;
571
572 while (temp_ei->data_type != QMI_EOTI) {
573 if (temp_ei->tlv_type == (u8)type)
574 return temp_ei;
575 temp_ei = temp_ei + 1;
576 }
577
578 return NULL;
579}
580
581/**
582 * qmi_decode() - Core Decode Function
583 * @ei_array: Struct info array describing the structure to be decoded.
584 * @out_c_struct: Buffer to hold the decoded C struct
585 * @in_buf: Buffer containing the QMI message to be decoded
586 * @in_buf_len: Length of the QMI message to be decoded
587 * @dec_level: Decode level to indicate the depth of the nested structure,
588 * within the main structure, being decoded
589 *
590 * Return: The number of bytes of decoded information on success, negative
591 * errno on error.
592 */
593static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
594 const void *in_buf, u32 in_buf_len,
595 int dec_level)
596{
597 struct qmi_elem_info *temp_ei = ei_array;
598 u8 opt_flag_value = 1;
599 u32 data_len_value = 0, data_len_sz = 0;
600 u8 *buf_dst = out_c_struct;
601 const u8 *tlv_pointer;
602 u32 tlv_len = 0;
603 u32 tlv_type;
604 u32 decoded_bytes = 0;
605 const void *buf_src = in_buf;
606 int rc;
607
608 while (decoded_bytes < in_buf_len) {
609 if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI)
610 return decoded_bytes;
611
612 if (dec_level == 1) {
613 tlv_pointer = buf_src;
614 QMI_ENCDEC_DECODE_TLV(&tlv_type,
615 &tlv_len, tlv_pointer);
616 buf_src += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
617 decoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
618 temp_ei = find_ei(ei_array, tlv_type);
619 if (!temp_ei && tlv_type < OPTIONAL_TLV_TYPE_START) {
620 pr_err("%s: Inval element info\n", __func__);
621 return -EINVAL;
622 } else if (!temp_ei) {
623 UPDATE_DECODE_VARIABLES(buf_src,
624 decoded_bytes, tlv_len);
625 continue;
626 }
627 } else {
628 /*
629 * No length information for elements in nested
630 * structures. So use remaining decodable buffer space.
631 */
632 tlv_len = in_buf_len - decoded_bytes;
633 }
634
635 buf_dst = out_c_struct + temp_ei->offset;
636 if (temp_ei->data_type == QMI_OPT_FLAG) {
637 memcpy(buf_dst, &opt_flag_value, sizeof(u8));
638 temp_ei = temp_ei + 1;
639 buf_dst = out_c_struct + temp_ei->offset;
640 }
641
642 if (temp_ei->data_type == QMI_DATA_LEN) {
643 data_len_sz = temp_ei->elem_size == sizeof(u8) ?
644 sizeof(u8) : sizeof(u16);
645 rc = qmi_decode_basic_elem(&data_len_value, buf_src,
646 1, data_len_sz);
647 memcpy(buf_dst, &data_len_value, sizeof(u32));
648 temp_ei = temp_ei + 1;
649 buf_dst = out_c_struct + temp_ei->offset;
650 tlv_len -= data_len_sz;
651 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
652 }
653
654 if (temp_ei->array_type == NO_ARRAY) {
655 data_len_value = 1;
656 } else if (temp_ei->array_type == STATIC_ARRAY) {
657 data_len_value = temp_ei->elem_len;
658 } else if (data_len_value > temp_ei->elem_len) {
659 pr_err("%s: Data len %d > max spec %d\n",
660 __func__, data_len_value, temp_ei->elem_len);
661 return -ETOOSMALL;
662 }
663
664 switch (temp_ei->data_type) {
665 case QMI_UNSIGNED_1_BYTE:
666 case QMI_UNSIGNED_2_BYTE:
667 case QMI_UNSIGNED_4_BYTE:
668 case QMI_UNSIGNED_8_BYTE:
669 case QMI_SIGNED_2_BYTE_ENUM:
670 case QMI_SIGNED_4_BYTE_ENUM:
671 rc = qmi_decode_basic_elem(buf_dst, buf_src,
672 data_len_value,
673 temp_ei->elem_size);
674 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
675 break;
676
677 case QMI_STRUCT:
678 rc = qmi_decode_struct_elem(temp_ei, buf_dst, buf_src,
679 data_len_value, tlv_len,
680 dec_level + 1);
681 if (rc < 0)
682 return rc;
683 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
684 break;
685
686 case QMI_STRING:
687 rc = qmi_decode_string_elem(temp_ei, buf_dst, buf_src,
688 tlv_len, dec_level);
689 if (rc < 0)
690 return rc;
691 UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc);
692 break;
693
694 default:
695 pr_err("%s: Unrecognized data type\n", __func__);
696 return -EINVAL;
697 }
698 temp_ei = temp_ei + 1;
699 }
700
701 return decoded_bytes;
702}
703
704/**
705 * qmi_encode_message() - Encode C structure as QMI encoded message
706 * @type: Type of QMI message
707 * @msg_id: Message ID of the message
708 * @len: Passed as max length of the message, updated to actual size
709 * @txn_id: Transaction ID
710 * @ei: QMI message descriptor
711 * @c_struct: Reference to structure to encode
712 *
713 * Return: Buffer with encoded message, or negative ERR_PTR() on error
714 */
715void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
716 unsigned int txn_id, struct qmi_elem_info *ei,
717 const void *c_struct)
718{
719 struct qmi_header *hdr;
720 ssize_t msglen = 0;
721 void *msg;
722 int ret;
723
724 /* Check the possibility of a zero length QMI message */
725 if (!c_struct) {
726 ret = qmi_calc_min_msg_len(ei, 1);
727 if (ret) {
728 pr_err("%s: Calc. len %d != 0, but NULL c_struct\n",
729 __func__, ret);
730 return ERR_PTR(-EINVAL);
731 }
732 }
733
734 msg = kzalloc(sizeof(*hdr) + *len, GFP_KERNEL);
735 if (!msg)
736 return ERR_PTR(-ENOMEM);
737
738 /* Encode message, if we have a message */
739 if (c_struct) {
740 msglen = qmi_encode(ei, msg + sizeof(*hdr), c_struct, *len, 1);
741 if (msglen < 0) {
742 kfree(msg);
743 return ERR_PTR(msglen);
744 }
745 }
746
747 hdr = msg;
748 hdr->type = type;
749 hdr->txn_id = txn_id;
750 hdr->msg_id = msg_id;
751 hdr->msg_len = msglen;
752
753 *len = sizeof(*hdr) + msglen;
754
755 return msg;
756}
757EXPORT_SYMBOL(qmi_encode_message);
758
759/**
760 * qmi_decode_message() - Decode QMI encoded message to C structure
761 * @buf: Buffer with encoded message
762 * @len: Amount of data in @buf
763 * @ei: QMI message descriptor
764 * @c_struct: Reference to structure to decode into
765 *
766 * Return: The number of bytes of decoded information on success, negative
767 * errno on error.
768 */
769int qmi_decode_message(const void *buf, size_t len,
770 struct qmi_elem_info *ei, void *c_struct)
771{
772 if (!ei)
773 return -EINVAL;
774
775 if (!c_struct || !buf || !len)
776 return -EINVAL;
777
778 return qmi_decode(ei, c_struct, buf + sizeof(struct qmi_header),
779 len - sizeof(struct qmi_header), 1);
780}
781EXPORT_SYMBOL(qmi_decode_message);
782
783/* Common header in all QMI responses */
784struct qmi_elem_info qmi_response_type_v01_ei[] = {
785 {
786 .data_type = QMI_SIGNED_2_BYTE_ENUM,
787 .elem_len = 1,
788 .elem_size = sizeof(u16),
789 .array_type = NO_ARRAY,
790 .tlv_type = QMI_COMMON_TLV_TYPE,
791 .offset = offsetof(struct qmi_response_type_v01, result),
792 .ei_array = NULL,
793 },
794 {
795 .data_type = QMI_SIGNED_2_BYTE_ENUM,
796 .elem_len = 1,
797 .elem_size = sizeof(u16),
798 .array_type = NO_ARRAY,
799 .tlv_type = QMI_COMMON_TLV_TYPE,
800 .offset = offsetof(struct qmi_response_type_v01, error),
801 .ei_array = NULL,
802 },
803 {
804 .data_type = QMI_EOTI,
805 .elem_len = 0,
806 .elem_size = 0,
807 .array_type = NO_ARRAY,
808 .tlv_type = QMI_COMMON_TLV_TYPE,
809 .offset = 0,
810 .ei_array = NULL,
811 },
812};
813EXPORT_SYMBOL(qmi_response_type_v01_ei);
814
815MODULE_DESCRIPTION("QMI encoder/decoder helper");
816MODULE_LICENSE("GPL v2");
diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h
new file mode 100644
index 000000000000..3523295f3022
--- /dev/null
+++ b/include/linux/soc/qcom/qmi.h
@@ -0,0 +1,106 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
4 * Copyright (c) 2017, Linaro Ltd.
5 */
6#ifndef __QMI_HELPERS_H__
7#define __QMI_HELPERS_H__
8
9#include <linux/types.h>
10
11/**
12 * qmi_header - wireformat header of QMI messages
13 * @type: type of message
14 * @txn_id: transaction id
15 * @msg_id: message id
16 * @msg_len: length of message payload following header
17 */
18struct qmi_header {
19 u8 type;
20 u16 txn_id;
21 u16 msg_id;
22 u16 msg_len;
23} __packed;
24
25#define QMI_REQUEST 0
26#define QMI_RESPONSE 2
27#define QMI_INDICATION 4
28
29#define QMI_COMMON_TLV_TYPE 0
30
31enum qmi_elem_type {
32 QMI_EOTI,
33 QMI_OPT_FLAG,
34 QMI_DATA_LEN,
35 QMI_UNSIGNED_1_BYTE,
36 QMI_UNSIGNED_2_BYTE,
37 QMI_UNSIGNED_4_BYTE,
38 QMI_UNSIGNED_8_BYTE,
39 QMI_SIGNED_2_BYTE_ENUM,
40 QMI_SIGNED_4_BYTE_ENUM,
41 QMI_STRUCT,
42 QMI_STRING,
43};
44
45enum qmi_array_type {
46 NO_ARRAY,
47 STATIC_ARRAY,
48 VAR_LEN_ARRAY,
49};
50
51/**
52 * struct qmi_elem_info - describes how to encode a single QMI element
53 * @data_type: Data type of this element.
54 * @elem_len: Array length of this element, if an array.
55 * @elem_size: Size of a single instance of this data type.
56 * @array_type: Array type of this element.
57 * @tlv_type: QMI message specific type to identify which element
58 * is present in an incoming message.
59 * @offset: Specifies the offset of the first instance of this
60 * element in the data structure.
61 * @ei_array: Null-terminated array of @qmi_elem_info to describe nested
62 * structures.
63 */
64struct qmi_elem_info {
65 enum qmi_elem_type data_type;
66 u32 elem_len;
67 u32 elem_size;
68 enum qmi_array_type array_type;
69 u8 tlv_type;
70 u32 offset;
71 struct qmi_elem_info *ei_array;
72};
73
74#define QMI_RESULT_SUCCESS_V01 0
75#define QMI_RESULT_FAILURE_V01 1
76
77#define QMI_ERR_NONE_V01 0
78#define QMI_ERR_MALFORMED_MSG_V01 1
79#define QMI_ERR_NO_MEMORY_V01 2
80#define QMI_ERR_INTERNAL_V01 3
81#define QMI_ERR_CLIENT_IDS_EXHAUSTED_V01 5
82#define QMI_ERR_INVALID_ID_V01 41
83#define QMI_ERR_ENCODING_V01 58
84#define QMI_ERR_INCOMPATIBLE_STATE_V01 90
85#define QMI_ERR_NOT_SUPPORTED_V01 94
86
87/**
88 * qmi_response_type_v01 - common response header (decoded)
89 * @result: result of the transaction
90 * @error: error value, when @result is QMI_RESULT_FAILURE_V01
91 */
92struct qmi_response_type_v01 {
93 u16 result;
94 u16 error;
95};
96
97extern struct qmi_elem_info qmi_response_type_v01_ei[];
98
99void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
100 unsigned int txn_id, struct qmi_elem_info *ei,
101 const void *c_struct);
102
103int qmi_decode_message(const void *buf, size_t len,
104 struct qmi_elem_info *ei, void *c_struct);
105
106#endif