Skip to contentSkip to conversation

wifi: rtw88: rtw8822c: refactor DAC IQ calibration to s32

PATCH Superseded Arsenii Pashchenko 2 participants 8 messages Aug 15 – Aug 25 Realtek wireless driver (rtw88)

v6 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v6 cover wifi: rtw88: rtw8822c: refactor DAC IQ calibration to s32

This series refactors the Digital-to-Analog Converter (DAC) IQ calibration routines in the rtw8822c driver, eliminating legacy unsigned workarounds in favor of native signed math.

The original code heavily relies on unsigned 32-bit math mapped over a 10-bit circular hardware register scale centered around 0x200. This introduces complex nested boundary checks, custom bubble sort rules, and custom min/max tracking helpers.

By migrating the temporary stack arrays and signatures to signed s32 and utilizing the kernel's FIELD_GET_SIGNED() API, the coordination system is linearized. This allows the removal of internal custom helpers, collapses unsigned wrap-around logic into standard linear operations, and enables the drop-in integration of the kernel's native heapsort library.

The series is broken down as follows:
Patch 1: Introduces GENMASK constants for register fields and replaces
manual bit shifts with standard FIELD_GET() macros.
Patch 2: Converts stack buffers and function signatures to signed s32,
switches sampling to FIELD_GET_SIGNED(), and straightens out the validation windows and hardware offset mapping.
Patch 3: Replaces custom bubble sort logic and unused helpers with a direct
call to the kernel's native sort() library using a safe, overflow-proof relational comparator.

AI Disclosure:
An AI assistant was used for source code analysis and conceptual consultation regarding the signed math transformation. All code modifications, final implementations, and refactoring steps were written, reviewed, and verified manually by the author.

Testing:
- Note: The author does not possess the actual rtw8822c hardware. Actual throughput and runtime performance verification is left to the vendor or community testers.
- Every patch in the series was verified with scripts/checkpatch.pl and yielded 0 errors and 0 warnings.
- Each patch was sequentially built (bisected and compiled) to ensure there are no compiler warnings, pointer type mismatches, or broken builds at any intermediate step.
---
Changes in v6:
- Noted lack of physical hardware for throughput testing in the cover letter.
- Fixed a typo in the subject prefix of patch 2 ("fi:" -> "wifi:").
- Optimized the min/max search loop in rtw8822c_dac_cal_iq_search() by starting from index 1 since index 0 is used for initialization.
- Reverted an accidental change that broke the compilation.

Changes in v5:
- Fixed a typo in the subject prefix of patch 2 ("fi:" -> "wifi:").

Changes in v4:
- Flattened the series from 4 to 3 patches to avoid intermediate broken states where sign-extended variables interacted with unsigned check logic, ensuring 100% clean bisectability.
- Leveraged FIELD_GET_SIGNED() for modern, native handling of 10-bit signed hardware entries as suggested during review.
- Shifted definition of register field masks from the .c file into the shared rtw8822c.h header file according to subsystem design patterns.
- Stripped out custom rtw8822c_dac_iq_sort() wrapper, invoking the kernel sort() library directly inside the main calibration search loop.

Changes in v3:
- Corrected the subject prefix target tree from wireless-next to rtw-next as requested by the maintainer.

Changes in v2:
- Fixed missing target tree name in the subject prefix (switched to wireless-next).

Arsenii Pashchenko (3):
wifi: rtw88: rtw8822c: Use bitfield macros for DAC IQ sampling
wifi: rtw88: rtw8822c: Convert DAC IQ calibration path to signed math
wifi: rtw88: rtw8822c: Replace custom DAC IQ sorting with kernel sort

 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 155 ++++++------------
 drivers/net/wireless/realtek/rtw88/rtw8822c.h |   3 +
 2 files changed, 49 insertions(+), 109 deletions(-)
Signature · 1 line
2.55.0
#1 lore raw

PATCH v6 1/3 wifi: rtw88: rtw8822c: Use bitfield macros for DAC IQ sampling

