Skip to content

Commit 8066c83

Browse files
benzeajfvogel
authored andcommitted
wifi: cfg80211: add an hrtimer based delayed work item
[ Upstream commit 7ceba45a6658ce637da334cd0ebf27f4ede6c0fe ] 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> [ replaced hrtimer_setup() call with hrtimer_init() and manual timer.function assignment ] Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit d4caee32a9f8fc6fff5297d662c531caef18e222) Signed-off-by: Jack Vogel <jack.vogel@oracle.com>
1 parent b3c0f66 commit 8066c83

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

include/net/cfg80211.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6105,6 +6105,11 @@ static inline void wiphy_delayed_work_init(struct wiphy_delayed_work *dwork,
61056105
* after wiphy_lock() was called. Therefore, wiphy_cancel_work() can
61066106
* use just cancel_work() instead of cancel_work_sync(), it requires
61076107
* being in a section protected by wiphy_lock().
6108+
*
6109+
* Note that these are scheduled with a timer where the accuracy
6110+
* becomes less the longer in the future the scheduled timer is. Use
6111+
* wiphy_hrtimer_work_queue() if the timer must be not be late by more
6112+
* than approximately 10 percent.
61086113
*/
61096114
void wiphy_delayed_work_queue(struct wiphy *wiphy,
61106115
struct wiphy_delayed_work *dwork,
@@ -6176,6 +6181,79 @@ void wiphy_delayed_work_flush(struct wiphy *wiphy,
61766181
bool wiphy_delayed_work_pending(struct wiphy *wiphy,
61776182
struct wiphy_delayed_work *dwork);
61786183

6184+
struct wiphy_hrtimer_work {
6185+
struct wiphy_work work;
6186+
struct wiphy *wiphy;
6187+
struct hrtimer timer;
6188+
};
6189+
6190+
enum hrtimer_restart wiphy_hrtimer_work_timer(struct hrtimer *t);
6191+
6192+
static inline void wiphy_hrtimer_work_init(struct wiphy_hrtimer_work *hrwork,
6193+
wiphy_work_func_t func)
6194+
{
6195+
hrtimer_init(&hrwork->timer, CLOCK_BOOTTIME, HRTIMER_MODE_REL);
6196+
hrwork->timer.function = wiphy_hrtimer_work_timer;
6197+
wiphy_work_init(&hrwork->work, func);
6198+
}
6199+
6200+
/**
6201+
* wiphy_hrtimer_work_queue - queue hrtimer work for the wiphy
6202+
* @wiphy: the wiphy to queue for
6203+
* @hrwork: the high resolution timer worker
6204+
* @delay: the delay given as a ktime_t
6205+
*
6206+
* Please refer to wiphy_delayed_work_queue(). The difference is that
6207+
* the hrtimer work uses a high resolution timer for scheduling. This
6208+
* may be needed if timeouts might be scheduled further in the future
6209+
* and the accuracy of the normal timer is not sufficient.
6210+
*
6211+
* Expect a delay of a few milliseconds as the timer is scheduled
6212+
* with some slack and some more time may pass between queueing the
6213+
* work and its start.
6214+
*/
6215+
void wiphy_hrtimer_work_queue(struct wiphy *wiphy,
6216+
struct wiphy_hrtimer_work *hrwork,
6217+
ktime_t delay);
6218+
6219+
/**
6220+
* wiphy_hrtimer_work_cancel - cancel previously queued hrtimer work
6221+
* @wiphy: the wiphy, for debug purposes
6222+
* @hrtimer: the hrtimer work to cancel
6223+
*
6224+
* Cancel the work *without* waiting for it, this assumes being
6225+
* called under the wiphy mutex acquired by wiphy_lock().
6226+
*/
6227+
void wiphy_hrtimer_work_cancel(struct wiphy *wiphy,
6228+
struct wiphy_hrtimer_work *hrtimer);
6229+
6230+
/**
6231+
* wiphy_hrtimer_work_flush - flush previously queued hrtimer work
6232+
* @wiphy: the wiphy, for debug purposes
6233+
* @hrwork: the hrtimer work to flush
6234+
*
6235+
* Flush the work (i.e. run it if pending). This must be called
6236+
* under the wiphy mutex acquired by wiphy_lock().
6237+
*/
6238+
void wiphy_hrtimer_work_flush(struct wiphy *wiphy,
6239+
struct wiphy_hrtimer_work *hrwork);
6240+
6241+
/**
6242+
* wiphy_hrtimer_work_pending - Find out whether a wiphy hrtimer
6243+
* work item is currently pending.
6244+
*
6245+
* @wiphy: the wiphy, for debug purposes
6246+
* @hrwork: the hrtimer work in question
6247+
*
6248+
* Return: true if timer is pending, false otherwise
6249+
*
6250+
* Please refer to the wiphy_delayed_work_pending() documentation as
6251+
* this is the equivalent function for hrtimer based delayed work
6252+
* items.
6253+
*/
6254+
bool wiphy_hrtimer_work_pending(struct wiphy *wiphy,
6255+
struct wiphy_hrtimer_work *hrwork);
6256+
61796257
/**
61806258
* enum ieee80211_ap_reg_power - regulatory power for an Access Point
61816259
*

net/wireless/core.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,62 @@ bool wiphy_delayed_work_pending(struct wiphy *wiphy,
17631763
}
17641764
EXPORT_SYMBOL_GPL(wiphy_delayed_work_pending);
17651765

1766+
enum hrtimer_restart wiphy_hrtimer_work_timer(struct hrtimer *t)
1767+
{
1768+
struct wiphy_hrtimer_work *hrwork =
1769+
container_of(t, struct wiphy_hrtimer_work, timer);
1770+
1771+
wiphy_work_queue(hrwork->wiphy, &hrwork->work);
1772+
1773+
return HRTIMER_NORESTART;
1774+
}
1775+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_timer);
1776+
1777+
void wiphy_hrtimer_work_queue(struct wiphy *wiphy,
1778+
struct wiphy_hrtimer_work *hrwork,
1779+
ktime_t delay)
1780+
{
1781+
trace_wiphy_hrtimer_work_queue(wiphy, &hrwork->work, delay);
1782+
1783+
if (!delay) {
1784+
hrtimer_cancel(&hrwork->timer);
1785+
wiphy_work_queue(wiphy, &hrwork->work);
1786+
return;
1787+
}
1788+
1789+
hrwork->wiphy = wiphy;
1790+
hrtimer_start_range_ns(&hrwork->timer, delay,
1791+
1000 * NSEC_PER_USEC, HRTIMER_MODE_REL);
1792+
}
1793+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_queue);
1794+
1795+
void wiphy_hrtimer_work_cancel(struct wiphy *wiphy,
1796+
struct wiphy_hrtimer_work *hrwork)
1797+
{
1798+
lockdep_assert_held(&wiphy->mtx);
1799+
1800+
hrtimer_cancel(&hrwork->timer);
1801+
wiphy_work_cancel(wiphy, &hrwork->work);
1802+
}
1803+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_cancel);
1804+
1805+
void wiphy_hrtimer_work_flush(struct wiphy *wiphy,
1806+
struct wiphy_hrtimer_work *hrwork)
1807+
{
1808+
lockdep_assert_held(&wiphy->mtx);
1809+
1810+
hrtimer_cancel(&hrwork->timer);
1811+
wiphy_work_flush(wiphy, &hrwork->work);
1812+
}
1813+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_flush);
1814+
1815+
bool wiphy_hrtimer_work_pending(struct wiphy *wiphy,
1816+
struct wiphy_hrtimer_work *hrwork)
1817+
{
1818+
return hrtimer_is_queued(&hrwork->timer);
1819+
}
1820+
EXPORT_SYMBOL_GPL(wiphy_hrtimer_work_pending);
1821+
17661822
static int __init cfg80211_init(void)
17671823
{
17681824
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)