These macros enable future support for encoding and decoding primitive data types in a generic way. They handle host CPU endianness while ensuring little-endian format on the QMI wire, as required by the protocol. Signed-off-by: Alexander Wilhelm --- drivers/soc/qcom/qmi_encdec.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index 7660a960fb45..cb43531a8b66 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -11,6 +11,19 @@ #include #include +#define QMI_ENCDEC_ENCODE_u8(x) (x) +#define QMI_ENCDEC_ENCODE_u16(x) __cpu_to_le16(x) +#define QMI_ENCDEC_ENCODE_u32(x) __cpu_to_le32(x) +#define QMI_ENCDEC_ENCODE_u64(x) __cpu_to_le64(x) + +#define QMI_ENCDEC_DECODE_u8(x) (x) +#define QMI_ENCDEC_DECODE_u16(x) __le16_to_cpu(x) +#define QMI_ENCDEC_DECODE_u32(x) __le32_to_cpu(x) +#define QMI_ENCDEC_DECODE_u64(x) __le64_to_cpu(x) + +#define QMI_ENCDEC_ENCODE(val, type) QMI_ENCDEC_ENCODE_##type(val) +#define QMI_ENCDEC_DECODE(val, type) QMI_ENCDEC_DECODE_##type(val) + #define QMI_ENCDEC_ENCODE_TLV(type, length, p_dst) do { \ *p_dst++ = type; \ *p_dst++ = ((u8)((length) & 0xFF)); \ -- 2.43.0 Extend the QMI byte encoding and decoding logic to support multiple basic data type sizes (u8, u16, u32, u64) using existing macros for generic access. Ensure correct handling of data sizes and proper byte order conversion on big-endian platforms by consistently applying these macros during encoding and decoding of basic elements. Fixes: 9b8a11e82615 ("soc: qcom: Introduce QMI encoder/decoder") Signed-off-by: Alexander Wilhelm --- drivers/soc/qcom/qmi_encdec.c | 50 ++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index cb43531a8b66..d8575e92dbf6 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -36,18 +36,16 @@ *p_length |= ((u8)*p_src) << 8; \ } while (0) -#define QMI_ENCDEC_ENCODE_N_BYTES(p_dst, p_src, size) \ -do { \ - memcpy(p_dst, p_src, size); \ - p_dst = (u8 *)p_dst + size; \ - p_src = (u8 *)p_src + size; \ +#define QMI_ENCDEC_ENCODE_N_BYTES(p_dst, p_src, type) do { \ + *(type *)(p_dst) = QMI_ENCDEC_ENCODE(*(type *)(p_src), type); \ + p_dst = (u8 *)(p_dst) + sizeof(type); \ + p_src = (u8 *)(p_src) + sizeof(type); \ } while (0) -#define QMI_ENCDEC_DECODE_N_BYTES(p_dst, p_src, size) \ -do { \ - memcpy(p_dst, p_src, size); \ - p_dst = (u8 *)p_dst + size; \ - p_src = (u8 *)p_src + size; \ +#define QMI_ENCDEC_DECODE_N_BYTES(p_dst, p_src, type) do { \ + *(type *)(p_dst) = QMI_ENCDEC_DECODE(*(type *)(p_src), type); \ + p_dst = (u8 *)(p_dst) + sizeof(type); \ + p_src = (u8 *)(p_src) + sizeof(type); \ } while (0) #define UPDATE_ENCODE_VARIABLES(temp_si, buf_dst, \ @@ -182,7 +180,21 @@ static int qmi_encode_basic_elem(void *buf_dst, const void *buf_src, u32 i, rc = 0; for (i = 0; i < elem_len; i++) { - QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, elem_size); + switch (elem_size) { + case sizeof(u8): + QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, u8); + break; + case sizeof(u16): + QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, u16); + break; + case sizeof(u32): + QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, u32); + break; + case sizeof(u64): + QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, u64); + break; + } + rc += elem_size; } @@ -465,7 +477,21 @@ static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src, u32 i, rc = 0; for (i = 0; i < elem_len; i++) { - QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size); + switch (elem_size) { + case sizeof(u8): + QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, u8); + break; + case sizeof(u16): + QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, u16); + break; + case sizeof(u32): + QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, u32); + break; + case sizeof(u64): + QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, u64); + break; + } + rc += elem_size; } -- 2.43.0 To ensure correct handling of endianness in the QMI subsystem, the QMI_DATA_LEN field used in host-side drivers remains in CPU-native byte order. Remove unnecessary endianness conversions, considering that QMI_DATA_LEN is always of type `u32` on the host. On the QMI wire interface, however, its representation is variable and may use either 1 or 2 bytes. Fixes: 3ced38da5f7d ("soc: qcom: QMI encoding/decoding for big endian") Signed-off-by: Alexander Wilhelm --- drivers/soc/qcom/qmi_encdec.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index d8575e92dbf6..01f7045e91dc 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -365,6 +365,7 @@ 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, sizeof(u32)); data_len_sz = temp_ei->elem_size == sizeof(u8) ? sizeof(u8) : sizeof(u16); /* Check to avoid out of range buffer access */ @@ -375,13 +376,11 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, return -ETOOSMALL; } if (data_len_sz == sizeof(u8)) { - val8 = *(u8 *)buf_src; - data_len_value = (u32)val8; + val8 = data_len_value; rc = qmi_encode_basic_elem(buf_dst, &val8, 1, data_len_sz); } else { - val16 = *(u16 *)buf_src; - data_len_value = (u32)le16_to_cpu(val16); + val16 = data_len_value; rc = qmi_encode_basic_elem(buf_dst, &val16, 1, data_len_sz); } @@ -664,7 +663,6 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct, int rc; u8 val8; u16 val16; - u32 val32; while (decoded_bytes < in_buf_len) { if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI) @@ -712,8 +710,7 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct, 1, data_len_sz); data_len_value = (u32)val16; } - val32 = cpu_to_le32(data_len_value); - memcpy(buf_dst, &val32, sizeof(u32)); + memcpy(buf_dst, &data_len_value, sizeof(u32)); temp_ei = temp_ei + 1; buf_dst = out_c_struct + temp_ei->offset; tlv_len -= data_len_sz; -- 2.43.0 Due to internal endianness handling within the QMI subsystem, all QMI requests and responses must now be provided in CPU byte order. Replace all QMI-related data types with CPU-endian types and add the necessary conversions to ensure correct interpretation across architectures. Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Alexander Wilhelm --- drivers/net/wireless/ath/ath12k/qmi.c | 24 ++++++++++++++++-------- drivers/net/wireless/ath/ath12k/qmi.h | 16 ++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 7c611a1fd6d0..36325e62aa24 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -3307,20 +3307,28 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) /* This is number of CE configs */ req->tgt_cfg_len = ab->qmi.ce_cfg.tgt_ce_len; for (pipe_num = 0; pipe_num < req->tgt_cfg_len ; pipe_num++) { - req->tgt_cfg[pipe_num].pipe_num = ce_cfg[pipe_num].pipenum; - req->tgt_cfg[pipe_num].pipe_dir = ce_cfg[pipe_num].pipedir; - req->tgt_cfg[pipe_num].nentries = ce_cfg[pipe_num].nentries; - req->tgt_cfg[pipe_num].nbytes_max = ce_cfg[pipe_num].nbytes_max; - req->tgt_cfg[pipe_num].flags = ce_cfg[pipe_num].flags; + req->tgt_cfg[pipe_num].pipe_num = + __le32_to_cpu(ce_cfg[pipe_num].pipenum); + req->tgt_cfg[pipe_num].pipe_dir = + __le32_to_cpu(ce_cfg[pipe_num].pipedir); + req->tgt_cfg[pipe_num].nentries = + __le32_to_cpu(ce_cfg[pipe_num].nentries); + req->tgt_cfg[pipe_num].nbytes_max = + __le32_to_cpu(ce_cfg[pipe_num].nbytes_max); + req->tgt_cfg[pipe_num].flags = + __le32_to_cpu(ce_cfg[pipe_num].flags); } req->svc_cfg_valid = 1; /* This is number of Service/CE configs */ req->svc_cfg_len = ab->qmi.ce_cfg.svc_to_ce_map_len; for (pipe_num = 0; pipe_num < req->svc_cfg_len; pipe_num++) { - req->svc_cfg[pipe_num].service_id = svc_cfg[pipe_num].service_id; - req->svc_cfg[pipe_num].pipe_dir = svc_cfg[pipe_num].pipedir; - req->svc_cfg[pipe_num].pipe_num = svc_cfg[pipe_num].pipenum; + req->svc_cfg[pipe_num].service_id = + __le32_to_cpu(svc_cfg[pipe_num].service_id); + req->svc_cfg[pipe_num].pipe_dir = + __le32_to_cpu(svc_cfg[pipe_num].pipedir); + req->svc_cfg[pipe_num].pipe_num = + __le32_to_cpu(svc_cfg[pipe_num].pipenum); } /* set shadow v3 configuration */ diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index abdaade3b542..4767d9a2e309 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -392,17 +392,17 @@ enum qmi_wlanfw_pipedir_enum_v01 { }; struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01 { - __le32 pipe_num; - __le32 pipe_dir; - __le32 nentries; - __le32 nbytes_max; - __le32 flags; + u32 pipe_num; + u32 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; }; struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01 { - __le32 service_id; - __le32 pipe_dir; - __le32 pipe_num; + u32 service_id; + u32 pipe_dir; + u32 pipe_num; }; struct qmi_wlanfw_shadow_reg_cfg_s_v01 { -- 2.43.0