Define proper GENMASK constants for the In-phase (I) and Quadrature
(Q) components of the DAC IQ data register in the header file. Replace manual bit shifting, masking, and rtw_read32_mask() with standard rtw_read32() and the FIELD_GET() macro to improve code readability.

---
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 18 +++++++++---------
 drivers/net/wireless/realtek/rtw88/rtw8822c.h |  3 +++
 2 files changed, 12 insertions(+), 9 deletions(-)
drivers/net/wireless/realtek/rtw88/rtw8822c.c +9 -9
index 244c80264..137544649 100644
@@ -291,9 +291,9 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
 
 	while (i < DACK_SN_8822C && cnt < 10000) {
 		cnt++;
-		temp = rtw_read32_mask(rtwdev, 0x2dbc, 0x3fffff);
-		iv[i] = (temp & 0x3ff000) >> 12;
-		qv[i] = temp & 0x3ff;
+		temp = rtw_read32(rtwdev, 0x2dbc);
+		iv[i] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
+		qv[i] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
 
 		if (rtw8822c_dac_iq_check(rtwdev, iv[i]) &&
 		    rtw8822c_dac_iq_check(rtwdev, qv[i]))
@@ -344,12 +344,12 @@ static void rtw8822c_dac_cal_iq_search(struct rtw_dev *rtwdev,
 		rtw8822c_dac_iq_sort(rtwdev, iv, qv);
 
 		if (i_delta > 5 || q_delta > 5) {
-			temp = rtw_read32_mask(rtwdev, 0x2dbc, 0x3fffff);
-			iv[0] = (temp & 0x3ff000) >> 12;
-			qv[0] = temp & 0x3ff;
-			temp = rtw_read32_mask(rtwdev, 0x2dbc, 0x3fffff);
-			iv[DACK_SN_8822C - 1] = (temp & 0x3ff000) >> 12;
-			qv[DACK_SN_8822C - 1] = temp & 0x3ff;
+			temp = rtw_read32(rtwdev, 0x2dbc);
+			iv[0] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
+			qv[0] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+			temp = rtw_read32(rtwdev, 0x2dbc);
+			iv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
+			qv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
 		} else {
 			break;
 		}
drivers/net/wireless/realtek/rtw88/rtw8822c.h +3 -0
index fc62b67a1..7bea99614 100644
@@ -141,6 +141,9 @@ const struct rtw_table name ## _tbl = {			\
 #define DACK_RF_8822C		1
 #define DACK_SN_8822C		100
 
+#define RTW8822C_DAC_IV_MASK GENMASK(21, 12)
+#define RTW8822C_DAC_QV_MASK GENMASK(9, 0)
+
 /* phy status page0 */
 #define GET_PHY_STAT_P0_PWDB_A(phy_stat)                                       \
 	le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
Signature · 1 line
2.55.0
maintainer Acked-by on v6 1/3
#2 lore raw

RE: [PATCH rtw-next v6 1/3] wifi: rtw88: rtw8822c: Use bitfield macros for DAC IQ sampling

Quoted 7 lines · Arsenii Pashchenko

Define proper GENMASK constants for the In-phase (I) and Quadrature
(Q) components of the DAC IQ data register in the header file. Replace manual bit shifting, masking, and rtw_read32_mask() with standard rtw_read32() and the FIELD_GET() macro to improve code readability.

#3 lore raw

PATCH v6 2/3 wifi: rtw88: rtw8822c: Convert DAC IQ calibration path to signed math

In reply to Arsenii Pashchenko

Convert the temporary stack arrays 'iv' and 'qv' from u32 to s32. Update all internal function signatures to accept s32 pointers and handle signed values natively.

Use sign_extend32() combined with FIELD_GET() to properly interpret the 10-bit hardware values as signed integers. This allows flattening the complex nested unsigned boundary conditions in rtw8822c_dac_iq_check() into a simple amplitude boundary check. Ensure rtw8822c_dac_iq_offset() properly maps the signed average back to a 10-bit unsigned format expected by the hardware registers.

---
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 135 ++++++------------
 1 file changed, 40 insertions(+), 95 deletions(-)
drivers/net/wireless/realtek/rtw88/rtw8822c.c +40 -95
index 137544649..a10e87d6e 100644
@@ -153,49 +153,14 @@ static void rtw8822c_dac_restore_reg(struct rtw_dev *rtwdev,
 	}
 }
 
-static void rtw8822c_rf_minmax_cmp(struct rtw_dev *rtwdev, u32 value,
-				   u32 *min, u32 *max)
+static void __rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *v1, s32 *v2)
 {
-	if (value >= 0x200) {
-		if (*min >= 0x200) {
-			if (*min > value)
-				*min = value;
-		} else {
-			*min = value;
-		}
-		if (*max >= 0x200) {
-			if (*max < value)
-				*max = value;
-		}
-	} else {
-		if (*min < 0x200) {
-			if (*min > value)
-				*min = value;
-		}
-
-		if (*max  >= 0x200) {
-			*max = value;
-		} else {
-			if (*max < value)
-				*max = value;
-		}
-	}
-}
-
-static void __rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *v1, u32 *v2)
-{
-	if (*v1 >= 0x200 && *v2 >= 0x200) {
-		if (*v1 > *v2)
-			swap(*v1, *v2);
-	} else if (*v1 < 0x200 && *v2 < 0x200) {
-		if (*v1 > *v2)
-			swap(*v1, *v2);
-	} else if (*v1 < 0x200 && *v2 >= 0x200) {
+	if (*v1 > *v2)
 		swap(*v1, *v2);
-	}
+
 }
 
-static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
+static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *iv, s32 *qv)
 {
 	u32 i, j;
 
@@ -207,30 +172,16 @@ static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
 	}
 }
 
-static void rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, u32 *vec, u32 *val)
+static u32 rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, s32 *vec)
 {
-	u32 p, m, t, i;
+	s32 sum = 0;
 
-	m = 0;
-	p = 0;
-	for (i = 10; i < DACK_SN_8822C - 10; i++) {
-		if (vec[i] > 0x200)
-			m = (0x400 - vec[i]) + m;
-		else
-			p = vec[i] + p;
-	}
+	for (u32 i = 10; i < DACK_SN_8822C - 10; i++)
+		sum += vec[i];
 
-	if (p > m) {
-		t = p - m;
-		t = t / (DACK_SN_8822C - 20);
-	} else {
-		t = m - p;
-		t = t / (DACK_SN_8822C - 20);
-		if (t != 0x0)
-			t = 0x400 - t;
-	}
+	s32 avg = sum / (DACK_SN_8822C - 20);
 
-	*val = t;
+	return avg >= 0 ? (u32)avg : (u32)(0x400 + avg);
 }
 
 static u32 rtw8822c_get_path_write_addr(u8 path)
@@ -271,20 +222,18 @@ static u32 rtw8822c_get_path_read_addr(u8 path)
 	return base_addr;
 }
 
-static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, u32 value)
+static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, s32 value)
 {
-	bool ret = true;
 
-	if ((value >= 0x200 && (0x400 - value) > 0x64) ||
-	    (value < 0x200 && value > 0x64)) {
-		ret = false;
+	if (value > 100 || value < -100) {
 		rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] Error overflow\n");
+		return false;
 	}
 
-	return ret;
+	return true;
 }
 
-static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
+static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, s32 *iv, s32 *qv)
 {
 	u32 temp;
 	int i = 0, cnt = 0;
@@ -292,8 +241,8 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
 	while (i < DACK_SN_8822C && cnt < 10000) {
 		cnt++;
 		temp = rtw_read32(rtwdev, 0x2dbc);
-		iv[i] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
-		qv[i] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+		iv[i] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+		qv[i] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
 
 		if (rtw8822c_dac_iq_check(rtwdev, iv[i]) &&
 		    rtw8822c_dac_iq_check(rtwdev, qv[i]))
@@ -302,67 +251,63 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
 }
 
 static void rtw8822c_dac_cal_iq_search(struct rtw_dev *rtwdev,
-				       u32 *iv, u32 *qv,
+				       s32 *iv, s32 *qv,
 				       u32 *i_value, u32 *q_value)
 {
-	u32 i_max = 0, q_max = 0, i_min = 0, q_min = 0;
+	s32 i_max = 0, q_max = 0, i_min = 0, q_min = 0;
 	u32 i_delta, q_delta;
 	u32 temp;
-	int i, cnt = 0;
+	u32 i, cnt = 0;
 
 	do {
 		i_min = iv[0];
 		i_max = iv[0];
 		q_min = qv[0];
 		q_max = qv[0];
-		for (i = 0; i < DACK_SN_8822C; i++) {
-			rtw8822c_rf_minmax_cmp(rtwdev, iv[i], &i_min, &i_max);
-			rtw8822c_rf_minmax_cmp(rtwdev, qv[i], &q_min, &q_max);
+		for (i = 1; i < DACK_SN_8822C; i++) {
+			if (iv[i] < i_min)
+				i_min = iv[i];
+			if (iv[i] > i_max)
+				i_max = iv[i];
+			if (qv[i] < q_min)
+				q_min = qv[i];
+			if (qv[i] > q_max)
+				q_max = qv[i];
 		}
 
-		if (i_max < 0x200 && i_min < 0x200)
-			i_delta = i_max - i_min;
-		else if (i_max >= 0x200 && i_min >= 0x200)
-			i_delta = i_max - i_min;
-		else
-			i_delta = i_max + (0x400 - i_min);
+		i_delta = i_max - i_min;
+		q_delta = q_max - q_min;
 
-		if (q_max < 0x200 && q_min < 0x200)
-			q_delta = q_max - q_min;
-		else if (q_max >= 0x200 && q_min >= 0x200)
-			q_delta = q_max - q_min;
-		else
-			q_delta = q_max + (0x400 - q_min);
 
 		rtw_dbg(rtwdev, RTW_DBG_RFK,
-			"[DACK] i: min=0x%08x, max=0x%08x, delta=0x%08x\n",
+			"[DACK] i: min=%d, max=%d, delta=%d\n",
 			i_min, i_max, i_delta);
 		rtw_dbg(rtwdev, RTW_DBG_RFK,
-			"[DACK] q: min=0x%08x, max=0x%08x, delta=0x%08x\n",
+			"[DACK] q: min=%d, max=%d, delta=%d",
 			q_min, q_max, q_delta);
 
 		rtw8822c_dac_iq_sort(rtwdev, iv, qv);
 
 		if (i_delta > 5 || q_delta > 5) {
 			temp = rtw_read32(rtwdev, 0x2dbc);
-			iv[0] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
-			qv[0] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+			iv[0] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+			qv[0] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
 			temp = rtw_read32(rtwdev, 0x2dbc);
-			iv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
-			qv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+			iv[DACK_SN_8822C - 1] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+			qv[DACK_SN_8822C - 1] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
 		} else {
 			break;
 		}
 	} while (cnt++ < 100);
 
-	rtw8822c_dac_iq_offset(rtwdev, iv, i_value);
-	rtw8822c_dac_iq_offset(rtwdev, qv, q_value);
+	*i_value = rtw8822c_dac_iq_offset(rtwdev, iv);
+	*q_value = rtw8822c_dac_iq_offset(rtwdev, qv);
 }
 
 static void rtw8822c_dac_cal_rf_mode(struct rtw_dev *rtwdev,
 				     u32 *i_value, u32 *q_value)
 {
-	u32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
+	s32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
 	u32 rf_a, rf_b;
 
 	rf_a = rtw_read_rf(rtwdev, RF_PATH_A, 0x0, RFREG_MASK);
Signature · 1 line
2.55.0
maintainer
#4 lore raw

RE: [PATCH rtw-next v6 2/3] wifi: rtw88: rtw8822c: Convert DAC IQ calibration path to signed math

Quoted 6 lines · Arsenii Pashchenko

Convert the temporary stack arrays 'iv' and 'qv' from u32 to s32. Update all internal function signatures to accept s32 pointers and handle signed values natively.

Use sign_extend32() combined with FIELD_GET() to properly interpret the 10-bit hardware values as signed integers.

Forgot to update commit message as FIELD_GET_SIGNED()...

Quoted 8 lines

This allows flattening
the complex nested unsigned boundary conditions in rtw8822c_dac_iq_check() into a simple amplitude boundary check. Ensure rtw8822c_dac_iq_offset() properly maps the signed average back to a 10-bit unsigned format expected by the hardware registers.

---

[...]

Quoted 21 lines
drivers/net/wireless/realtek/rtw88/rtw8822c.c +4 -10
@@ -207,30 +172,16 @@ static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
        }
 }
 
-static void rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, u32 *vec, u32 *val)
+static u32 rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, s32 *vec)
 {
-       u32 p, m, t, i;
+       s32 sum = 0;
 
-       m = 0;
-       p = 0;
-       for (i = 10; i < DACK_SN_8822C - 10; i++) {
-               if (vec[i] > 0x200)
-                       m = (0x400 - vec[i]) + m;
-               else
-                       p = vec[i] + p;
-       }
+       for (u32 i = 10; i < DACK_SN_8822C - 10; i++)
+               sum += vec[i];
 

drivers/net/wireless/realtek/rtw88/rtw8822c.c static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *iv, u32 *qv) · line 182

