Skip to content

Commit 7ceba45

Browse files
benzeajmberg-intel
authored andcommitted
wifi: cfg80211: add an hrtimer based delayed work item
The normal timer mechanism assume that timeout further in the future need a lower accuracy. As an example, the granularity for a timer scheduled 4096 ms in the future on a 1000 Hz system is already 512 ms. This granularity is perfectly sufficient for e.g. timeouts, but there are other types of events that will happen at a future point in time and require a higher accuracy. Add a new wiphy_hrtimer_work type that uses an hrtimer internally. The API is almost identical to the existing wiphy_delayed_work and it can be used as a drop-in replacement after minor adjustments. The work will be scheduled relative to the current time with a slack of 1 millisecond. CC: stable@vger.kernel.org # 6.4+ Signed-off-by: Benjamin Berg <benjamin.berg@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20251028125710.7f13a2adc5eb.I01b5af0363869864b0580d9c2a1770bafab69566@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 3b8694e commit 7ceba45

3 files changed

Lines changed: 155 additions & 0 deletions

File tree

include/net/cfg80211.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6435,6 +6435,11 @@ static inline void wiphy_delayed_work_init(struct wiphy_delayed_work *dwork,
64356435
* after wiphy_lock() was called. Therefore, wiphy_cancel_work() can
64366436
* use just cancel_work() instead of cancel_work_sync(), it requires
64376437
* being in a section protected by wiphy_lock().
6438+
*
6439+
* Note that these are scheduled with a timer where the accuracy
6440+
* becomes less the longer in the future the scheduled timer is. Use
6441+
* wiphy_hrtimer_work_queue() if the timer must be not be late by more
6442+
* than approximately 10 percent.
64386443
*/
64396444
void wiphy_delayed_work_queue(struct wiphy *wiphy,
64406445
struct wiphy_delayed_work *dwork,
@@ -6506,6 +6511,79 @@ void wiphy_delayed_work_flush(struct wiphy *wiphy,
65066511
bool wiphy_delayed_work_pending(struct wiphy *wiphy,
65076512
struct wiphy_delayed_work *dwork);
65086513

6514+
struct wiphy_hrtimer_work {
6515+
struct wiphy_work work;
6516+
struct wiphy *wiphy;
6517+
struct hrtimer timer;
6518+
};
6519+
6520+
enum hrtimer_restart wiphy_hrtimer_work_timer(struct hrtimer *t);
6521+
6522+
static inline void wiphy_hrtimer_work_init(struct wiphy_hrtimer_work *hrwork,
6523+
wiphy_work_func_t func)
6524+
{
6525+
hrtimer_setup(&hrwork->timer, wiphy_hrtimer_work_timer,
6526+
CLOCK_BOOTTIME, HRTIMER_MODE_REL);
6527+
wiphy_work_init(&hrwork->work, func);
6528+
}
6529+
6530+
/**
6531+
* wiphy_hrtimer_work_queue - queue hrtimer work for the wiphy
6532+
* @wiphy: the wiphy to queue for
6533+
* @hrwork: the high resolution timer worker
6534+
* @delay: the delay given as a ktime_t
6535+
*
6536+
* Please refer to wiphy_delayed_work_queue(). The difference is that
6537+
* the hrtimer work uses a high resolution timer for scheduling. This
6538+
* may be needed if timeouts might be scheduled further in the future
6539+
* and the accuracy of the normal timer is not sufficient.
6540+
*
6541+
* Expect a delay of a few milliseconds as the timer is scheduled
6542+
* with some slack and some more time may pass between queueing the
6543+
* work and its start.
6544+
*/
6545+
void wiphy_hrtimer_work_queue(struct wiphy *wiphy,
6546+
struct wiphy_hrtimer_work *hrwork,
6547+
ktime_t delay);
6548+
6549+
/**
6550+
* wiphy_hrtimer_work_cancel - cancel previously queued hrtimer work
6551+
* @wiphy: the wiphy, for debug purposes
6552+
* @hrtimer: the hrtimer work to cancel
6553+
*
6554+
* Cancel the work *without* waiting for it, this assumes being
6555+
* called under the wiphy mutex acquired by wiphy_lock().
6556+
*/
6557+
void wiphy_hrtimer_work_cancel(struct wiphy *wiphy,
6558+
struct wiphy_hrtimer_work *hrtimer);
6559+
6560+
/**
6561+
* wiphy_hrtimer_work_flush - flush previously queued hrtimer work
6562+
* @wiphy: the wiphy, for debug purposes
6563+
* @hrwork: the hrtimer work to flush
6564+
*
6565+
* Flush the work (i.e. run it if pending). This must be called
6566+
* under the wiphy mutex acquired by wiphy_lock().
6567+
*/
6568+
void wiphy_hrtimer_work_flush(struct wiphy *wiphy,
6569+
struct wiphy_hrtimer_work *hrwork);
6570+
6571+
/**
6572+
* wiphy_hrtimer_work_pending - Find out whether a wiphy hrtimer
6573+
* work item is currently pending.
6574+
*
6575+
* @wiphy: the wiphy, for debug purposes
6576+
* @hrwork: the hrtimer work in question
6577+
*
6578+
* Return: true if timer is pending, false otherwise
6579+
*
6580+
* Please refer to the wiphy_delayed_work_pending() documentation as
6581+
* this is the equivalent function for hrtimer based delayed work
6582+
* items.
6583+
*/
6584+
bool wiphy_hrtimer_work_pending(struct wiphy *wiphy,
6585+
struct wiphy_hrtimer_work *hrwork);
6586+
65096587
/**
65106588
* enum ieee80211_ap_reg_power - regulatory power for an Access Point
65116589
*

net/wireless/core.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,62 @@ bool wiphy_delayed_work_pending(struct wiphy *wiphy,
17871787
}
17881788
EXPORT_SYMBOL_GPL(wiphy_delayed_work_pending);
17891789

1790+
enum hrtimer_restart wiphy_hrtimer_work_timer(struct hrtimer *t)
1791+
{
1792+
struct wiphy_hrtimer_work *hrwork =
1793+
container_of(t, struct wiphy_hrtimer_work, timer);
1794+
1795+
wiphy_work_queue(hrwork->wiphy, &hrwork->work);
1796+
1797+
return HRTIMER_NORESTART;
1798+
}
1799+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_timer);
1800+
1801+
void wiphy_hrtimer_work_queue(struct wiphy *wiphy,
1802+
struct wiphy_hrtimer_work *hrwork,
1803+
ktime_t delay)
1804+
{
1805+
trace_wiphy_hrtimer_work_queue(wiphy, &hrwork->work, delay);
1806+
1807+
if (!delay) {
1808+
hrtimer_cancel(&hrwork->timer);
1809+
wiphy_work_queue(wiphy, &hrwork->work);
1810+
return;
1811+
}
1812+
1813+
hrwork->wiphy = wiphy;
1814+
hrtimer_start_range_ns(&hrwork->timer, delay,
1815+
1000 * NSEC_PER_USEC, HRTIMER_MODE_REL);
1816+
}
1817+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_queue);
1818+
1819+
void wiphy_hrtimer_work_cancel(struct wiphy *wiphy,
1820+
struct wiphy_hrtimer_work *hrwork)
1821+
{
1822+
lockdep_assert_held(&wiphy->mtx);
1823+
1824+
hrtimer_cancel(&hrwork->timer);
1825+
wiphy_work_cancel(wiphy, &hrwork->work);
1826+
}
1827+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_cancel);
1828+
1829+
void wiphy_hrtimer_work_flush(struct wiphy *wiphy,
1830+
struct wiphy_hrtimer_work *hrwork)
1831+
{
1832+
lockdep_assert_held(&wiphy->mtx);
1833+
1834+
hrtimer_cancel(&hrwork->timer);
1835+
wiphy_work_flush(wiphy, &hrwork->work);
1836+
}
1837+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_flush);
1838+
1839+
bool wiphy_hrtimer_work_pending(struct wiphy *wiphy,
1840+
struct wiphy_hrtimer_work *hrwork)
1841+
{
1842+
return hrtimer_is_queued(&hrwork->timer);
1843+
}
1844+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_pending);
1845+
17901846
static int __init cfg80211_init(void)
17911847
{
17921848
int err;

net/wireless/trace.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,27 @@ TRACE_EVENT(wiphy_delayed_work_queue,
304304
__entry->delay)
305305
);
306306

307+
TRACE_EVENT(wiphy_hrtimer_work_queue,
308+
TP_PROTO(struct wiphy *wiphy, struct wiphy_work *work,
309+
ktime_t delay),
310+
TP_ARGS(wiphy, work, delay),
311+
TP_STRUCT__entry(
312+
WIPHY_ENTRY
313+
__field(void *, instance)
314+
__field(void *, func)
315+
__field(ktime_t, delay)
316+
),
317+
TP_fast_assign(
318+
WIPHY_ASSIGN;
319+
__entry->instance = work;
320+
__entry->func = work->func;
321+
__entry->delay = delay;
322+
),
323+
TP_printk(WIPHY_PR_FMT " instance=%p func=%pS delay=%llu",
324+
WIPHY_PR_ARG, __entry->instance, __entry->func,
325+
__entry->delay)
326+
);
327+
307328
TRACE_EVENT(wiphy_work_worker_start,
308329
TP_PROTO(struct wiphy *wiphy),
309330
TP_ARGS(wiphy),

0 commit comments

Comments
 (0)