Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH] wifi: ath: avoid repeated divisions in DFS PRI detector
@ 2026-07-01 17:04 frank0988
  2026-07-01 19:08 ` Jeff Johnson
  2026-07-02  3:52 ` [PATCH v2] " Chun-Cheng Chang
  0 siblings, 2 replies; 3+ messages in thread
From: frank0988 @ 2026-07-01 17:04 UTC (permalink / raw)
  To: Jeff Johnson; +Cc: linux-wireless, linux-kernel, frank0988

pde_get_multiple() is called repeatedly with the same PRI (Pulse
Repetition Interval) value while validating candidate and existing PRI
sequences.

Cache the reciprocal value for each sequence structure and leverage
reciprocal_divide() in the hot path. This keeps the existing matching
logic and tolerance checks intact while replacing expensive hardware
integer divisions with low-cost multiply-and-shift operations.

Testing with a userspace model of the same detector logic demonstrated
identical detector states and outputs across 100 verification traces.
To eliminate memory allocator noise, an isolated micro-benchmark using
a static object pool showed that the reciprocal variant reduces CPU
cycles by approximately 3.4%.

Signed-off-by: frank0988 <frank0988855428@gmail.com>
---
 drivers/net/wireless/ath/dfs_pri_detector.c | 14 +++++++++++---
 drivers/net/wireless/ath/dfs_pri_detector.h |  3 +++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c
index 388f9d1913bd..520fd1567a0b 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
@@ -16,6 +16,7 @@
 
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/reciprocal_div.h>
 
 #include "ath.h"
 #include "dfs_pattern_detector.h"