Quoted 10 lines
drivers/net/wireless/realtek/rtw88/rtw8822c.c +1 -9
-       if (p > m) {
-               t = p - m;
-               t = t / (DACK_SN_8822C - 20);
-       } else {
-               t = m - p;
-               t = t / (DACK_SN_8822C - 20);
-               if (t != 0x0)
-                       t = 0x400 - t;
-       }
+       s32 avg = sum / (DACK_SN_8822C - 20);

No declaration in the middle.

drivers/net/wireless/realtek/rtw88/rtw8822c.c static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *iv, u32 *qv) · line 184

Quoted 3 lines
drivers/net/wireless/realtek/rtw88/rtw8822c.c +1 -1
-       *val = t;
+       return avg >= 0 ? (u32)avg : (u32)(0x400 + avg);

Maybe, we can give an example to understand easier, like

avg = -1, return 0x3FF. (signed 10 bits value)

Quoted 44 lines
drivers/net/wireless/realtek/rtw88/rtw8822c.c +7 -9
 }
 
 static u32 rtw8822c_get_path_write_addr(u8 path)
@@ -271,20 +222,18 @@ static u32 rtw8822c_get_path_read_addr(u8 path)
        return base_addr;
 }
 
-static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, u32 value)
+static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, s32 value)
 {
-       bool ret = true;
 
-       if ((value >= 0x200 && (0x400 - value) > 0x64) ||
-           (value < 0x200 && value > 0x64)) {
-               ret = false;
+       if (value > 100 || value < -100) {
                rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] Error overflow\n");
+               return false;
        }
 
-       return ret;
+       return true;
 }
 
