Linux ARM-MSM sub-architecture
 help / color / mirror / Atom feed
* [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