* [PATCH 0/2] soc: qcom: QMI helpers supports for big endian
@ 2025-05-21 9:25 Alexander Wilhelm
2025-05-21 9:25 ` [PATCH 1/2] soc: qcom: QMI encoding/decoding " Alexander Wilhelm
2025-05-21 9:25 ` [PATCH 2/2] soc: qcom: fix endianness for QMI header Alexander Wilhelm
0 siblings, 2 replies; 4+ messages in thread
From: Alexander Wilhelm @ 2025-05-21 9:25 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio; +Cc: linux-arm-msm, linux-kernel
Fix QMI encoding and decoding for variable length elements to support big
endian platforms. Also fix endiannes for QMI header.
Alexander Wilhelm (2):
soc: qcom: QMI encoding/decoding for big endian
soc: qcom: fix endianness for QMI header
drivers/soc/qcom/qmi_encdec.c | 52 +++++++++++++++++++++++++-------
drivers/soc/qcom/qmi_interface.c | 6 ++--
include/linux/soc/qcom/qmi.h | 6 ++--
3 files changed, 47 insertions(+), 17 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] soc: qcom: QMI encoding/decoding for big endian
2025-05-21 9:25 [PATCH 0/2] soc: qcom: QMI helpers supports for big endian Alexander Wilhelm
@ 2025-05-21 9:25 ` Alexander Wilhelm
2025-05-22 14:03 ` kernel test robot
2025-05-21 9:25 ` [PATCH 2/2] soc: qcom: fix endianness for QMI header Alexander Wilhelm
1 sibling, 1 reply; 4+ messages in thread
From: Alexander Wilhelm @ 2025-05-21 9:25 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio; +Cc: linux-arm-msm, linux-kernel
The QMI_DATA_LEN type may have different sizes. Taking the element's
address of that type and interpret it as a smaller sized ones works fine
for little endian platforms but not for big endian ones. Instead use
temporary variables of smaller sized types and cast them correctly to
support big endian platforms.
Fixes: 9b8a11e82615 ("soc: qcom: Introduce QMI encoder/decoder")
Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
---
drivers/soc/qcom/qmi_encdec.c | 46 +++++++++++++++++++++++++++++------
1 file changed, 38 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c
index bb09eff85cff..7e91c0b4fc52 100644
--- a/drivers/soc/qcom/qmi_encdec.c
+++ b/drivers/soc/qcom/qmi_encdec.c
@@ -304,6 +304,8 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
const void *buf_src;
int encode_tlv = 0;
int rc;
+ u8 val8;
+ u16 val16;
if (!ei_array)
return 0;
@@ -338,7 +340,6 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
break;
case QMI_DATA_LEN:
- memcpy(&data_len_value, buf_src, temp_ei->elem_size);
data_len_sz = temp_ei->elem_size == sizeof(u8) ?
sizeof(u8) : sizeof(u16);
/* Check to avoid out of range buffer access */
@@ -348,8 +349,17 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
__func__);
return -ETOOSMALL;
}
- rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
- 1, data_len_sz);
+ if (data_len_sz == sizeof(u8)) {
+ val8 = *(u8 *)buf_src;
+ data_len_value = val8;
+ rc = qmi_encode_basic_elem(buf_dst, &val8,
+ 1, data_len_sz);
+ } else {
+ val16 = *(u16 *)buf_src;
+ data_len_value = le16_to_cpu(val16);
+ rc = qmi_encode_basic_elem(buf_dst, &val16,
+ 1, data_len_sz);
+ }
UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
encoded_bytes, tlv_len,
encode_tlv, rc);
@@ -523,14 +533,23 @@ static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array,
u32 string_len = 0;
u32 string_len_sz = 0;
const struct qmi_elem_info *temp_ei = ei_array;
+ u8 val8;
+ u16 val16;
if (dec_level == 1) {
string_len = tlv_len;
} else {
string_len_sz = temp_ei->elem_len <= U8_MAX ?
sizeof(u8) : sizeof(u16);
- rc = qmi_decode_basic_elem(&string_len, buf_src,
- 1, string_len_sz);
+ if (string_len_sz == sizeof(u8)) {
+ rc = qmi_decode_basic_elem(&val8, buf_src,
+ 1, string_len_sz);
+ string_len = val8;
+ } else {
+ rc = qmi_decode_basic_elem(&val16, buf_src,
+ 1, string_len_sz);
+ string_len = val16;
+ }
decoded_bytes += rc;
}
@@ -604,6 +623,9 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
u32 decoded_bytes = 0;
const void *buf_src = in_buf;
int rc;
+ u8 val8;
+ u16 val16;
+ u32 val32;
while (decoded_bytes < in_buf_len) {
if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI)
@@ -642,9 +664,17 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
if (temp_ei->data_type == QMI_DATA_LEN) {
data_len_sz = temp_ei->elem_size == sizeof(u8) ?
sizeof(u8) : sizeof(u16);
- rc = qmi_decode_basic_elem(&data_len_value, buf_src,
- 1, data_len_sz);
- memcpy(buf_dst, &data_len_value, sizeof(u32));
+ if (data_len_sz == sizeof(u8)) {
+ rc = qmi_decode_basic_elem(&val8, buf_src,
+ 1, data_len_sz);
+ data_len_value = val8;
+ } else {
+ rc = qmi_decode_basic_elem(&val16, buf_src,
+ 1, data_len_sz);
+ data_len_value = val16;
+ }
+ val32 = cpu_to_le32(data_len_value);
+ memcpy(buf_dst, &val32, sizeof(u32));
temp_ei = temp_ei + 1;
buf_dst = out_c_struct + temp_ei->offset;
tlv_len -= data_len_sz;
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] soc: qcom: fix endianness for QMI header
2025-05-21 9:25 [PATCH 0/2] soc: qcom: QMI helpers supports for big endian Alexander Wilhelm
2025-05-21 9:25 ` [PATCH 1/2] soc: qcom: QMI encoding/decoding " Alexander Wilhelm
@ 2025-05-21 9:25 ` Alexander Wilhelm
1 sibling, 0 replies; 4+ messages in thread
From: Alexander Wilhelm @ 2025-05-21 9:25 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio; +Cc: linux-arm-msm, linux-kernel
The members of QMI header have to be swapped on big endian platforms. Use
__le16 types instead of u16 ones.
Fixes: 9b8a11e82615 ("soc: qcom: Introduce QMI encoder/decoder")
Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
---
drivers/soc/qcom/qmi_encdec.c | 6 +++---
drivers/soc/qcom/qmi_interface.c | 6 +++---
include/linux/soc/qcom/qmi.h | 6 +++---
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c
index 7e91c0b4fc52..f031bdc48eb3 100644
--- a/drivers/soc/qcom/qmi_encdec.c
+++ b/drivers/soc/qcom/qmi_encdec.c
@@ -776,9 +776,9 @@ void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
hdr = msg;
hdr->type = type;
- hdr->txn_id = txn_id;
- hdr->msg_id = msg_id;
- hdr->msg_len = msglen;
+ hdr->txn_id = cpu_to_le16(txn_id);
+ hdr->msg_id = cpu_to_le16(msg_id);
+ hdr->msg_len = cpu_to_le16(msglen);
*len = sizeof(*hdr) + msglen;
diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c
index bc6d6379d8b1..6500f863aae5 100644
--- a/drivers/soc/qcom/qmi_interface.c
+++ b/drivers/soc/qcom/qmi_interface.c
@@ -400,7 +400,7 @@ static void qmi_invoke_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
for (handler = qmi->handlers; handler->fn; handler++) {
if (handler->type == hdr->type &&
- handler->msg_id == hdr->msg_id)
+ handler->msg_id == le16_to_cpu(hdr->msg_id))
break;
}
@@ -488,7 +488,7 @@ static void qmi_handle_message(struct qmi_handle *qmi,
/* If this is a response, find the matching transaction handle */
if (hdr->type == QMI_RESPONSE) {
mutex_lock(&qmi->txn_lock);
- txn = idr_find(&qmi->txns, hdr->txn_id);
+ txn = idr_find(&qmi->txns, le16_to_cpu(hdr->txn_id));
/* Ignore unexpected responses */
if (!txn) {
@@ -514,7 +514,7 @@ static void qmi_handle_message(struct qmi_handle *qmi,
} else {
/* Create a txn based on the txn_id of the incoming message */
memset(&tmp_txn, 0, sizeof(tmp_txn));
- tmp_txn.id = hdr->txn_id;
+ tmp_txn.id = le16_to_cpu(hdr->txn_id);
qmi_invoke_handler(qmi, sq, &tmp_txn, buf, len);
}
diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h
index 469e02d2aa0d..291cdc7ef49c 100644
--- a/include/linux/soc/qcom/qmi.h
+++ b/include/linux/soc/qcom/qmi.h
@@ -24,9 +24,9 @@ struct socket;
*/
struct qmi_header {
u8 type;
- u16 txn_id;
- u16 msg_id;
- u16 msg_len;
+ __le16 txn_id;
+ __le16 msg_id;
+ __le16 msg_len;
} __packed;
#define QMI_REQUEST 0
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] soc: qcom: QMI encoding/decoding for big endian
2025-05-21 9:25 ` [PATCH 1/2] soc: qcom: QMI encoding/decoding " Alexander Wilhelm
@ 2025-05-22 14:03 ` kernel test robot
0 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2025-05-22 14:03 UTC (permalink / raw)
To: Alexander Wilhelm, Bjorn Andersson, Konrad Dybcio
Cc: oe-kbuild-all, linux-arm-msm, linux-kernel
Hi Alexander,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.15-rc7 next-20250522]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Alexander-Wilhelm/soc-qcom-QMI-encoding-decoding-for-big-endian/20250521-172849
base: linus/master
patch link: https://lore.kernel.org/r/20250521092554.1026716-2-alexander.wilhelm%40westermo.com
patch subject: [PATCH 1/2] soc: qcom: QMI encoding/decoding for big endian
config: csky-randconfig-r132-20250522 (https://download.01.org/0day-ci/archive/20250522/202505222118.Hv5tsNGQ-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 15.1.0
reproduce: (https://download.01.org/0day-ci/archive/20250522/202505222118.Hv5tsNGQ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505222118.Hv5tsNGQ-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/soc/qcom/qmi_encdec.c:359:50: sparse: sparse: cast to restricted __le16
>> drivers/soc/qcom/qmi_encdec.c:676:31: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] val32 @@ got restricted __le32 [usertype] @@
drivers/soc/qcom/qmi_encdec.c:676:31: sparse: expected unsigned int [usertype] val32
drivers/soc/qcom/qmi_encdec.c:676:31: sparse: got restricted __le32 [usertype]
vim +359 drivers/soc/qcom/qmi_encdec.c
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 */
292 static int qmi_encode(const 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 const 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 u8 val8;
308 u16 val16;
309
310 if (!ei_array)
311 return 0;
312
313 tlv_pointer = buf_dst;
314 tlv_len = 0;
315 if (enc_level == 1)
316 buf_dst = buf_dst + (TLV_LEN_SIZE + TLV_TYPE_SIZE);
317
318 while (temp_ei->data_type != QMI_EOTI) {
319 buf_src = in_c_struct + temp_ei->offset;
320 tlv_type = temp_ei->tlv_type;
321
322 if (temp_ei->array_type == NO_ARRAY) {
323 data_len_value = 1;
324 } else if (temp_ei->array_type == STATIC_ARRAY) {
325 data_len_value = temp_ei->elem_len;
326 } else if (data_len_value <= 0 ||
327 temp_ei->elem_len < data_len_value) {
328 pr_err("%s: Invalid data length\n", __func__);
329 return -EINVAL;
330 }
331
332 switch (temp_ei->data_type) {
333 case QMI_OPT_FLAG:
334 rc = qmi_encode_basic_elem(&opt_flag_value, buf_src,
335 1, sizeof(u8));
336 if (opt_flag_value)
337 temp_ei = temp_ei + 1;
338 else
339 temp_ei = skip_to_next_elem(temp_ei, enc_level);
340 break;
341
342 case QMI_DATA_LEN:
343 data_len_sz = temp_ei->elem_size == sizeof(u8) ?
344 sizeof(u8) : sizeof(u16);
345 /* Check to avoid out of range buffer access */
346 if ((data_len_sz + encoded_bytes + TLV_LEN_SIZE +
347 TLV_TYPE_SIZE) > out_buf_len) {
348 pr_err("%s: Too Small Buffer @DATA_LEN\n",
349 __func__);
350 return -ETOOSMALL;
351 }
352 if (data_len_sz == sizeof(u8)) {
353 val8 = *(u8 *)buf_src;
354 data_len_value = val8;
355 rc = qmi_encode_basic_elem(buf_dst, &val8,
356 1, data_len_sz);
357 } else {
358 val16 = *(u16 *)buf_src;
> 359 data_len_value = le16_to_cpu(val16);
360 rc = qmi_encode_basic_elem(buf_dst, &val16,
361 1, data_len_sz);
362 }
363 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
364 encoded_bytes, tlv_len,
365 encode_tlv, rc);
366 if (!data_len_value)
367 temp_ei = skip_to_next_elem(temp_ei, enc_level);
368 else
369 encode_tlv = 0;
370 break;
371
372 case QMI_UNSIGNED_1_BYTE:
373 case QMI_UNSIGNED_2_BYTE:
374 case QMI_UNSIGNED_4_BYTE:
375 case QMI_UNSIGNED_8_BYTE:
376 case QMI_SIGNED_2_BYTE_ENUM:
377 case QMI_SIGNED_4_BYTE_ENUM:
378 /* Check to avoid out of range buffer access */
379 if (((data_len_value * temp_ei->elem_size) +
380 encoded_bytes + TLV_LEN_SIZE + TLV_TYPE_SIZE) >
381 out_buf_len) {
382 pr_err("%s: Too Small Buffer @data_type:%d\n",
383 __func__, temp_ei->data_type);
384 return -ETOOSMALL;
385 }
386 rc = qmi_encode_basic_elem(buf_dst, buf_src,
387 data_len_value,
388 temp_ei->elem_size);
389 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
390 encoded_bytes, tlv_len,
391 encode_tlv, rc);
392 break;
393
394 case QMI_STRUCT:
395 rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
396 data_len_value,
397 out_buf_len - encoded_bytes,
398 enc_level + 1);
399 if (rc < 0)
400 return rc;
401 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
402 encoded_bytes, tlv_len,
403 encode_tlv, rc);
404 break;
405
406 case QMI_STRING:
407 rc = qmi_encode_string_elem(temp_ei, buf_dst, buf_src,
408 out_buf_len - encoded_bytes,
409 enc_level);
410 if (rc < 0)
411 return rc;
412 UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
413 encoded_bytes, tlv_len,
414 encode_tlv, rc);
415 break;
416 default:
417 pr_err("%s: Unrecognized data type\n", __func__);
418 return -EINVAL;
419 }
420
421 if (encode_tlv && enc_level == 1) {
422 QMI_ENCDEC_ENCODE_TLV(tlv_type, tlv_len, tlv_pointer);
423 encoded_bytes += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
424 tlv_pointer = buf_dst;
425 tlv_len = 0;
426 buf_dst = buf_dst + TLV_LEN_SIZE + TLV_TYPE_SIZE;
427 encode_tlv = 0;
428 }
429 }
430
431 return encoded_bytes;
432 }
433
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-05-22 14:04 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-21 9:25 [PATCH 0/2] soc: qcom: QMI helpers supports for big endian Alexander Wilhelm
2025-05-21 9:25 ` [PATCH 1/2] soc: qcom: QMI encoding/decoding " Alexander Wilhelm
2025-05-22 14:03 ` kernel test robot
2025-05-21 9:25 ` [PATCH 2/2] soc: qcom: fix endianness for QMI header Alexander Wilhelm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox