Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1724178 > unrolled thread
| Started by | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| First post | 2017-08-31 14:30 +0200 |
| Last post | 2017-08-31 14:40 +0200 |
| Articles | 15 on this page of 35 — 8 participants |
Back to article view | Back to linux.kernel
[PATCH 00/25] hrtimer: Provide softirq context hrtimers Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 07/25] hrtimer: Reduce conditional code (hres_active) Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 05/25] hrtimer: Switch for loop to _ffs() evaluation Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 24/25] net/cdc_ncm: Replace tasklet with softirq hrtimer Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
Re: [PATCH 24/25] net/cdc_ncm: Replace tasklet with softirq hrtimer Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2017-08-31 15:40 +0200
Re: [PATCH 24/25] net/cdc_ncm: Replace tasklet with softirq hrtimer Bjørn Mork <bjorn@mork.no> - 2017-08-31 16:00 +0200
[PATCH 24/25 v2] net/cdc_ncm: Replace tasklet with softirq hrtimer Sebastian Andrzej Siewior <bigeasy@linutronix.de> - 2017-09-05 17:50 +0200
[PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
Re: [PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Iwai <tiwai@suse.de> - 2017-08-31 16:30 +0200
Re: [PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2017-08-31 16:30 +0200
Re: [PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Iwai <tiwai@suse.de> - 2017-08-31 17:40 +0200
Re: [PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2017-09-01 12:30 +0200
Re: [PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Iwai <tiwai@suse.de> - 2017-09-01 14:00 +0200
Re: [PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2017-09-02 03:30 +0200
Re: [PATCH 23/25] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2017-09-04 14:50 +0200
[PATCH 23/25 v2] ALSA/dummy: Replace tasklet with softirq hrtimer Sebastian Andrzej Siewior <bigeasy@linutronix.de> - 2017-09-05 18:00 +0200
Re: [PATCH 23/25 v2] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Iwai <tiwai@suse.de> - 2017-09-05 18:10 +0200
Re: [PATCH 23/25 v2] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2017-09-05 18:10 +0200
[PATCH 23/25 v3] ALSA/dummy: Replace tasklet with softirq hrtimer Sebastian Andrzej Siewior <bigeasy@linutronix.de> - 2017-09-05 18:20 +0200
Re: [PATCH 23/25 v3] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2017-09-06 06:40 +0200
Re: [alsa-devel] [PATCH 23/25 v3] ALSA/dummy: Replace tasklet with softirq hrtimer Takashi Iwai <tiwai@suse.de> - 2017-09-08 10:30 +0200
[PATCH 22/25] softirq: Remove tasklet_hrtimer Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 21/25] xfrm: Replace hrtimer tasklet with softirq hrtimer Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 06/25] hrtimer: Store running timer in hrtimer_clock_base Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer Thomas Gleixner <tglx@linutronix.de> - 2017-09-01 18:00 +0200
Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer Oliver Hartkopp <socketcan@hartkopp.net> - 2017-09-01 19:10 +0200
Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer Oliver Hartkopp <socketcan@hartkopp.net> - 2017-09-01 18:00 +0200
Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer Oliver Hartkopp <socketcan@hartkopp.net> - 2017-09-02 20:10 +0200
[PATCH 10/25] hrtimer: Make handling of hrtimer reprogramming and enqueuing not conditional Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 14/25] hrtimer: Split out code from __hrtimer_get_next_event() for reuse Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 25/25] usb/gadget/NCM: Replace tasklet with softirq hrtimer Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 03/25] hrtimer: Fix kerneldoc for struct hrtimer_cpu_base Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
[PATCH 09/25] hrtimer: Reduce conditional code (hrtimer_reprogram()) Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:30 +0200
Re: [PATCH 00/25] hrtimer: Provide softirq context hrtimers Anna-Maria Gleixner <anna-maria@linutronix.de> - 2017-08-31 14:40 +0200
Page 2 of 2 — ← Prev page 1 [2]
| From | Takashi Iwai <tiwai@suse.de> |
|---|---|
| Date | 2017-09-08 10:30 +0200 |
| Subject | Re: [alsa-devel] [PATCH 23/25 v3] ALSA/dummy: Replace tasklet with softirq hrtimer |
| Message-ID | <unmPM-4eF-21@gated-at.bofh.it> |
| In reply to | #1727151 |
On Wed, 06 Sep 2017 06:30:03 +0200, Takashi Sakamoto wrote: > > On Sep 6 2017 01:18, Sebastian Andrzej Siewior wrote: > > From: Thomas Gleixner <tglx@linutronix.de> > > > > The tasklet is used to defer the execution of snd_pcm_period_elapsed() to > > the softirq context. Using the CLOCK_MONOTONIC_SOFT base invokes the timer > > callback in softirq context as well which renders the tasklet useless. > > > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > > Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> > > Cc: Jaroslav Kysela <perex@perex.cz> > > Cc: Takashi Iwai <tiwai@suse.com> > > Cc: Takashi Sakamoto <o-takashi@sakamocchi.jp> > > Cc: alsa-devel@alsa-project.org > > [o-takashi: avoid stall due to a call of hrtimer_cancel() on a callback > > of hrtimer] > > Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> > > Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> > > --- > > On 2017-09-06 01:05:43 [+0900], Takashi Sakamoto wrote: > >> As Iwai-san mentioned, in this function, .trigger can be called in two > >> cases; XRUN occurs and draining is done. Thus, let you change the comment as > >> 'In cases of XRUN and draining, this calls .trigger to stop PCM substream.'. > >> I'm sorry to trouble you. > >> > >> snd_pcm_period_elapsed() > >> ->snd_pcm_update_hw_ptr0() > >> ->snd_pcm_update_state() > >> ->snd_pcm_drain_done() > >> ... > >> ->.trigger(TRIGGER_STOP) > >> ->xrun() > >> ->snd_pcm_stop() > >> ... > >> ->.trigger(TRIGGER_STOP) > >> > > > > I think you asked me just to update the comment. Did I do it right? > > > > v2…v3: updated the comment as per Takashi Sakamoto's suggestion. > > v1…v2: merged Takashi Sakamoto fixup of the original patch into v2. > > > > sound/drivers/dummy.c | 25 +++++++++++-------------- > > 1 file changed, 11 insertions(+), 14 deletions(-) > > This Looks good to me. I did quick test and confirmed that it brings > no stalls. > > Tested-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> I suppose you'd apply all together in some tree like tip or whatever? In anyway, feel free to take my ack for this patch: Reviewed-by: Takashi Iwai <tiwai@suse.de> Thanks! Takashi
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 22/25] softirq: Remove tasklet_hrtimer |
| Message-ID | <ukwLG-5Ay-59@gated-at.bofh.it> |
| In reply to | #1724178 |
From: Thomas Gleixner <tglx@linutronix.de>
There are no more tasklet_hrtimer users of this interface.
Remove it.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
---
include/linux/interrupt.h | 25 ----------------------
kernel/softirq.c | 51 ----------------------------------------------
2 files changed, 76 deletions(-)
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -631,31 +631,6 @@ extern void tasklet_kill_immediate(struc
extern void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data);
-struct tasklet_hrtimer {
- struct hrtimer timer;
- struct tasklet_struct tasklet;
- enum hrtimer_restart (*function)(struct hrtimer *);
-};
-
-extern void
-tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
- enum hrtimer_restart (*function)(struct hrtimer *),
- clockid_t which_clock, enum hrtimer_mode mode);
-
-static inline
-void tasklet_hrtimer_start(struct tasklet_hrtimer *ttimer, ktime_t time,
- const enum hrtimer_mode mode)
-{
- hrtimer_start(&ttimer->timer, time, mode);
-}
-
-static inline
-void tasklet_hrtimer_cancel(struct tasklet_hrtimer *ttimer)
-{
- hrtimer_cancel(&ttimer->timer);
- tasklet_kill(&ttimer->tasklet);
-}
-
/*
* Autoprobing for irqs:
*
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -594,57 +594,6 @@ void tasklet_kill(struct tasklet_struct
}
EXPORT_SYMBOL(tasklet_kill);
-/*
- * tasklet_hrtimer
- */
-
-/*
- * The trampoline is called when the hrtimer expires. It schedules a tasklet
- * to run __tasklet_hrtimer_trampoline() which in turn will call the intended
- * hrtimer callback, but from softirq context.
- */
-static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
-{
- struct tasklet_hrtimer *ttimer =
- container_of(timer, struct tasklet_hrtimer, timer);
-
- tasklet_hi_schedule(&ttimer->tasklet);
- return HRTIMER_NORESTART;
-}
-
-/*
- * Helper function which calls the hrtimer callback from
- * tasklet/softirq context
- */
-static void __tasklet_hrtimer_trampoline(unsigned long data)
-{
- struct tasklet_hrtimer *ttimer = (void *)data;
- enum hrtimer_restart restart;
-
- restart = ttimer->function(&ttimer->timer);
- if (restart != HRTIMER_NORESTART)
- hrtimer_restart(&ttimer->timer);
-}
-
-/**
- * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
- * @ttimer: tasklet_hrtimer which is initialized
- * @function: hrtimer callback function which gets called from softirq context
- * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
- * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
- */
-void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
- enum hrtimer_restart (*function)(struct hrtimer *),
- clockid_t which_clock, enum hrtimer_mode mode)
-{
- hrtimer_init(&ttimer->timer, which_clock, mode);
- ttimer->timer.function = __hrtimer_tasklet_trampoline;
- tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
- (unsigned long)ttimer);
- ttimer->function = function;
-}
-EXPORT_SYMBOL_GPL(tasklet_hrtimer_init);
-
void __init softirq_init(void)
{
int cpu;
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 21/25] xfrm: Replace hrtimer tasklet with softirq hrtimer |
| Message-ID | <ukwLG-5Ay-63@gated-at.bofh.it> |
| In reply to | #1724178 |
From: Thomas Gleixner <tglx@linutronix.de>
Switch the timer to CLOCK_MONOTONIC_SOFT, which executed the timer
callback in softirq context and remove the hrtimer_tasklet.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
---
include/net/xfrm.h | 2 +-
net/xfrm/xfrm_state.c | 29 +++++++++++++++++------------
2 files changed, 18 insertions(+), 13 deletions(-)
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -213,7 +213,7 @@ struct xfrm_state {
struct xfrm_stats stats;
struct xfrm_lifetime_cur curlft;
- struct tasklet_hrtimer mtimer;
+ struct hrtimer mtimer;
struct xfrm_state_offload xso;
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -418,7 +418,7 @@ static void xfrm_put_mode(struct xfrm_mo
static void xfrm_state_gc_destroy(struct xfrm_state *x)
{
- tasklet_hrtimer_cancel(&x->mtimer);
+ hrtimer_cancel(&x->mtimer);
del_timer_sync(&x->rtimer);
kfree(x->aead);
kfree(x->aalg);
@@ -463,8 +463,8 @@ static void xfrm_state_gc_task(struct wo
static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
{
- struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer);
- struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer);
+ struct xfrm_state *x = container_of(me, struct xfrm_state, mtimer);
+ enum hrtimer_restart ret = HRTIMER_NORESTART;
unsigned long now = get_seconds();
long next = LONG_MAX;
int warn = 0;
@@ -528,7 +528,8 @@ static enum hrtimer_restart xfrm_timer_h
km_state_expired(x, 0, 0);
resched:
if (next != LONG_MAX) {
- tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL);
+ hrtimer_forward_now(&x->mtimer, ktime_set(next, 0));
+ ret = HRTIMER_RESTART;
}
goto out;
@@ -545,7 +546,7 @@ static enum hrtimer_restart xfrm_timer_h
out:
spin_unlock(&x->lock);
- return HRTIMER_NORESTART;
+ return ret;
}
static void xfrm_replay_timer_handler(unsigned long data);
@@ -564,8 +565,8 @@ struct xfrm_state *xfrm_state_alloc(stru
INIT_HLIST_NODE(&x->bydst);
INIT_HLIST_NODE(&x->bysrc);
INIT_HLIST_NODE(&x->byspi);
- tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler,
- CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
+ hrtimer_init(&x->mtimer, CLOCK_BOOTTIME_SOFT, HRTIMER_MODE_ABS);
+ x->mtimer.function = xfrm_timer_handler;
setup_timer(&x->rtimer, xfrm_replay_timer_handler,
(unsigned long)x);
x->curlft.add_time = get_seconds();
@@ -1021,7 +1022,9 @@ xfrm_state_find(const xfrm_address_t *da
hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
}
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
- tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL);
+ hrtimer_start(&x->mtimer,
+ ktime_set(net->xfrm.sysctl_acq_expires, 0),
+ HRTIMER_MODE_REL);
net->xfrm.state_num++;
xfrm_hash_grow_check(net, x->bydst.next != NULL);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
@@ -1132,7 +1135,7 @@ static void __xfrm_state_insert(struct x
hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
}
- tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
if (x->replay_maxage)
mod_timer(&x->rtimer, jiffies + x->replay_maxage);
@@ -1236,7 +1239,9 @@ static struct xfrm_state *__find_acq_cor
x->mark.m = m->m;
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
xfrm_state_hold(x);
- tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL);
+ hrtimer_start(&x->mtimer,
+ ktime_set(net->xfrm.sysctl_acq_expires, 0),
+ HRTIMER_MODE_REL);
list_add(&x->km.all, &net->xfrm.state_all);
hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
h = xfrm_src_hash(net, daddr, saddr, family);
@@ -1535,7 +1540,7 @@ int xfrm_state_update(struct xfrm_state
memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
x1->km.dying = 0;
- tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
if (x1->curlft.use_time)
xfrm_state_check_expire(x1);
@@ -1559,7 +1564,7 @@ int xfrm_state_check_expire(struct xfrm_
if (x->curlft.bytes >= x->lft.hard_byte_limit ||
x->curlft.packets >= x->lft.hard_packet_limit) {
x->km.state = XFRM_STATE_EXPIRED;
- tasklet_hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL);
+ hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL);
return -EINVAL;
}
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 06/25] hrtimer: Store running timer in hrtimer_clock_base |
| Message-ID | <ukwLG-5Ay-55@gated-at.bofh.it> |
| In reply to | #1724178 |
From: Anna-Maria Gleixner <anna-maria@linutronix.de>
The pointer to the currently running timer is stored in hrtimer_cpu_base
before the base lock is dropped and the callback is invoked.
This results in two levels of indirections and the upcoming support for
softirq based hrtimer requires splitting the "running" storage into soft
and hard irq context expiry.
Storing both in the cpu base would require conditionals in all code paths
accessing that information.
It's possible to have a per clock base sequence count and running pointer
without changing the semantics of the related mechanisms because the timer
base pointer cannot be changed while a timer is running the callback.
Unfortunately this makes cpu_clock base larger than 32 bytes on 32bit
kernels. Instead of having huge gaps due to alignment, remove the alignment
and let the compiler pack cpu base for 32bit. The resulting cache access
patterns are fortunately not really different from the current
behaviour. On 64bit kernels the 64byte alignment stays and the behaviour is
unchanged.
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
---
include/linux/hrtimer.h | 20 +++++++++-----------
kernel/time/hrtimer.c | 28 +++++++++++++---------------
2 files changed, 22 insertions(+), 26 deletions(-)
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -112,9 +112,9 @@ struct hrtimer_sleeper {
};
#ifdef CONFIG_64BIT
-# define HRTIMER_CLOCK_BASE_ALIGN 64
+# define __hrtimer_clock_base_align ____cacheline_aligned
#else
-# define HRTIMER_CLOCK_BASE_ALIGN 32
+# define __hrtimer_clock_base_align
#endif
/**
@@ -123,18 +123,22 @@ struct hrtimer_sleeper {
* @index: clock type index for per_cpu support when moving a
* timer to a base on another cpu.
* @clockid: clock id for per_cpu support
+ * @seq: seqcount around __run_hrtimer
+ * @running: pointer to the currently running hrtimer
* @active: red black tree root node for the active timers
* @get_time: function to retrieve the current time of the clock
* @offset: offset of this clock to the monotonic base
*/
struct hrtimer_clock_base {
struct hrtimer_cpu_base *cpu_base;
- int index;
+ unsigned int index;
clockid_t clockid;
+ seqcount_t seq;
+ struct hrtimer *running;
struct timerqueue_head active;
ktime_t (*get_time)(void);
ktime_t offset;
-} __attribute__((__aligned__(HRTIMER_CLOCK_BASE_ALIGN)));
+} __hrtimer_clock_base_align;
enum hrtimer_base_type {
HRTIMER_BASE_MONOTONIC,
@@ -148,8 +152,6 @@ enum hrtimer_base_type {
* struct hrtimer_cpu_base - the per cpu clock bases
* @lock: lock protecting the base and associated clock bases
* and timers
- * @seq: seqcount around __run_hrtimer
- * @running: pointer to the currently running hrtimer
* @cpu: cpu number
* @active_bases: Bitfield to mark bases with active timers
* @clock_was_set_seq: Sequence counter of clock was set events
@@ -173,8 +175,6 @@ enum hrtimer_base_type {
*/
struct hrtimer_cpu_base {
raw_spinlock_t lock;
- seqcount_t seq;
- struct hrtimer *running;
unsigned int cpu;
unsigned int active_bases;
unsigned int clock_was_set_seq;
@@ -196,8 +196,6 @@ struct hrtimer_cpu_base {
static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
{
- BUILD_BUG_ON(sizeof(struct hrtimer_clock_base) > HRTIMER_CLOCK_BASE_ALIGN);
-
timer->node.expires = time;
timer->_softexpires = time;
}
@@ -422,7 +420,7 @@ static inline int hrtimer_is_queued(stru
*/
static inline int hrtimer_callback_running(struct hrtimer *timer)
{
- return timer->base->cpu_base->running == timer;
+ return timer->base->running == timer;
}
/* Forward a hrtimer so it expires after now: */
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -70,7 +70,6 @@
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
{
.lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
- .seq = SEQCNT_ZERO(hrtimer_bases.seq),
.clock_base =
{
{
@@ -118,7 +117,6 @@ static const int hrtimer_clock_to_base_t
* timer->base->cpu_base
*/
static struct hrtimer_cpu_base migration_cpu_base = {
- .seq = SEQCNT_ZERO(migration_cpu_base),
.clock_base = { { .cpu_base = &migration_cpu_base, }, },
};
@@ -1136,19 +1134,19 @@ EXPORT_SYMBOL_GPL(hrtimer_init);
*/
bool hrtimer_active(const struct hrtimer *timer)
{
- struct hrtimer_cpu_base *cpu_base;
+ struct hrtimer_clock_base *base;
unsigned int seq;
do {
- cpu_base = READ_ONCE(timer->base->cpu_base);
- seq = raw_read_seqcount_begin(&cpu_base->seq);
+ base = READ_ONCE(timer->base);
+ seq = raw_read_seqcount_begin(&base->seq);
if (timer->state != HRTIMER_STATE_INACTIVE ||
- cpu_base->running == timer)
+ base->running == timer)
return true;
- } while (read_seqcount_retry(&cpu_base->seq, seq) ||
- cpu_base != READ_ONCE(timer->base->cpu_base));
+ } while (read_seqcount_retry(&base->seq, seq) ||
+ base != READ_ONCE(timer->base));
return false;
}
@@ -1182,16 +1180,16 @@ static void __run_hrtimer(struct hrtimer
lockdep_assert_held(&cpu_base->lock);
debug_deactivate(timer);
- cpu_base->running = timer;
+ base->running = timer;
/*
* Separate the ->running assignment from the ->state assignment.
*
* As with a regular write barrier, this ensures the read side in
- * hrtimer_active() cannot observe cpu_base->running == NULL &&
+ * hrtimer_active() cannot observe base->running == NULL &&
* timer->state == INACTIVE.
*/
- raw_write_seqcount_barrier(&cpu_base->seq);
+ raw_write_seqcount_barrier(&base->seq);
__remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0);
fn = timer->function;
@@ -1232,13 +1230,13 @@ static void __run_hrtimer(struct hrtimer
* Separate the ->running assignment from the ->state assignment.
*
* As with a regular write barrier, this ensures the read side in
- * hrtimer_active() cannot observe cpu_base->running == NULL &&
+ * hrtimer_active() cannot observe base->running.timer == NULL &&
* timer->state == INACTIVE.
*/
- raw_write_seqcount_barrier(&cpu_base->seq);
+ raw_write_seqcount_barrier(&base->seq);
- WARN_ON_ONCE(cpu_base->running != timer);
- cpu_base->running = NULL;
+ WARN_ON_ONCE(base->running != timer);
+ base->running = NULL;
}
static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now)
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer |
| Message-ID | <ukwLG-5Ay-57@gated-at.bofh.it> |
| In reply to | #1724178 |
From: Thomas Gleixner <tglx@linutronix.de>
Switch the timer to CLOCK_MONOTONIC_SOFT, which executed the timer
callback in softirq context and remove the hrtimer_tasklet.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: linux-can@vger.kernel.org
---
net/can/bcm.c | 150 ++++++++++++++++++----------------------------------------
1 file changed, 49 insertions(+), 101 deletions(-)
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -102,7 +102,6 @@ struct bcm_op {
unsigned long frames_abs, frames_filtered;
struct bcm_timeval ival1, ival2;
struct hrtimer timer, thrtimer;
- struct tasklet_struct tsklet, thrtsklet;
ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
int rx_ifindex;
int cfsiz;
@@ -364,25 +363,34 @@ static void bcm_send_to_user(struct bcm_
}
}
-static void bcm_tx_start_timer(struct bcm_op *op)
+static bool bcm_tx_set_expiry(struct bcm_op *op, struct hrtimer *hrt)
{
+ ktime_t ival;
+
if (op->kt_ival1 && op->count)
- hrtimer_start(&op->timer,
- ktime_add(ktime_get(), op->kt_ival1),
- HRTIMER_MODE_ABS);
+ ival = op->kt_ival1;
else if (op->kt_ival2)
- hrtimer_start(&op->timer,
- ktime_add(ktime_get(), op->kt_ival2),
- HRTIMER_MODE_ABS);
+ ival = op->kt_ival2;
+ else
+ return false;
+
+ hrtimer_set_expires(hrt, ktime_add(ktime_get(), ival));
+ return true;
}
-static void bcm_tx_timeout_tsklet(unsigned long data)
+static void bcm_tx_start_timer(struct bcm_op *op)
{
- struct bcm_op *op = (struct bcm_op *)data;
+ if (bcm_tx_set_expiry(op, &op->timer))
+ hrtimer_start_expires(&op->timer, HRTIMER_MODE_ABS);
+}
+
+/* bcm_tx_timeout_handler - performs cyclic CAN frame transmissions */
+static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
+{
+ struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
struct bcm_msg_head msg_head;
if (op->kt_ival1 && (op->count > 0)) {
-
op->count--;
if (!op->count && (op->flags & TX_COUNTEVT)) {
@@ -399,22 +407,12 @@ static void bcm_tx_timeout_tsklet(unsign
}
bcm_can_tx(op);
- } else if (op->kt_ival2)
+ } else if (op->kt_ival2) {
bcm_can_tx(op);
+ }
- bcm_tx_start_timer(op);
-}
-
-/*
- * bcm_tx_timeout_handler - performs cyclic CAN frame transmissions
- */
-static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
-{
- struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
-
- tasklet_schedule(&op->tsklet);
-
- return HRTIMER_NORESTART;
+ return bcm_tx_set_expiry(op, &op->timer) ?
+ HRTIMER_RESTART : HRTIMER_NORESTART;
}
/*
@@ -542,11 +540,18 @@ static void bcm_rx_starttimer(struct bcm
hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL);
}
-static void bcm_rx_timeout_tsklet(unsigned long data)
+/* bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out */
+static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
{
- struct bcm_op *op = (struct bcm_op *)data;
+ struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
struct bcm_msg_head msg_head;
+ /* if user wants to be informed, when cyclic CAN-Messages come back */
+ if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
+ /* clear received CAN frames to indicate 'nothing received' */
+ memset(op->last_frames, 0, op->nframes * op->cfsiz);
+ }
+
/* create notification to user */
msg_head.opcode = RX_TIMEOUT;
msg_head.flags = op->flags;
@@ -557,25 +562,6 @@ static void bcm_rx_timeout_tsklet(unsign
msg_head.nframes = 0;
bcm_send_to_user(op, &msg_head, NULL, 0);
-}
-
-/*
- * bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out
- */
-static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
-{
- struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
-
- /* schedule before NET_RX_SOFTIRQ */
- tasklet_hi_schedule(&op->tsklet);
-
- /* no restart of the timer is done here! */
-
- /* if user wants to be informed, when cyclic CAN-Messages come back */
- if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
- /* clear received CAN frames to indicate 'nothing received' */
- memset(op->last_frames, 0, op->nframes * op->cfsiz);
- }
return HRTIMER_NORESTART;
}
@@ -583,14 +569,12 @@ static enum hrtimer_restart bcm_rx_timeo
/*
* bcm_rx_do_flush - helper for bcm_rx_thr_flush
*/
-static inline int bcm_rx_do_flush(struct bcm_op *op, int update,
- unsigned int index)
+static inline int bcm_rx_do_flush(struct bcm_op *op, unsigned int index)
{
struct canfd_frame *lcf = op->last_frames + op->cfsiz * index;
if ((op->last_frames) && (lcf->flags & RX_THR)) {
- if (update)
- bcm_rx_changed(op, lcf);
+ bcm_rx_changed(op, lcf);
return 1;
}
return 0;
@@ -598,11 +582,8 @@ static inline int bcm_rx_do_flush(struct
/*
* bcm_rx_thr_flush - Check for throttled data and send it to the userspace
- *
- * update == 0 : just check if throttled data is available (any irq context)
- * update == 1 : check and send throttled data to userspace (soft_irq context)
*/
-static int bcm_rx_thr_flush(struct bcm_op *op, int update)
+static int bcm_rx_thr_flush(struct bcm_op *op)
{
int updated = 0;
@@ -611,24 +592,16 @@ static int bcm_rx_thr_flush(struct bcm_o
/* for MUX filter we start at index 1 */
for (i = 1; i < op->nframes; i++)
- updated += bcm_rx_do_flush(op, update, i);
+ updated += bcm_rx_do_flush(op, i);
} else {
/* for RX_FILTER_ID and simple filter */
- updated += bcm_rx_do_flush(op, update, 0);
+ updated += bcm_rx_do_flush(op, 0);
}
return updated;
}
-static void bcm_rx_thr_tsklet(unsigned long data)
-{
- struct bcm_op *op = (struct bcm_op *)data;
-
- /* push the changed data to the userspace */
- bcm_rx_thr_flush(op, 1);
-}
-
/*
* bcm_rx_thr_handler - the time for blocked content updates is over now:
* Check for throttled data and send it to the userspace
@@ -637,9 +610,7 @@ static enum hrtimer_restart bcm_rx_thr_h
{
struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
- tasklet_schedule(&op->thrtsklet);
-
- if (bcm_rx_thr_flush(op, 0)) {
+ if (bcm_rx_thr_flush(op)) {
hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2);
return HRTIMER_RESTART;
} else {
@@ -735,23 +706,8 @@ static struct bcm_op *bcm_find_op(struct
static void bcm_remove_op(struct bcm_op *op)
{
- if (op->tsklet.func) {
- while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) ||
- test_bit(TASKLET_STATE_RUN, &op->tsklet.state) ||
- hrtimer_active(&op->timer)) {
- hrtimer_cancel(&op->timer);
- tasklet_kill(&op->tsklet);
- }
- }
-
- if (op->thrtsklet.func) {
- while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) ||
- test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) ||
- hrtimer_active(&op->thrtimer)) {
- hrtimer_cancel(&op->thrtimer);
- tasklet_kill(&op->thrtsklet);
- }
- }
+ hrtimer_cancel(&op->timer);
+ hrtimer_cancel(&op->thrtimer);
if ((op->frames) && (op->frames != &op->sframe))
kfree(op->frames);
@@ -979,15 +935,13 @@ static int bcm_tx_setup(struct bcm_msg_h
op->ifindex = ifindex;
/* initialize uninitialized (kzalloc) structure */
- hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&op->timer, CLOCK_MONOTONIC_SOFT,
+ HRTIMER_MODE_REL);
op->timer.function = bcm_tx_timeout_handler;
- /* initialize tasklet for tx countevent notification */
- tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet,
- (unsigned long) op);
-
/* currently unused in tx_ops */
- hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC_SOFT,
+ HRTIMER_MODE_REL);
/* add this bcm_op to the list of the tx_ops */
list_add(&op->list, &bo->tx_ops);
@@ -1150,20 +1104,14 @@ static int bcm_rx_setup(struct bcm_msg_h
op->rx_ifindex = ifindex;
/* initialize uninitialized (kzalloc) structure */
- hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&op->timer, CLOCK_MONOTONIC_SOFT,
+ HRTIMER_MODE_REL);
op->timer.function = bcm_rx_timeout_handler;
- /* initialize tasklet for rx timeout notification */
- tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet,
- (unsigned long) op);
-
- hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC_SOFT,
+ HRTIMER_MODE_REL);
op->thrtimer.function = bcm_rx_thr_handler;
- /* initialize tasklet for rx throttle handling */
- tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet,
- (unsigned long) op);
-
/* add this bcm_op to the list of the rx_ops */
list_add(&op->list, &bo->rx_ops);
@@ -1209,7 +1157,7 @@ static int bcm_rx_setup(struct bcm_msg_h
*/
op->kt_lastmsg = 0;
hrtimer_cancel(&op->thrtimer);
- bcm_rx_thr_flush(op, 1);
+ bcm_rx_thr_flush(op);
}
if ((op->flags & STARTTIMER) && op->kt_ival1)
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2017-09-01 18:00 +0200 |
| Subject | Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer |
| Message-ID | <ukWwp-759-1@gated-at.bofh.it> |
| In reply to | #1724186 |
On Fri, 1 Sep 2017, Oliver Hartkopp wrote: > Hi Anna-Maria & Thomas, > > thanks for the effort! > > I'm really happy that the hrtimer becomes softirq capable as it basically > reverts this ugly commit from January 2009: > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=6e5c172cf7ca1ab878cc6a6a4c1d52fef60f3ee0 > > From the first look the changes seem to be correct. > > I'll pick the entire patchset for a test and give a Acked|Tested-by then. > > Best regards, > Oliver > > ps. > > On 08/31/2017 02:23 PM, Anna-Maria Gleixner wrote: > > (nothing here!) > > Please send patches inline and not as attachments. Tnx! PS: Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline; filename=canbcm_Replace_hrtimer_tasklet_with_softirq_based_hrtimer.patch Please get a proper mail client, which actually parses the Content-Disposition tag correcly Thanks, tglx
[toc] | [prev] | [next] | [standalone]
| From | Oliver Hartkopp <socketcan@hartkopp.net> |
|---|---|
| Date | 2017-09-01 19:10 +0200 |
| Subject | Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer |
| Message-ID | <ukXCa-81A-11@gated-at.bofh.it> |
| In reply to | #1725182 |
On 09/01/2017 05:56 PM, Thomas Gleixner wrote: > On Fri, 1 Sep 2017, Oliver Hartkopp wrote: >> >> On 08/31/2017 02:23 PM, Anna-Maria Gleixner wrote: >> >> (nothing here!) >> >> Please send patches inline and not as attachments. Tnx! > > PS: > > Content-Type: text/plain; charset=UTF-8 > Content-Disposition: inline; > filename=canbcm_Replace_hrtimer_tasklet_with_softirq_based_hrtimer.patch > > Please get a proper mail client, which actually parses the > Content-Disposition tag correcly > Aah! Setting mail.reply_quote_inline = true in the config editor fixes that issue when replying a quilt post with Thunderbird. Tnx! Best, Oliver
[toc] | [prev] | [next] | [standalone]
| From | Oliver Hartkopp <socketcan@hartkopp.net> |
|---|---|
| Date | 2017-09-01 18:00 +0200 |
| Subject | Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer |
| Message-ID | <ukWwp-759-3@gated-at.bofh.it> |
| In reply to | #1724186 |
Hi Anna-Maria & Thomas, thanks for the effort! I'm really happy that the hrtimer becomes softirq capable as it basically reverts this ugly commit from January 2009: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=6e5c172cf7ca1ab878cc6a6a4c1d52fef60f3ee0 From the first look the changes seem to be correct. I'll pick the entire patchset for a test and give a Acked|Tested-by then. Best regards, Oliver ps. On 08/31/2017 02:23 PM, Anna-Maria Gleixner wrote: (nothing here!) Please send patches inline and not as attachments. Tnx!
[toc] | [prev] | [next] | [standalone]
| From | Oliver Hartkopp <socketcan@hartkopp.net> |
|---|---|
| Date | 2017-09-02 20:10 +0200 |
| Subject | Re: [PATCH 19/25] can/bcm: Replace hrtimer_tasklet with softirq based hrtimer |
| Message-ID | <ull1M-6fs-3@gated-at.bofh.it> |
| In reply to | #1724186 |
On 08/31/2017 02:23 PM, Anna-Maria Gleixner wrote:
> From: Thomas Gleixner <tglx@linutronix.de>
>
> Switch the timer to CLOCK_MONOTONIC_SOFT, which executed the timer
> callback in softirq context and remove the hrtimer_tasklet.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
> Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Thanks,
Oliver
> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
> Cc: linux-can@vger.kernel.org
> ---
> net/can/bcm.c | 150 ++++++++++++++++++----------------------------------------
> 1 file changed, 49 insertions(+), 101 deletions(-)
>
> --- a/net/can/bcm.c
> +++ b/net/can/bcm.c
> @@ -102,7 +102,6 @@ struct bcm_op {
> unsigned long frames_abs, frames_filtered;
> struct bcm_timeval ival1, ival2;
> struct hrtimer timer, thrtimer;
> - struct tasklet_struct tsklet, thrtsklet;
> ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
> int rx_ifindex;
> int cfsiz;
> @@ -364,25 +363,34 @@ static void bcm_send_to_user(struct bcm_
> }
> }
>
> -static void bcm_tx_start_timer(struct bcm_op *op)
> +static bool bcm_tx_set_expiry(struct bcm_op *op, struct hrtimer *hrt)
> {
> + ktime_t ival;
> +
> if (op->kt_ival1 && op->count)
> - hrtimer_start(&op->timer,
> - ktime_add(ktime_get(), op->kt_ival1),
> - HRTIMER_MODE_ABS);
> + ival = op->kt_ival1;
> else if (op->kt_ival2)
> - hrtimer_start(&op->timer,
> - ktime_add(ktime_get(), op->kt_ival2),
> - HRTIMER_MODE_ABS);
> + ival = op->kt_ival2;
> + else
> + return false;
> +
> + hrtimer_set_expires(hrt, ktime_add(ktime_get(), ival));
> + return true;
> }
>
> -static void bcm_tx_timeout_tsklet(unsigned long data)
> +static void bcm_tx_start_timer(struct bcm_op *op)
> {
> - struct bcm_op *op = (struct bcm_op *)data;
> + if (bcm_tx_set_expiry(op, &op->timer))
> + hrtimer_start_expires(&op->timer, HRTIMER_MODE_ABS);
> +}
> +
> +/* bcm_tx_timeout_handler - performs cyclic CAN frame transmissions */
> +static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
> +{
> + struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
> struct bcm_msg_head msg_head;
>
> if (op->kt_ival1 && (op->count > 0)) {
> -
> op->count--;
> if (!op->count && (op->flags & TX_COUNTEVT)) {
>
> @@ -399,22 +407,12 @@ static void bcm_tx_timeout_tsklet(unsign
> }
> bcm_can_tx(op);
>
> - } else if (op->kt_ival2)
> + } else if (op->kt_ival2) {
> bcm_can_tx(op);
> + }
>
> - bcm_tx_start_timer(op);
> -}
> -
> -/*
> - * bcm_tx_timeout_handler - performs cyclic CAN frame transmissions
> - */
> -static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
> -{
> - struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
> -
> - tasklet_schedule(&op->tsklet);
> -
> - return HRTIMER_NORESTART;
> + return bcm_tx_set_expiry(op, &op->timer) ?
> + HRTIMER_RESTART : HRTIMER_NORESTART;
> }
>
> /*
> @@ -542,11 +540,18 @@ static void bcm_rx_starttimer(struct bcm
> hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL);
> }
>
> -static void bcm_rx_timeout_tsklet(unsigned long data)
> +/* bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out */
> +static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
> {
> - struct bcm_op *op = (struct bcm_op *)data;
> + struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
> struct bcm_msg_head msg_head;
>
> + /* if user wants to be informed, when cyclic CAN-Messages come back */
> + if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
> + /* clear received CAN frames to indicate 'nothing received' */
> + memset(op->last_frames, 0, op->nframes * op->cfsiz);
> + }
> +
> /* create notification to user */
> msg_head.opcode = RX_TIMEOUT;
> msg_head.flags = op->flags;
> @@ -557,25 +562,6 @@ static void bcm_rx_timeout_tsklet(unsign
> msg_head.nframes = 0;
>
> bcm_send_to_user(op, &msg_head, NULL, 0);
> -}
> -
> -/*
> - * bcm_rx_timeout_handler - when the (cyclic) CAN frame reception timed out
> - */
> -static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
> -{
> - struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
> -
> - /* schedule before NET_RX_SOFTIRQ */
> - tasklet_hi_schedule(&op->tsklet);
> -
> - /* no restart of the timer is done here! */
> -
> - /* if user wants to be informed, when cyclic CAN-Messages come back */
> - if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
> - /* clear received CAN frames to indicate 'nothing received' */
> - memset(op->last_frames, 0, op->nframes * op->cfsiz);
> - }
>
> return HRTIMER_NORESTART;
> }
> @@ -583,14 +569,12 @@ static enum hrtimer_restart bcm_rx_timeo
> /*
> * bcm_rx_do_flush - helper for bcm_rx_thr_flush
> */
> -static inline int bcm_rx_do_flush(struct bcm_op *op, int update,
> - unsigned int index)
> +static inline int bcm_rx_do_flush(struct bcm_op *op, unsigned int index)
> {
> struct canfd_frame *lcf = op->last_frames + op->cfsiz * index;
>
> if ((op->last_frames) && (lcf->flags & RX_THR)) {
> - if (update)
> - bcm_rx_changed(op, lcf);
> + bcm_rx_changed(op, lcf);
> return 1;
> }
> return 0;
> @@ -598,11 +582,8 @@ static inline int bcm_rx_do_flush(struct
>
> /*
> * bcm_rx_thr_flush - Check for throttled data and send it to the userspace
> - *
> - * update == 0 : just check if throttled data is available (any irq context)
> - * update == 1 : check and send throttled data to userspace (soft_irq context)
> */
> -static int bcm_rx_thr_flush(struct bcm_op *op, int update)
> +static int bcm_rx_thr_flush(struct bcm_op *op)
> {
> int updated = 0;
>
> @@ -611,24 +592,16 @@ static int bcm_rx_thr_flush(struct bcm_o
>
> /* for MUX filter we start at index 1 */
> for (i = 1; i < op->nframes; i++)
> - updated += bcm_rx_do_flush(op, update, i);
> + updated += bcm_rx_do_flush(op, i);
>
> } else {
> /* for RX_FILTER_ID and simple filter */
> - updated += bcm_rx_do_flush(op, update, 0);
> + updated += bcm_rx_do_flush(op, 0);
> }
>
> return updated;
> }
>
> -static void bcm_rx_thr_tsklet(unsigned long data)
> -{
> - struct bcm_op *op = (struct bcm_op *)data;
> -
> - /* push the changed data to the userspace */
> - bcm_rx_thr_flush(op, 1);
> -}
> -
> /*
> * bcm_rx_thr_handler - the time for blocked content updates is over now:
> * Check for throttled data and send it to the userspace
> @@ -637,9 +610,7 @@ static enum hrtimer_restart bcm_rx_thr_h
> {
> struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
>
> - tasklet_schedule(&op->thrtsklet);
> -
> - if (bcm_rx_thr_flush(op, 0)) {
> + if (bcm_rx_thr_flush(op)) {
> hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2);
> return HRTIMER_RESTART;
> } else {
> @@ -735,23 +706,8 @@ static struct bcm_op *bcm_find_op(struct
>
> static void bcm_remove_op(struct bcm_op *op)
> {
> - if (op->tsklet.func) {
> - while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) ||
> - test_bit(TASKLET_STATE_RUN, &op->tsklet.state) ||
> - hrtimer_active(&op->timer)) {
> - hrtimer_cancel(&op->timer);
> - tasklet_kill(&op->tsklet);
> - }
> - }
> -
> - if (op->thrtsklet.func) {
> - while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) ||
> - test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) ||
> - hrtimer_active(&op->thrtimer)) {
> - hrtimer_cancel(&op->thrtimer);
> - tasklet_kill(&op->thrtsklet);
> - }
> - }
> + hrtimer_cancel(&op->timer);
> + hrtimer_cancel(&op->thrtimer);
>
> if ((op->frames) && (op->frames != &op->sframe))
> kfree(op->frames);
> @@ -979,15 +935,13 @@ static int bcm_tx_setup(struct bcm_msg_h
> op->ifindex = ifindex;
>
> /* initialize uninitialized (kzalloc) structure */
> - hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> + hrtimer_init(&op->timer, CLOCK_MONOTONIC_SOFT,
> + HRTIMER_MODE_REL);
> op->timer.function = bcm_tx_timeout_handler;
>
> - /* initialize tasklet for tx countevent notification */
> - tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet,
> - (unsigned long) op);
> -
> /* currently unused in tx_ops */
> - hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> + hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC_SOFT,
> + HRTIMER_MODE_REL);
>
> /* add this bcm_op to the list of the tx_ops */
> list_add(&op->list, &bo->tx_ops);
> @@ -1150,20 +1104,14 @@ static int bcm_rx_setup(struct bcm_msg_h
> op->rx_ifindex = ifindex;
>
> /* initialize uninitialized (kzalloc) structure */
> - hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> + hrtimer_init(&op->timer, CLOCK_MONOTONIC_SOFT,
> + HRTIMER_MODE_REL);
> op->timer.function = bcm_rx_timeout_handler;
>
> - /* initialize tasklet for rx timeout notification */
> - tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet,
> - (unsigned long) op);
> -
> - hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> + hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC_SOFT,
> + HRTIMER_MODE_REL);
> op->thrtimer.function = bcm_rx_thr_handler;
>
> - /* initialize tasklet for rx throttle handling */
> - tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet,
> - (unsigned long) op);
> -
> /* add this bcm_op to the list of the rx_ops */
> list_add(&op->list, &bo->rx_ops);
>
> @@ -1209,7 +1157,7 @@ static int bcm_rx_setup(struct bcm_msg_h
> */
> op->kt_lastmsg = 0;
> hrtimer_cancel(&op->thrtimer);
> - bcm_rx_thr_flush(op, 1);
> + bcm_rx_thr_flush(op);
> }
>
> if ((op->flags & STARTTIMER) && op->kt_ival1)
>
>
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 10/25] hrtimer: Make handling of hrtimer reprogramming and enqueuing not conditional |
| Message-ID | <ukwLG-5Ay-65@gated-at.bofh.it> |
| In reply to | #1724178 |
The hrtimer_reprogramming, remote timer enqueuing and handling of the
hrtimer_cpu_base struct member expires_next depend on the active high
resolution timers. This makes the code harder to understand.
To simplify the code, the hrtimer reprogramming is now executed
independently except for the real reprogramming part. The expires_next
stores now the first enqueued timer. Due to the adaption of the
check_target function, remote enqueuing is now only possible when the
expiry time is after the currently first expiry time independent of the
active high resolution timers.
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
---
kernel/time/hrtimer.c | 31 ++++++++++++-------------------
1 file changed, 12 insertions(+), 19 deletions(-)
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -154,10 +154,11 @@ struct hrtimer_clock_base *lock_hrtimer_
}
/*
- * With high resolution timers enabled we do not migrate the timer
- * when it is expiring before the next event on the target cpu because
- * we cannot reprogram the target cpu hardware and we would cause it
- * to fire late.
+ * We do not migrate the timer when it is expiring before the next
+ * event on the target cpu. When high resolution is enabled, we cannot
+ * reprogram the target cpu hardware and we would cause it to fire
+ * late. To keep it simple, we handle the high resolution enabled and
+ * disabled case similar.
*
* Called with cpu_base->lock of target cpu held.
*/
@@ -166,9 +167,6 @@ hrtimer_check_target(struct hrtimer *tim
{
ktime_t expires;
- if (!new_base->cpu_base->hres_active)
- return 0;
-
expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset);
return expires <= new_base->cpu_base->expires_next;
}
@@ -689,21 +687,24 @@ static void hrtimer_reprogram(struct hrt
/* Update the pointer to the next expiring timer */
hrtimer_update_next_timer(cpu_base, timer);
+ cpu_base->expires_next = expires;
/*
+ * If hres is not active, hardware does not have to be
+ * programmed yet.
+ *
* If a hang was detected in the last timer interrupt then we
* do not schedule a timer which is earlier than the expiry
* which we enforced in the hang detection. We want the system
* to make progress.
*/
- if (cpu_base->hang_detected)
+ if (!__hrtimer_hres_active(cpu_base) || cpu_base->hang_detected)
return;
/*
* Program the timer hardware. We enforce the expiry for
* events which are already in the past.
*/
- cpu_base->expires_next = expires;
tick_program_event(expires, 1);
}
@@ -943,16 +944,8 @@ void hrtimer_start_range_ns(struct hrtim
if (!leftmost)
goto unlock;
- if (!hrtimer_is_hres_active(timer)) {
- /*
- * Kick to reschedule the next tick to handle the new timer
- * on dynticks target.
- */
- if (new_base->cpu_base->nohz_active)
- wake_up_nohz_cpu(new_base->cpu_base->cpu);
- } else {
- hrtimer_reprogram(timer, new_base);
- }
+ hrtimer_reprogram(timer, new_base);
+
unlock:
unlock_hrtimer_base(timer, &flags);
}
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 14/25] hrtimer: Split out code from __hrtimer_get_next_event() for reuse |
| Message-ID | <ukwLG-5Ay-61@gated-at.bofh.it> |
| In reply to | #1724178 |
From: Anna-Maria Gleixner <anna-maria@linutronix.de>
Preparatory patch for softirq based hrtimers. No functional change.
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
---
kernel/time/hrtimer.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -454,12 +454,12 @@ static inline void hrtimer_update_next_t
}
#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
-static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base)
+static ktime_t __hrtimer_next_event_base(struct hrtimer_cpu_base *cpu_base,
+ unsigned int active,
+ ktime_t expires_next)
{
- unsigned int active = cpu_base->active_bases;
- ktime_t expires, expires_next = KTIME_MAX;
+ ktime_t expires;
- hrtimer_update_next_timer(cpu_base, NULL);
while (active) {
unsigned int id = __ffs(active);
struct hrtimer_clock_base *base;
@@ -486,6 +486,18 @@ static ktime_t __hrtimer_get_next_event(
expires_next = 0;
return expires_next;
}
+
+static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base)
+{
+ unsigned int active = cpu_base->active_bases;
+ ktime_t expires_next = KTIME_MAX;
+
+ hrtimer_update_next_timer(cpu_base, NULL);
+
+ expires_next = __hrtimer_next_event_base(cpu_base, active, expires_next);
+
+ return expires_next;
+}
#endif
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 25/25] usb/gadget/NCM: Replace tasklet with softirq hrtimer |
| Message-ID | <ukwLG-5Ay-67@gated-at.bofh.it> |
| In reply to | #1724178 |
From: Thomas Gleixner <tglx@linutronix.de>
The tx_tasklet tasklet is used in invoke the hrtimer (task_timer) in
softirq context. This can be also achieved without the tasklet but with
CLOCK_MONOTONIC_SOFT as hrtimer base.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
Cc: Felipe Balbi <balbi@kernel.org>
Cc: linux-usb@vger.kernel.org
---
drivers/usb/gadget/function/f_ncm.c | 28 ++++++----------------------
1 file changed, 6 insertions(+), 22 deletions(-)
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -77,9 +77,7 @@ struct f_ncm {
struct sk_buff *skb_tx_ndp;
u16 ndp_dgram_count;
bool timer_force_tx;
- struct tasklet_struct tx_tasklet;
struct hrtimer task_timer;
-
bool timer_stopping;
};
@@ -1154,17 +1152,15 @@ static struct sk_buff *ncm_wrap_ntb(stru
}
/*
- * This transmits the NTB if there are frames waiting.
+ * The transmit should only be run if no skb data has been sent
+ * for a certain duration.
*/
-static void ncm_tx_tasklet(unsigned long data)
+static enum hrtimer_restart ncm_tx_timeout(struct hrtimer *data)
{
- struct f_ncm *ncm = (void *)data;
-
- if (ncm->timer_stopping)
- return;
+ struct f_ncm *ncm = container_of(data, struct f_ncm, task_timer);
/* Only send if data is available. */
- if (ncm->skb_tx_data) {
+ if (!ncm->timer_stopping && ncm->skb_tx_data) {
ncm->timer_force_tx = true;
/* XXX This allowance of a NULL skb argument to ndo_start_xmit
@@ -1177,16 +1173,6 @@ static void ncm_tx_tasklet(unsigned long
ncm->timer_force_tx = false;
}
-}
-
-/*
- * The transmit should only be run if no skb data has been sent
- * for a certain duration.
- */
-static enum hrtimer_restart ncm_tx_timeout(struct hrtimer *data)
-{
- struct f_ncm *ncm = container_of(data, struct f_ncm, task_timer);
- tasklet_schedule(&ncm->tx_tasklet);
return HRTIMER_NORESTART;
}
@@ -1519,8 +1505,7 @@ static int ncm_bind(struct usb_configura
ncm->port.open = ncm_open;
ncm->port.close = ncm_close;
- tasklet_init(&ncm->tx_tasklet, ncm_tx_tasklet, (unsigned long) ncm);
- hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC_SOFT, HRTIMER_MODE_REL);
ncm->task_timer.function = ncm_tx_timeout;
DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
@@ -1629,7 +1614,6 @@ static void ncm_unbind(struct usb_config
DBG(c->cdev, "ncm unbind\n");
hrtimer_cancel(&ncm->task_timer);
- tasklet_kill(&ncm->tx_tasklet);
ncm_string_defs[0].id = 0;
usb_free_all_descriptors(f);
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 03/25] hrtimer: Fix kerneldoc for struct hrtimer_cpu_base |
| Message-ID | <ukwLG-5Ay-69@gated-at.bofh.it> |
| In reply to | #1724178 |
From: Anna-Maria Gleixner <anna-maria@linutronix.de>
The sequence '/**' marks the start of a struct description. Add the
missing second asterisk. While at it adapt the ordering of the struct
members to the struct definition and document the purpose of
expires_next more precisely.
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
---
include/linux/hrtimer.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -144,7 +144,7 @@ enum hrtimer_base_type {
HRTIMER_MAX_CLOCK_BASES,
};
-/*
+/**
* struct hrtimer_cpu_base - the per cpu clock bases
* @lock: lock protecting the base and associated clock bases
* and timers
@@ -155,12 +155,12 @@ enum hrtimer_base_type {
* @clock_was_set_seq: Sequence counter of clock was set events
* @migration_enabled: The migration of hrtimers to other cpus is enabled
* @nohz_active: The nohz functionality is enabled
- * @expires_next: absolute time of the next event which was scheduled
- * via clock_set_next_event()
- * @next_timer: Pointer to the first expiring timer
* @in_hrtirq: hrtimer_interrupt() is currently executing
* @hres_active: State of high resolution mode
* @hang_detected: The last hrtimer interrupt detected a hang
+ * @expires_next: absolute time of the next event, is required for remote
+ * hrtimer enqueue
+ * @next_timer: Pointer to the first expiring timer
* @nr_events: Total number of hrtimer interrupt events
* @nr_retries: Total number of hrtimer interrupt retries
* @nr_hangs: Total number of hrtimer interrupt hangs
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:30 +0200 |
| Subject | [PATCH 09/25] hrtimer: Reduce conditional code (hrtimer_reprogram()) |
| Message-ID | <ukwLG-5Ay-71@gated-at.bofh.it> |
| In reply to | #1724178 |
The hrtimer_reprogram() is currently required only when
CONFIG_HIGH_RES_TIMERS is set. Additional bitfields of hrtimer_cpu_base
struct are high resolution timer specific as well.
To simplify the hrtimer code, the behaviour of CONFIG_HIGH_RES_TIMERS and
!CONFIG_HIGH_RES_TIMERS should be similar. As preparation for this, the
function hrtimer_reprogram() and required hrtimer_cpu_base struct members
are moved outside the conditional area.
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
---
include/linux/hrtimer.h | 6 +-
kernel/time/hrtimer.c | 131 +++++++++++++++++++++++-------------------------
2 files changed, 66 insertions(+), 71 deletions(-)
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -180,10 +180,10 @@ struct hrtimer_cpu_base {
unsigned int clock_was_set_seq;
bool migration_enabled;
bool nohz_active;
- unsigned int hres_active : 1;
-#ifdef CONFIG_HIGH_RES_TIMERS
- unsigned int in_hrtirq : 1,
+ unsigned int hres_active : 1,
+ in_hrtirq : 1,
hang_detected : 1;
+#ifdef CONFIG_HIGH_RES_TIMERS
unsigned int nr_events;
unsigned int nr_retries;
unsigned int nr_hangs;
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -449,13 +449,13 @@ static inline void debug_deactivate(stru
trace_hrtimer_cancel(timer);
}
-#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
static inline void hrtimer_update_next_timer(struct hrtimer_cpu_base *cpu_base,
struct hrtimer *timer)
{
cpu_base->next_timer = timer;
}
+#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base)
{
unsigned int active = cpu_base->active_bases;
@@ -582,68 +582,6 @@ hrtimer_force_reprogram(struct hrtimer_c
}
/*
- * When a timer is enqueued and expires earlier than the already enqueued
- * timers, we have to check, whether it expires earlier than the timer for
- * which the clock event device was armed.
- *
- * Called with interrupts disabled and base->cpu_base.lock held
- */
-static void hrtimer_reprogram(struct hrtimer *timer,
- struct hrtimer_clock_base *base)
-{
- struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
- ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
-
- WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0);
-
- /*
- * If the timer is not on the current cpu, we cannot reprogram
- * the other cpus clock event device.
- */
- if (base->cpu_base != cpu_base)
- return;
-
- /*
- * If the hrtimer interrupt is running, then it will
- * reevaluate the clock bases and reprogram the clock event
- * device. The callbacks are always executed in hard interrupt
- * context so we don't need an extra check for a running
- * callback.
- */
- if (cpu_base->in_hrtirq)
- return;
-
- /*
- * CLOCK_REALTIME timer might be requested with an absolute
- * expiry time which is less than base->offset. Set it to 0.
- */
- if (expires < 0)
- expires = 0;
-
- if (expires >= cpu_base->expires_next)
- return;
-
- /* Update the pointer to the next expiring timer */
- hrtimer_update_next_timer(cpu_base, timer);
-
- /*
- * If a hang was detected in the last timer interrupt then we
- * do not schedule a timer which is earlier than the expiry
- * which we enforced in the hang detection. We want the system
- * to make progress.
- */
- if (cpu_base->hang_detected)
- return;
-
- /*
- * Program the timer hardware. We enforce the expiry for
- * events which are already in the past.
- */
- cpu_base->expires_next = expires;
- tick_program_event(expires, 1);
-}
-
-/*
* Retrigger next event is called after clock was set
*
* Called with interrupts disabled via on_each_cpu()
@@ -703,16 +641,73 @@ static inline int hrtimer_is_hres_enable
static inline void hrtimer_switch_to_hres(void) { }
static inline void
hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
-static inline int hrtimer_reprogram(struct hrtimer *timer,
- struct hrtimer_clock_base *base)
-{
- return 0;
-}
static inline void retrigger_next_event(void *arg) { }
#endif /* CONFIG_HIGH_RES_TIMERS */
/*
+ * When a timer is enqueued and expires earlier than the already enqueued
+ * timers, we have to check, whether it expires earlier than the timer for
+ * which the clock event device was armed.
+ *
+ * Called with interrupts disabled and base->cpu_base.lock held
+ */
+static void hrtimer_reprogram(struct hrtimer *timer,
+ struct hrtimer_clock_base *base)
+{
+ struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
+ ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
+
+ WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0);
+
+ /*
+ * If the timer is not on the current cpu, we cannot reprogram
+ * the other cpus clock event device.
+ */
+ if (base->cpu_base != cpu_base)
+ return;
+
+ /*
+ * If the hrtimer interrupt is running, then it will
+ * reevaluate the clock bases and reprogram the clock event
+ * device. The callbacks are always executed in hard interrupt
+ * context so we don't need an extra check for a running
+ * callback.
+ */
+ if (cpu_base->in_hrtirq)
+ return;
+
+ /*
+ * CLOCK_REALTIME timer might be requested with an absolute
+ * expiry time which is less than base->offset. Set it to 0.
+ */
+ if (expires < 0)
+ expires = 0;
+
+ if (expires >= cpu_base->expires_next)
+ return;
+
+ /* Update the pointer to the next expiring timer */
+ hrtimer_update_next_timer(cpu_base, timer);
+
+ /*
+ * If a hang was detected in the last timer interrupt then we
+ * do not schedule a timer which is earlier than the expiry
+ * which we enforced in the hang detection. We want the system
+ * to make progress.
+ */
+ if (cpu_base->hang_detected)
+ return;
+
+ /*
+ * Program the timer hardware. We enforce the expiry for
+ * events which are already in the past.
+ */
+ cpu_base->expires_next = expires;
+ tick_program_event(expires, 1);
+}
+
+/*
* Clock realtime was set
*
* Change the offset of the realtime clock vs. the monotonic
[toc] | [prev] | [next] | [standalone]
| From | Anna-Maria Gleixner <anna-maria@linutronix.de> |
|---|---|
| Date | 2017-08-31 14:40 +0200 |
| Message-ID | <ukwVk-5Dr-21@gated-at.bofh.it> |
| In reply to | #1724178 |
I'm sorry for the typo in the email address!
Anna-Maria
On Thu, 31 Aug 2017, Anna-Maria Gleixner wrote:
> There are quite some places in the kernel which use a combination of
> hrtimers and tasklets to make use of the precise expiry of hrtimers, which
> schedule a tasklet to bring the actual function into softirq context.
>
> This was introduced when the previous hrtimer softirq code was
> removed. That code was implemented by expiring the timer in hard irq
> context and then deferring the execution of the callback into softirq
> context. That caused a lot of pointless shuffling between the rbtree and a
> linked list.
>
> In recent discussions it turned out that more potential users of hrtimers
> in softirq context might come up. Aside of that the RT patches need this
> functionality as well to defer hrtimers into softirq context if their
> callbacks are not interrupt safe on RT.
>
> This series implements a new approach by adding SOFT_* clock ids and
> instead of doing the list shuffle, timers started with these clock ids are
> put into separate soft expiry hrtimer queues. These queues are evaluated
> only when the hardirq context detects that the first expiring timer in the
> softirq queues has expired. That makes the overhead in the hardirq context
> minimal.
>
> The series reworks the code to reuse as much as possible from the existing
> facilities for the new softirq hrtimers and integrates them with all
> flavours of hrtimers (HIGH_RES=y/n - NOHZ=y/n).
>
> To achieve this quite some of the conditionals in the existing code are
> removed for the price of adding some pointless data and state tracking to
> the HIGH_RES=n case. That's minimal, but well worth it as it increases the
> readability and maintainability of the code.
>
> The first part of the series implements the new functionality and the
> second part converts the hrtimer/tasklet users to make use of it and
> removes struct hrtimer_tasklet and the surrounding helper functions.
>
> This series is available from git as well:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/bigeasy/linux-hrtimer.git soft_hrtimer
> https://git.kernel.org/bigeasy/linux-hrtimer/h/soft_hrtimer
>
>
> Thanks,
>
> Anna-Maria
>
> ---
> drivers/net/usb/cdc_ncm.c | 37 +-
> drivers/net/wireless/mac80211_hwsim.c | 44 +-
> drivers/usb/gadget/function/f_ncm.c | 28 -
> include/linux/hrtimer.h | 76 ++---
> include/linux/interrupt.h | 25 -
> include/linux/usb/cdc_ncm.h | 2
> include/net/xfrm.h | 2
> kernel/softirq.c | 51 ---
> kernel/time/hrtimer.c | 513 +++++++++++++++++++++-------------
> net/can/bcm.c | 150 +++------
> net/xfrm/xfrm_state.c | 29 +
> sound/drivers/dummy.c | 16 -
> 12 files changed, 484 insertions(+), 489 deletions(-)
>
>
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web