-static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
+static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, s32 *iv, s32 *qv)
 {
        u32 temp;
        int i = 0, cnt = 0;
@@ -292,8 +241,8 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
        while (i < DACK_SN_8822C && cnt < 10000) {
                cnt++;
                temp = rtw_read32(rtwdev, 0x2dbc);
-               iv[i] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
-               qv[i] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+               iv[i] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+               qv[i] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
 
                if (rtw8822c_dac_iq_check(rtwdev, iv[i]) &&
                    rtw8822c_dac_iq_check(rtwdev, qv[i]))
@@ -302,67 +251,63 @@ static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv)
 }
 
 static void rtw8822c_dac_cal_iq_search(struct rtw_dev *rtwdev,

drivers/net/wireless/realtek/rtw88/rtw8822c.c static void rtw8822c_dac_cal_iq_sample(struct rtw_dev *rtwdev, u32 *iv, u32 *qv) · line 260

Quoted 10 lines
drivers/net/wireless/realtek/rtw88/rtw8822c.c +3 -3
-                                      u32 *iv, u32 *qv,
+                                      s32 *iv, s32 *qv,
                                       u32 *i_value, u32 *q_value)
 {
-       u32 i_max = 0, q_max = 0, i_min = 0, q_min = 0;
+       s32 i_max = 0, q_max = 0, i_min = 0, q_min = 0;
        u32 i_delta, q_delta;
        u32 temp;
-       int i, cnt = 0;
+       u32 i, cnt = 0;

Why did you need changing 'int' to 'u32'?

Quoted 79 lines
drivers/net/wireless/realtek/rtw88/rtw8822c.c +20 -25
        do {
                i_min = iv[0];
                i_max = iv[0];
                q_min = qv[0];
                q_max = qv[0];
-               for (i = 0; i < DACK_SN_8822C; i++) {
-                       rtw8822c_rf_minmax_cmp(rtwdev, iv[i], &i_min, &i_max);
-                       rtw8822c_rf_minmax_cmp(rtwdev, qv[i], &q_min, &q_max);
+               for (i = 1; i < DACK_SN_8822C; i++) {
+                       if (iv[i] < i_min)
+                               i_min = iv[i];
+                       if (iv[i] > i_max)
+                               i_max = iv[i];
+                       if (qv[i] < q_min)
+                               q_min = qv[i];
+                       if (qv[i] > q_max)
+                               q_max = qv[i];
                }
 
-               if (i_max < 0x200 && i_min < 0x200)
-                       i_delta = i_max - i_min;
-               else if (i_max >= 0x200 && i_min >= 0x200)
-                       i_delta = i_max - i_min;
-               else
-                       i_delta = i_max + (0x400 - i_min);
+               i_delta = i_max - i_min;
+               q_delta = q_max - q_min;
 
-               if (q_max < 0x200 && q_min < 0x200)
-                       q_delta = q_max - q_min;
-               else if (q_max >= 0x200 && q_min >= 0x200)
-                       q_delta = q_max - q_min;
-               else
-                       q_delta = q_max + (0x400 - q_min);
 
                rtw_dbg(rtwdev, RTW_DBG_RFK,
-                       "[DACK] i: min=0x%08x, max=0x%08x, delta=0x%08x\n",
+                       "[DACK] i: min=%d, max=%d, delta=%d\n",
                        i_min, i_max, i_delta);
                rtw_dbg(rtwdev, RTW_DBG_RFK,
-                       "[DACK] q: min=0x%08x, max=0x%08x, delta=0x%08x\n",
+                       "[DACK] q: min=%d, max=%d, delta=%d",
                        q_min, q_max, q_delta);
 
                rtw8822c_dac_iq_sort(rtwdev, iv, qv);
 
                if (i_delta > 5 || q_delta > 5) {
                        temp = rtw_read32(rtwdev, 0x2dbc);
-                       iv[0] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
-                       qv[0] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+                       iv[0] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+                       qv[0] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
                        temp = rtw_read32(rtwdev, 0x2dbc);
-                       iv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_IV_MASK, temp);
-                       qv[DACK_SN_8822C - 1] = FIELD_GET(RTW8822C_DAC_QV_MASK, temp);
+                       iv[DACK_SN_8822C - 1] = FIELD_GET_SIGNED(RTW8822C_DAC_IV_MASK, temp);
+                       qv[DACK_SN_8822C - 1] = FIELD_GET_SIGNED(RTW8822C_DAC_QV_MASK, temp);
                } else {
                        break;
                }
        } while (cnt++ < 100);
 
-       rtw8822c_dac_iq_offset(rtwdev, iv, i_value);
-       rtw8822c_dac_iq_offset(rtwdev, qv, q_value);
+       *i_value = rtw8822c_dac_iq_offset(rtwdev, iv);
+       *q_value = rtw8822c_dac_iq_offset(rtwdev, qv);
 }
 
 static void rtw8822c_dac_cal_rf_mode(struct rtw_dev *rtwdev,
                                     u32 *i_value, u32 *q_value)
 {
-       u32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
+       s32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
        u32 rf_a, rf_b;
 
        rf_a = rtw_read_rf(rtwdev, RF_PATH_A, 0x0, RFREG_MASK);
--

2.55.0

#5 lore raw

PATCH v6 3/3 wifi: rtw88: rtw8822c: Replace custom DAC IQ sorting with kernel sort

In reply to Arsenii Pashchenko

Replace the custom, nested bubble-sort logic in the calibration loop with direct calls to the kernel's optimized heapsort implementation inside rtw8822c_dac_cal_iq_search().

Implement a safe, overflow-proof s32 comparator using the subtraction of relationals pattern. Since the input values are already properly sign-extended into signed arrays, the custom circular index sorting rules and helper functions completely disappear, reducing lines of code.

---
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 22 ++++++-------------
 1 file changed, 7 insertions(+), 15 deletions(-)
drivers/net/wireless/realtek/rtw88/rtw8822c.c +7 -15
index a10e87d6e..8a6a8bbf9 100644
@@ -3,6 +3,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/sort.h>
 #include "main.h"
 #include "coex.h"
 #include "fw.h"
@@ -153,24 +154,14 @@ static void rtw8822c_dac_restore_reg(struct rtw_dev *rtwdev,
 	}
 }
 
-static void __rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *v1, s32 *v2)
+static int rtw8822c_dac_iq_cmp_s32(const void *a, const void *b)
 {
-	if (*v1 > *v2)
-		swap(*v1, *v2);
+	s32 val_a = *(const s32 *)a;
+	s32 val_b = *(const s32 *)b;
 
+	return (val_a > val_b) - (val_a < val_b);
 }
 
-static void rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, s32 *iv, s32 *qv)
-{
-	u32 i, j;
-
-	for (i = 0; i < DACK_SN_8822C - 1; i++) {
-		for (j = 0; j < (DACK_SN_8822C - 1 - i) ; j++) {
-			__rtw8822c_dac_iq_sort(rtwdev, &iv[j], &iv[j + 1]);
-			__rtw8822c_dac_iq_sort(rtwdev, &qv[j], &qv[j + 1]);
-		}
-	}
-}
 
 static u32 rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, s32 *vec)
 {
@@ -286,7 +277,8 @@ static void rtw8822c_dac_cal_iq_search(struct rtw_dev *rtwdev,
 			"[DACK] q: min=%d, max=%d, delta=%d",
 			q_min, q_max, q_delta);
 
-		rtw8822c_dac_iq_sort(rtwdev, iv, qv);
+		sort(iv, DACK_SN_8822C, sizeof(s32), rtw8822c_dac_iq_cmp_s32, NULL);
+		sort(qv, DACK_SN_8822C, sizeof(s32), rtw8822c_dac_iq_cmp_s32, NULL);
 
 		if (i_delta > 5 || q_delta > 5) {
 			temp = rtw_read32(rtwdev, 0x2dbc);
Signature · 1 line
2.55.0
maintainer Acked-by on v6 3/3
#6 lore raw

RE: [PATCH rtw-next v6 3/3] wifi: rtw88: rtw8822c: Replace custom DAC IQ sorting with kernel sort

Quoted 10 lines · Arsenii Pashchenko

Replace the custom, nested bubble-sort logic in the calibration loop with direct calls to the kernel's optimized heapsort implementation inside rtw8822c_dac_cal_iq_search().

Implement a safe, overflow-proof s32 comparator using the subtraction of relationals pattern. Since the input values are already properly sign-extended into signed arrays, the custom circular index sorting rules and helper functions completely disappear, reducing lines of code.

maintainer
#7 lore raw
In reply to Arsenii Pashchenko
Quoted 4 lines · Arsenii Pashchenko

Testing:
- Note: The author does not possess the actual rtw8822c hardware. Actual throughput and runtime performance verification is left to the vendor or community testers.

As I mentioned earlier, we need testing on real hardware, and then I can merge it. But you can continue to update your patchset.

Ping-Ke