@@ -41,7 +42,9 @@ struct pulse_elem {
  * pde_get_multiple() - get number of multiples considering a given tolerance
  * Return value: factor if abs(val - factor*fraction) <= tolerance, 0 otherwise
  */
-static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
+static u32 pde_get_multiple(u32 val, u32 fraction,
+			    struct reciprocal_value fraction_recip,
+			    u32 tolerance)
 {
 	u32 remainder;
 	u32 factor;
@@ -56,8 +59,8 @@ static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
 		/* val and fraction are within tolerance */
 		return 1;
 
-	factor = val / fraction;
-	remainder = val % fraction;
+	factor = reciprocal_divide(val, fraction_recip);
+	remainder = val - factor * fraction;
 	if (remainder > tolerance) {
 		/* no exact match */
 		if ((fraction - remainder) <= tolerance)
@@ -247,6 +250,9 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
 		ps.last_ts = ts;
 		ps.pri = GET_PRI_TO_USE(pde->rs->pri_min,
 			pde->rs->pri_max, ts - p->ts);
+		ps.pri_recip = (struct reciprocal_value){};
+		if (ps.pri)
+			ps.pri_recip = reciprocal_value(ps.pri);
 		ps.dur = ps.pri * (pde->rs->ppb - 1)
 				+ 2 * pde->rs->max_pri_tolerance;
 
@@ -261,6 +267,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
 				break;
 			/* check if pulse match (multi)PRI */
 			factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri,
+						  ps.pri_recip,
 						  pde->rs->max_pri_tolerance);
 			if (factor > 0) {
 				ps.count++;
@@ -318,6 +325,7 @@ pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts)
 
 		delta_ts = ts - ps->last_ts;
 		factor = pde_get_multiple(delta_ts, ps->pri,
+					  ps->pri_recip,
 					  pde->rs->max_pri_tolerance);
 		if (factor > 0) {
 			ps->last_ts = ts;
diff --git a/drivers/net/wireless/ath/dfs_pri_detector.h b/drivers/net/wireless/ath/dfs_pri_detector.h
index 86339f2b4d3a..c519466cff8b 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.h
+++ b/drivers/net/wireless/ath/dfs_pri_detector.h
@@ -18,6 +18,7 @@
 #define DFS_PRI_DETECTOR_H
 
 #include <linux/list.h>
+#include <linux/reciprocal_div.h>
 
 extern struct ath_dfs_pool_stats global_dfs_pool_stats;
 
@@ -25,6 +26,7 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats;
  * struct pri_sequence - sequence of pulses matching one PRI
  * @head: list_head
  * @pri: pulse repetition interval (PRI) in usecs
+ * @pri_recip: cached reciprocal value for PRI divisions
  * @dur: duration of sequence in usecs
  * @count: number of pulses in this sequence
  * @count_falses: number of not matching pulses in this sequence
@@ -35,6 +37,7 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats;
 struct pri_sequence {
 	struct list_head head;
 	u32 pri;
+	struct reciprocal_value pri_recip;
 	u32 dur;
 	u32 count;
 	u32 count_falses;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] wifi: ath: avoid repeated divisions in DFS PRI detector
  2026-07-01 17:04 [PATCH] wifi: ath: avoid repeated divisions in DFS PRI detector frank0988
@ 2026-07-01 19:08 ` Jeff Johnson
  2026-07-02  3:52 ` [PATCH v2] " Chun-Cheng Chang
  1 sibling, 0 replies; 3+ messages in thread
From: Jeff Johnson @ 2026-07-01 19:08 UTC (permalink / raw)
  To: frank0988, Jeff Johnson; +Cc: linux-wireless, linux-kernel

On 7/1/2026 10:04 AM, frank0988 wrote:
> pde_get_multiple() is called repeatedly with the same PRI (Pulse
> Repetition Interval) value while validating candidate and existing PRI
> sequences.
> 
> Cache the reciprocal value for each sequence structure and leverage
> reciprocal_divide() in the hot path. This keeps the existing matching
> logic and tolerance checks intact while replacing expensive hardware
> integer divisions with low-cost multiply-and-shift operations.
> 
> Testing with a userspace model of the same detector logic demonstrated
> identical detector states and outputs across 100 verification traces.
> To eliminate memory allocator noise, an isolated micro-benchmark using
> a static object pool showed that the reciprocal variant reduces CPU
> cycles by approximately 3.4%.
> 
> Signed-off-by: frank0988 <frank0988855428@gmail.com>

You must sign off with a "known identity"

https://www.kernel.org/doc/html/latest/process/submitting-patches.html#developer-s-certificate-of-origin-1-1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2] wifi: ath: avoid repeated divisions in DFS PRI detector
  2026-07-01 17:04 [PATCH] wifi: ath: avoid repeated divisions in DFS PRI detector frank0988
  2026-07-01 19:08 ` Jeff Johnson
@ 2026-07-02  3:52 ` Chun-Cheng Chang
  1 sibling, 0 replies; 3+ messages in thread
From: Chun-Cheng Chang @ 2026-07-02  3:52 UTC (permalink / raw)
  To: Jeff Johnson; +Cc: linux-wireless, linux-kernel, Chun-Cheng Chang

pde_get_multiple() is called repeatedly with the same PRI (Pulse
Repetition Interval) value while validating candidate and existing PRI
sequences.

Cache the reciprocal value for each sequence structure and leverage
reciprocal_divide() in the hot path. This keeps the existing matching
logic and tolerance checks intact while replacing expensive hardware
integer divisions with low-cost multiply-and-shift operations.

Testing with a userspace model of the same detector logic demonstrated
identical detector states and outputs across 100 verification traces.
To eliminate memory allocator noise, an isolated micro-benchmark using
a static object pool showed that the reciprocal variant reduces CPU
cycles by approximately 3.4%.

Signed-off-by: Chun-Cheng Chang <frank0988855428@gmail.com>
---
Changes in v2:
- Use a known identity for the author and Signed-off-by tags.

 drivers/net/wireless/ath/dfs_pri_detector.c | 14 +++++++++++---
 drivers/net/wireless/ath/dfs_pri_detector.h |  3 +++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c
index 388f9d1913bd..520fd1567a0b 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
@@ -16,6 +16,7 @@
 
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/reciprocal_div.h>
 
 #include "ath.h"
 #include "dfs_pattern_detector.h"
@@ -41,7 +42,9 @@ struct pulse_elem {
  * pde_get_multiple() - get number of multiples considering a given tolerance
  * Return value: factor if abs(val - factor*fraction) <= tolerance, 0 otherwise
  */
-static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
+static u32 pde_get_multiple(u32 val, u32 fraction,
+			    struct reciprocal_value fraction_recip,
+			    u32 tolerance)
 {
 	u32 remainder;
 	u32 factor;
@@ -56,8 +59,8 @@ static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
 		/* val and fraction are within tolerance */
 		return 1;
 
-	factor = val / fraction;
-	remainder = val % fraction;
+	factor = reciprocal_divide(val, fraction_recip);
+	remainder = val - factor * fraction;
 	if (remainder > tolerance) {
 		/* no exact match */
 		if ((fraction - remainder) <= tolerance)
@@ -247,6 +250,9 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
 		ps.last_ts = ts;
 		ps.pri = GET_PRI_TO_USE(pde->rs->pri_min,
 			pde->rs->pri_max, ts - p->ts);
+		ps.pri_recip = (struct reciprocal_value){};
+		if (ps.pri)
+			ps.pri_recip = reciprocal_value(ps.pri);
 		ps.dur = ps.pri * (pde->rs->ppb - 1)
 				+ 2 * pde->rs->max_pri_tolerance;
 
@@ -261,6 +267,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
 				break;
 			/* check if pulse match (multi)PRI */
 			factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri,
+						  ps.pri_recip,
 						  pde->rs->max_pri_tolerance);
 			if (factor > 0) {
 				ps.count++;
@@ -318,6 +325,7 @@ pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts)
 
 		delta_ts = ts - ps->last_ts;
 		factor = pde_get_multiple(delta_ts, ps->pri,
+					  ps->pri_recip,
 					  pde->rs->max_pri_tolerance);
 		if (factor > 0) {
 			ps->last_ts = ts;
diff --git a/drivers/net/wireless/ath/dfs_pri_detector.h b/drivers/net/wireless/ath/dfs_pri_detector.h
index 86339f2b4d3a..c519466cff8b 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.h
+++ b/drivers/net/wireless/ath/dfs_pri_detector.h
@@ -18,6 +18,7 @@
 #define DFS_PRI_DETECTOR_H
 
 #include <linux/list.h>
+#include <linux/reciprocal_div.h>
 
 extern struct ath_dfs_pool_stats global_dfs_pool_stats;
 
@@ -25,6 +26,7 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats;
  * struct pri_sequence - sequence of pulses matching one PRI
  * @head: list_head
  * @pri: pulse repetition interval (PRI) in usecs
+ * @pri_recip: cached reciprocal value for PRI divisions
  * @dur: duration of sequence in usecs
  * @count: number of pulses in this sequence
  * @count_falses: number of not matching pulses in this sequence
@@ -35,6 +37,7 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats;
 struct pri_sequence {
 	struct list_head head;
 	u32 pri;
+	struct reciprocal_value pri_recip;
 	u32 dur;
 	u32 count;
 	u32 count_falses;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-02  3:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01 17:04 [PATCH] wifi: ath: avoid repeated divisions in DFS PRI detector frank0988
2026-07-01 19:08 ` Jeff Johnson
2026-07-02  3:52 ` [PATCH v2] " Chun-Cheng Chang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox