[PATCH v2] wifi: ath: avoid repeated divisions in DFS PRI detector

From: Chun-Cheng Chang

Date: Wed Jul 01 2026 - 23:52:51 EST


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@xxxxxxxxx>
---
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