Updates for timers, timekeeping and drivers:

- Core:
 
    - The timer_shutdown[_sync]() infrastructure:
 
      Tearing down timers can be tedious when there are circular
      dependencies to other things which need to be torn down. A prime
      example is timer and workqueue where the timer schedules work and the
      work arms the timer.
 
      What needs to prevented is that pending work which is drained via
      destroy_workqueue() does not rearm the previously shutdown
      timer. Nothing in that shutdown sequence relies on the timer being
      functional.
 
      The conclusion was that the semantics of timer_shutdown_sync() should
      be:
 
 	- timer is not enqueued
     	- timer callback is not running
     	- timer cannot be rearmed
 
      Preventing the rearming of shutdown timers is done by discarding rearm
      attempts silently. A warning for the case that a rearm attempt of a
      shutdown timer is detected would not be really helpful because it's
      entirely unclear how it should be acted upon. The only way to address
      such a case is to add 'if (in_shutdown)' conditionals all over the
      place. This is error prone and in most cases of teardown not required
      all.
 
    - The real fix for the bluetooth HCI teardown based on
      timer_shutdown_sync().
 
      A larger scale conversion to timer_shutdown_sync() is work in
      progress.
 
    - Consolidation of VDSO time namespace helper functions
 
    - Small fixes for timer and timerqueue
 
  - Drivers:
 
    - Prevent integer overflow on the XGene-1 TVAL register which causes
      an never ending interrupt storm.
 
    - The usual set of new device tree bindings
 
    - Small fixes and improvements all over the place
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmOUuC0THHRnbHhAbGlu
 dXRyb25peC5kZQAKCRCmGPVMDXSYodpZD/9kCDi009n65QFF1J4kE5aZuABbRMtO
 7sy66fJpDyB/MtcbPPH29uzQUEs1VMTQVB+ZM+7e1YGoxSWuSTzeoFH+yK1w4tEZ
 VPbOcvUEjG0esKUehwYFeOjSnIjy6M1Y41aOUaDnq00/azhfTrzLxQA1BbbFbkpw
 S7u2hllbyRJ8KdqQyV9cVpXmze6fcpdtNhdQeoA7qQCsSPnJ24MSpZ/PG9bAovq8
 75IRROT7CQRd6AMKAVpA9Ov8ak9nbY3EgQmoKcp5ZXfXz8kD3nHky9Lste7djgYB
 U085Vwcelt39V5iXevDFfzrBYRUqrMKOXIf2xnnoDNeF5Jlj5gChSNVZwTLO38wu
 RFEVCjCjuC41GQJWSck9LRSYdriW/htVbEE8JLc6uzUJGSyjshgJRn/PK4HjpiLY
 AvH2rd4rAap/rjDKvfWvBqClcfL7pyBvavgJeyJ8oXyQjHrHQwapPcsMFBm0Cky5
 soF0Lr3hIlQ9u+hwUuFdNZkY9mOg09g9ImEjW1AZTKY0DfJMc5JAGjjSCfuopVUN
 Uf/qqcUeQPSEaC+C9xiFs0T3svYFxBqpgPv4B6t8zAnozon9fyZs+lv5KdRg4X77
 qX395qc6PaOSQlA7gcxVw3vjCPd0+hljXX84BORP7z+uzcsomvIH1MxJepIHmgaJ
 JrYbSZ5qzY5TTA==
 =JlDe
 -----END PGP SIGNATURE-----

Merge tag 'timers-core-2022-12-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer updates from Thomas Gleixner:
 "Updates for timers, timekeeping and drivers:

  Core:

   - The timer_shutdown[_sync]() infrastructure:

     Tearing down timers can be tedious when there are circular
     dependencies to other things which need to be torn down. A prime
     example is timer and workqueue where the timer schedules work and
     the work arms the timer.

     What needs to prevented is that pending work which is drained via
     destroy_workqueue() does not rearm the previously shutdown timer.
     Nothing in that shutdown sequence relies on the timer being
     functional.

     The conclusion was that the semantics of timer_shutdown_sync()
     should be:
	- timer is not enqueued
    	- timer callback is not running
    	- timer cannot be rearmed

     Preventing the rearming of shutdown timers is done by discarding
     rearm attempts silently.

     A warning for the case that a rearm attempt of a shutdown timer is
     detected would not be really helpful because it's entirely unclear
     how it should be acted upon. The only way to address such a case is
     to add 'if (in_shutdown)' conditionals all over the place. This is
     error prone and in most cases of teardown not required all.

   - The real fix for the bluetooth HCI teardown based on
     timer_shutdown_sync().

     A larger scale conversion to timer_shutdown_sync() is work in
     progress.

   - Consolidation of VDSO time namespace helper functions

   - Small fixes for timer and timerqueue

  Drivers:

   - Prevent integer overflow on the XGene-1 TVAL register which causes
     an never ending interrupt storm.

   - The usual set of new device tree bindings

   - Small fixes and improvements all over the place"

* tag 'timers-core-2022-12-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (34 commits)
  dt-bindings: timer: renesas,cmt: Add r8a779g0 CMT support
  dt-bindings: timer: renesas,tmu: Add r8a779g0 support
  clocksource/drivers/arm_arch_timer: Use kstrtobool() instead of strtobool()
  clocksource/drivers/timer-ti-dm: Fix missing clk_disable_unprepare in dmtimer_systimer_init_clock()
  clocksource/drivers/timer-ti-dm: Clear settings on probe and free
  clocksource/drivers/timer-ti-dm: Make timer_get_irq static
  clocksource/drivers/timer-ti-dm: Fix warning for omap_timer_match
  clocksource/drivers/arm_arch_timer: Fix XGene-1 TVAL register math error
  clocksource/drivers/timer-npcm7xx: Enable timer 1 clock before use
  dt-bindings: timer: nuvoton,npcm7xx-timer: Allow specifying all clocks
  dt-bindings: timer: rockchip: Add rockchip,rk3128-timer
  clockevents: Repair kernel-doc for clockevent_delta2ns()
  clocksource/drivers/ingenic-ost: Define pm functions properly in platform_driver struct
  clocksource/drivers/sh_cmt: Access registers according to spec
  vdso/timens: Refactor copy-pasted find_timens_vvar_page() helper into one copy
  Bluetooth: hci_qca: Fix the teardown problem for real
  timers: Update the documentation to reflect on the new timer_shutdown() API
  timers: Provide timer_shutdown[_sync]()
  timers: Add shutdown mechanism to the internal functions
  timers: Split [try_to_]del_timer[_sync]() to prepare for shutdown mode
  ...
This commit is contained in:
Linus Torvalds 2022-12-12 12:52:02 -08:00
commit 0a1d4434db
35 changed files with 530 additions and 298 deletions

View File

@ -1858,7 +1858,7 @@ unloaded. After a given module has been unloaded, any attempt to call
one of its functions results in a segmentation fault. The module-unload one of its functions results in a segmentation fault. The module-unload
functions must therefore cancel any delayed calls to loadable-module functions must therefore cancel any delayed calls to loadable-module
functions, for example, any outstanding mod_timer() must be dealt functions, for example, any outstanding mod_timer() must be dealt
with via del_timer_sync() or similar. with via timer_shutdown_sync() or similar.
Unfortunately, there is no way to cancel an RCU callback; once you Unfortunately, there is no way to cancel an RCU callback; once you
invoke call_rcu(), the callback function is eventually going to be invoke call_rcu(), the callback function is eventually going to be

View File

@ -191,7 +191,7 @@ Here is a sample module which implements a basic per cpu counter using
static void __exit test_exit(void) static void __exit test_exit(void)
{ {
del_timer_sync(&test_timer); timer_shutdown_sync(&test_timer);
} }
module_init(test_init); module_init(test_init);

View File

@ -25,7 +25,13 @@ properties:
- description: The timer interrupt of timer 0 - description: The timer interrupt of timer 0
clocks: clocks:
maxItems: 1 items:
- description: The reference clock for timer 0
- description: The reference clock for timer 1
- description: The reference clock for timer 2
- description: The reference clock for timer 3
- description: The reference clock for timer 4
minItems: 1
required: required:
- compatible - compatible

View File

@ -102,12 +102,14 @@ properties:
- enum: - enum:
- renesas,r8a779a0-cmt0 # 32-bit CMT0 on R-Car V3U - renesas,r8a779a0-cmt0 # 32-bit CMT0 on R-Car V3U
- renesas,r8a779f0-cmt0 # 32-bit CMT0 on R-Car S4-8 - renesas,r8a779f0-cmt0 # 32-bit CMT0 on R-Car S4-8
- renesas,r8a779g0-cmt0 # 32-bit CMT0 on R-Car V4H
- const: renesas,rcar-gen4-cmt0 # 32-bit CMT0 on R-Car Gen4 - const: renesas,rcar-gen4-cmt0 # 32-bit CMT0 on R-Car Gen4
- items: - items:
- enum: - enum:
- renesas,r8a779a0-cmt1 # 48-bit CMT on R-Car V3U - renesas,r8a779a0-cmt1 # 48-bit CMT on R-Car V3U
- renesas,r8a779f0-cmt1 # 48-bit CMT on R-Car S4-8 - renesas,r8a779f0-cmt1 # 48-bit CMT on R-Car S4-8
- renesas,r8a779g0-cmt1 # 48-bit CMT on R-Car V4H
- const: renesas,rcar-gen4-cmt1 # 48-bit CMT on R-Car Gen4 - const: renesas,rcar-gen4-cmt1 # 48-bit CMT on R-Car Gen4
reg: reg:

View File

@ -38,6 +38,7 @@ properties:
- renesas,tmu-r8a77995 # R-Car D3 - renesas,tmu-r8a77995 # R-Car D3
- renesas,tmu-r8a779a0 # R-Car V3U - renesas,tmu-r8a779a0 # R-Car V3U
- renesas,tmu-r8a779f0 # R-Car S4-8 - renesas,tmu-r8a779f0 # R-Car S4-8
- renesas,tmu-r8a779g0 # R-Car V4H
- const: renesas,tmu - const: renesas,tmu
reg: reg:

View File

@ -18,6 +18,7 @@ properties:
- enum: - enum:
- rockchip,rv1108-timer - rockchip,rv1108-timer
- rockchip,rk3036-timer - rockchip,rk3036-timer
- rockchip,rk3128-timer
- rockchip,rk3188-timer - rockchip,rk3188-timer
- rockchip,rk3228-timer - rockchip,rk3228-timer
- rockchip,rk3229-timer - rockchip,rk3229-timer

View File

@ -967,7 +967,7 @@ you might do the following::
while (list) { while (list) {
struct foo *next = list->next; struct foo *next = list->next;
del_timer(&list->timer); timer_delete(&list->timer);
kfree(list); kfree(list);
list = next; list = next;
} }
@ -981,7 +981,7 @@ the lock after we spin_unlock_bh(), and then try to free
the element (which has already been freed!). the element (which has already been freed!).
This can be avoided by checking the result of This can be avoided by checking the result of
del_timer(): if it returns 1, the timer has been deleted. timer_delete(): if it returns 1, the timer has been deleted.
If 0, it means (in this case) that it is currently running, so we can If 0, it means (in this case) that it is currently running, so we can
do:: do::
@ -990,7 +990,7 @@ do::
while (list) { while (list) {
struct foo *next = list->next; struct foo *next = list->next;
if (!del_timer(&list->timer)) { if (!timer_delete(&list->timer)) {
/* Give timer a chance to delete this */ /* Give timer a chance to delete this */
spin_unlock_bh(&list_lock); spin_unlock_bh(&list_lock);
goto retry; goto retry;
@ -1005,9 +1005,12 @@ do::
Another common problem is deleting timers which restart themselves (by Another common problem is deleting timers which restart themselves (by
calling add_timer() at the end of their timer function). calling add_timer() at the end of their timer function).
Because this is a fairly common case which is prone to races, you should Because this is a fairly common case which is prone to races, you should
use del_timer_sync() (``include/linux/timer.h``) to use timer_delete_sync() (``include/linux/timer.h``) to handle this case.
handle this case. It returns the number of times the timer had to be
deleted before we finally stopped it from adding itself back in. Before freeing a timer, timer_shutdown() or timer_shutdown_sync() should be
called which will keep it from being rearmed. Any subsequent attempt to
rearm the timer will be silently ignored by the core code.
Locking Speed Locking Speed
============= =============
@ -1335,7 +1338,7 @@ lock.
- kfree() - kfree()
- add_timer() and del_timer() - add_timer() and timer_delete()
Mutex API reference Mutex API reference
=================== ===================

View File

@ -118,7 +118,7 @@ existing timer wheel code, as it is mature and well suited. Sharing code
was not really a win, due to the different data structures. Also, the was not really a win, due to the different data structures. Also, the
hrtimer functions now have clearer behavior and clearer names - such as hrtimer functions now have clearer behavior and clearer names - such as
hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly
equivalent to del_timer() and del_timer_sync()] - so there's no direct equivalent to timer_delete() and timer_delete_sync()] - so there's no direct
1:1 mapping between them on the algorithmic level, and thus no real 1:1 mapping between them on the algorithmic level, and thus no real
potential for code sharing either. potential for code sharing either.

View File

@ -990,7 +990,7 @@ potreste fare come segue::
while (list) { while (list) {
struct foo *next = list->next; struct foo *next = list->next;
del_timer(&list->timer); timer_delete(&list->timer);
kfree(list); kfree(list);
list = next; list = next;
} }
@ -1003,7 +1003,7 @@ e prenderà il *lock* solo dopo spin_unlock_bh(), e cercherà
di eliminare il suo oggetto (che però è già stato eliminato). di eliminare il suo oggetto (che però è già stato eliminato).
Questo può essere evitato controllando il valore di ritorno di Questo può essere evitato controllando il valore di ritorno di
del_timer(): se ritorna 1, il temporizzatore è stato già timer_delete(): se ritorna 1, il temporizzatore è stato già
rimosso. Se 0, significa (in questo caso) che il temporizzatore è in rimosso. Se 0, significa (in questo caso) che il temporizzatore è in
esecuzione, quindi possiamo fare come segue:: esecuzione, quindi possiamo fare come segue::
@ -1012,7 +1012,7 @@ esecuzione, quindi possiamo fare come segue::
while (list) { while (list) {
struct foo *next = list->next; struct foo *next = list->next;
if (!del_timer(&list->timer)) { if (!timer_delete(&list->timer)) {
/* Give timer a chance to delete this */ /* Give timer a chance to delete this */
spin_unlock_bh(&list_lock); spin_unlock_bh(&list_lock);
goto retry; goto retry;
@ -1026,10 +1026,8 @@ esecuzione, quindi possiamo fare come segue::
Un altro problema è l'eliminazione dei temporizzatori che si riavviano Un altro problema è l'eliminazione dei temporizzatori che si riavviano
da soli (chiamando add_timer() alla fine della loro esecuzione). da soli (chiamando add_timer() alla fine della loro esecuzione).
Dato che questo è un problema abbastanza comune con una propensione Dato che questo è un problema abbastanza comune con una propensione
alle corse critiche, dovreste usare del_timer_sync() alle corse critiche, dovreste usare timer_delete_sync()
(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il (``include/linux/timer.h``) per gestire questo caso.
numero di volte che il temporizzatore è stato interrotto prima che
fosse in grado di fermarlo senza che si riavviasse.
Velocità della sincronizzazione Velocità della sincronizzazione
=============================== ===============================
@ -1374,7 +1372,7 @@ contesto, o trattenendo un qualsiasi *lock*.
- kfree() - kfree()
- add_timer() e del_timer() - add_timer() e timer_delete()
Riferimento per l'API dei Mutex Riferimento per l'API dei Mutex
=============================== ===============================

View File

@ -185,7 +185,7 @@ UP之间没有不同的行为在你的架构的 ``local.h`` 中包括 ``asm-g
static void __exit test_exit(void) static void __exit test_exit(void)
{ {
del_timer_sync(&test_timer); timer_shutdown_sync(&test_timer);
} }
module_init(test_init); module_init(test_init);

View File

@ -90,7 +90,7 @@ static void __init spear_clocksource_init(void)
200, 16, clocksource_mmio_readw_up); 200, 16, clocksource_mmio_readw_up);
} }
static inline void timer_shutdown(struct clock_event_device *evt) static inline void spear_timer_shutdown(struct clock_event_device *evt)
{ {
u16 val = readw(gpt_base + CR(CLKEVT)); u16 val = readw(gpt_base + CR(CLKEVT));
@ -101,7 +101,7 @@ static inline void timer_shutdown(struct clock_event_device *evt)
static int spear_shutdown(struct clock_event_device *evt) static int spear_shutdown(struct clock_event_device *evt)
{ {
timer_shutdown(evt); spear_timer_shutdown(evt);
return 0; return 0;
} }
@ -111,7 +111,7 @@ static int spear_set_oneshot(struct clock_event_device *evt)
u16 val; u16 val;
/* stop the timer */ /* stop the timer */
timer_shutdown(evt); spear_timer_shutdown(evt);
val = readw(gpt_base + CR(CLKEVT)); val = readw(gpt_base + CR(CLKEVT));
val |= CTRL_ONE_SHOT; val |= CTRL_ONE_SHOT;
@ -126,7 +126,7 @@ static int spear_set_periodic(struct clock_event_device *evt)
u16 val; u16 val;
/* stop the timer */ /* stop the timer */
timer_shutdown(evt); spear_timer_shutdown(evt);
period = clk_get_rate(gpt_clk) / HZ; period = clk_get_rate(gpt_clk) / HZ;
period >>= CTRL_PRESCALER16; period >>= CTRL_PRESCALER16;

View File

@ -151,28 +151,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
mmap_read_unlock(mm); mmap_read_unlock(mm);
return 0; return 0;
} }
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
if (likely(vma->vm_mm == current->mm))
return current->nsproxy->time_ns->vvar_page;
/*
* VM_PFNMAP | VM_IO protect .fault() handler from being called
* through interfaces like /proc/$pid/mem or
* process_vm_{readv,writev}() as long as there's no .access()
* in special_mapping_vmops.
* For more details check_vma_flags() and __access_remote_vm()
*/
WARN(1, "vvar_page accessed remotely");
return NULL;
}
#else
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
return NULL;
}
#endif #endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,

View File

@ -129,28 +129,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
return 0; return 0;
} }
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
if (likely(vma->vm_mm == current->mm))
return current->nsproxy->time_ns->vvar_page;
/*
* VM_PFNMAP | VM_IO protect .fault() handler from being called
* through interfaces like /proc/$pid/mem or
* process_vm_{readv,writev}() as long as there's no .access()
* in special_mapping_vmops.
* For more details check_vma_flags() and __access_remote_vm()
*/
WARN(1, "vvar_page accessed remotely");
return NULL;
}
#else
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
return NULL;
}
#endif #endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,

View File

@ -137,28 +137,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
mmap_read_unlock(mm); mmap_read_unlock(mm);
return 0; return 0;
} }
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
if (likely(vma->vm_mm == current->mm))
return current->nsproxy->time_ns->vvar_page;
/*
* VM_PFNMAP | VM_IO protect .fault() handler from being called
* through interfaces like /proc/$pid/mem or
* process_vm_{readv,writev}() as long as there's no .access()
* in special_mapping_vmops.
* For more details check_vma_flags() and __access_remote_vm()
*/
WARN(1, "vvar_page accessed remotely");
return NULL;
}
#else
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
return NULL;
}
#endif #endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,

View File

@ -44,21 +44,6 @@ struct vdso_data *arch_get_vdso_data(void *vvar_page)
return (struct vdso_data *)(vvar_page); return (struct vdso_data *)(vvar_page);
} }
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
if (likely(vma->vm_mm == current->mm))
return current->nsproxy->time_ns->vvar_page;
/*
* VM_PFNMAP | VM_IO protect .fault() handler from being called
* through interfaces like /proc/$pid/mem or
* process_vm_{readv,writev}() as long as there's no .access()
* in special_mapping_vmops().
* For more details check_vma_flags() and __access_remote_vm()
*/
WARN(1, "vvar_page accessed remotely");
return NULL;
}
/* /*
* The VVAR page layout depends on whether a task belongs to the root or * The VVAR page layout depends on whether a task belongs to the root or
* non-root time namespace. Whenever a task changes its namespace, the VVAR * non-root time namespace. Whenever a task changes its namespace, the VVAR
@ -84,11 +69,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
mmap_read_unlock(mm); mmap_read_unlock(mm);
return 0; return 0;
} }
#else
static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
return NULL;
}
#endif #endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,

View File

@ -98,24 +98,6 @@ static int vdso_mremap(const struct vm_special_mapping *sm,
} }
#ifdef CONFIG_TIME_NS #ifdef CONFIG_TIME_NS
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
if (likely(vma->vm_mm == current->mm))
return current->nsproxy->time_ns->vvar_page;
/*
* VM_PFNMAP | VM_IO protect .fault() handler from being called
* through interfaces like /proc/$pid/mem or
* process_vm_{readv,writev}() as long as there's no .access()
* in special_mapping_vmops().
* For more details check_vma_flags() and __access_remote_vm()
*/
WARN(1, "vvar_page accessed remotely");
return NULL;
}
/* /*
* The vvar page layout depends on whether a task belongs to the root or * The vvar page layout depends on whether a task belongs to the root or
* non-root time namespace. Whenever a task changes its namespace, the VVAR * non-root time namespace. Whenever a task changes its namespace, the VVAR
@ -140,11 +122,6 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
return 0; return 0;
} }
#else
static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
return NULL;
}
#endif #endif
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,

View File

@ -696,9 +696,15 @@ static int qca_close(struct hci_uart *hu)
skb_queue_purge(&qca->tx_wait_q); skb_queue_purge(&qca->tx_wait_q);
skb_queue_purge(&qca->txq); skb_queue_purge(&qca->txq);
skb_queue_purge(&qca->rx_memdump_q); skb_queue_purge(&qca->rx_memdump_q);
/*
* Shut the timers down so they can't be rearmed when
* destroy_workqueue() drains pending work which in turn might try
* to arm a timer. After shutdown rearm attempts are silently
* ignored by the timer core code.
*/
timer_shutdown_sync(&qca->tx_idle_timer);
timer_shutdown_sync(&qca->wake_retrans_timer);
destroy_workqueue(qca->workqueue); destroy_workqueue(qca->workqueue);
del_timer_sync(&qca->tx_idle_timer);
del_timer_sync(&qca->wake_retrans_timer);
qca->hu = NULL; qca->hu = NULL;
kfree_skb(qca->rx_skb); kfree_skb(qca->rx_skb);

View File

@ -155,7 +155,7 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
out: out:
if (!priv->response_length) { if (!priv->response_length) {
*off = 0; *off = 0;
del_singleshot_timer_sync(&priv->user_read_timer); del_timer_sync(&priv->user_read_timer);
flush_work(&priv->timeout_work); flush_work(&priv->timeout_work);
} }
mutex_unlock(&priv->buffer_mutex); mutex_unlock(&priv->buffer_mutex);
@ -262,7 +262,7 @@ __poll_t tpm_common_poll(struct file *file, poll_table *wait)
void tpm_common_release(struct file *file, struct file_priv *priv) void tpm_common_release(struct file *file, struct file_priv *priv)
{ {
flush_work(&priv->async_work); flush_work(&priv->async_work);
del_singleshot_timer_sync(&priv->user_read_timer); del_timer_sync(&priv->user_read_timer);
flush_work(&priv->timeout_work); flush_work(&priv->timeout_work);
file->private_data = NULL; file->private_data = NULL;
priv->response_length = 0; priv->response_length = 0;

View File

@ -18,6 +18,7 @@
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/clocksource_ids.h> #include <linux/clocksource_ids.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kstrtox.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/io.h> #include <linux/io.h>
@ -97,7 +98,7 @@ static bool evtstrm_enable __ro_after_init = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EV
static int __init early_evtstrm_cfg(char *buf) static int __init early_evtstrm_cfg(char *buf)
{ {
return strtobool(buf, &evtstrm_enable); return kstrtobool(buf, &evtstrm_enable);
} }
early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg); early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg);
@ -687,8 +688,8 @@ static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id)
return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt);
} }
static __always_inline int timer_shutdown(const int access, static __always_inline int arch_timer_shutdown(const int access,
struct clock_event_device *clk) struct clock_event_device *clk)
{ {
unsigned long ctrl; unsigned long ctrl;
@ -701,22 +702,22 @@ static __always_inline int timer_shutdown(const int access,
static int arch_timer_shutdown_virt(struct clock_event_device *clk) static int arch_timer_shutdown_virt(struct clock_event_device *clk)
{ {
return timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk); return arch_timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk);
} }
static int arch_timer_shutdown_phys(struct clock_event_device *clk) static int arch_timer_shutdown_phys(struct clock_event_device *clk)
{ {
return timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); return arch_timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk);
} }
static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk) static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk)
{ {
return timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); return arch_timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk);
} }
static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk) static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk)
{ {
return timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); return arch_timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk);
} }
static __always_inline void set_next_event(const int access, unsigned long evt, static __always_inline void set_next_event(const int access, unsigned long evt,

View File

@ -141,7 +141,7 @@ static int __init ingenic_ost_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int __maybe_unused ingenic_ost_suspend(struct device *dev) static int ingenic_ost_suspend(struct device *dev)
{ {
struct ingenic_ost *ost = dev_get_drvdata(dev); struct ingenic_ost *ost = dev_get_drvdata(dev);
@ -150,14 +150,14 @@ static int __maybe_unused ingenic_ost_suspend(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused ingenic_ost_resume(struct device *dev) static int ingenic_ost_resume(struct device *dev)
{ {
struct ingenic_ost *ost = dev_get_drvdata(dev); struct ingenic_ost *ost = dev_get_drvdata(dev);
return clk_enable(ost->clk); return clk_enable(ost->clk);
} }
static const struct dev_pm_ops __maybe_unused ingenic_ost_pm_ops = { static const struct dev_pm_ops ingenic_ost_pm_ops = {
/* _noirq: We want the OST clock to be gated last / ungated first */ /* _noirq: We want the OST clock to be gated last / ungated first */
.suspend_noirq = ingenic_ost_suspend, .suspend_noirq = ingenic_ost_suspend,
.resume_noirq = ingenic_ost_resume, .resume_noirq = ingenic_ost_resume,
@ -181,9 +181,7 @@ static const struct of_device_id ingenic_ost_of_match[] = {
static struct platform_driver ingenic_ost_driver = { static struct platform_driver ingenic_ost_driver = {
.driver = { .driver = {
.name = "ingenic-ost", .name = "ingenic-ost",
#ifdef CONFIG_PM_SUSPEND .pm = pm_sleep_ptr(&ingenic_ost_pm_ops),
.pm = &ingenic_ost_pm_ops,
#endif
.of_match_table = ingenic_ost_of_match, .of_match_table = ingenic_ost_of_match,
}, },
}; };

View File

@ -13,6 +13,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
@ -116,6 +117,7 @@ struct sh_cmt_device {
void __iomem *mapbase; void __iomem *mapbase;
struct clk *clk; struct clk *clk;
unsigned long rate; unsigned long rate;
unsigned int reg_delay;
raw_spinlock_t lock; /* Protect the shared start/stop register */ raw_spinlock_t lock; /* Protect the shared start/stop register */
@ -247,10 +249,17 @@ static inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, u32 value) static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, u32 value)
{ {
if (ch->iostart) u32 old_value = sh_cmt_read_cmstr(ch);
ch->cmt->info->write_control(ch->iostart, 0, value);
else if (value != old_value) {
ch->cmt->info->write_control(ch->cmt->mapbase, 0, value); if (ch->iostart) {
ch->cmt->info->write_control(ch->iostart, 0, value);
udelay(ch->cmt->reg_delay);
} else {
ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
udelay(ch->cmt->reg_delay);
}
}
} }
static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch) static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
@ -260,7 +269,12 @@ static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, u32 value) static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, u32 value)
{ {
ch->cmt->info->write_control(ch->ioctrl, CMCSR, value); u32 old_value = sh_cmt_read_cmcsr(ch);
if (value != old_value) {
ch->cmt->info->write_control(ch->ioctrl, CMCSR, value);
udelay(ch->cmt->reg_delay);
}
} }
static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch) static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
@ -268,14 +282,33 @@ static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
return ch->cmt->info->read_count(ch->ioctrl, CMCNT); return ch->cmt->info->read_count(ch->ioctrl, CMCNT);
} }
static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value) static inline int sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value)
{ {
/* Tests showed that we need to wait 3 clocks here */
unsigned int cmcnt_delay = DIV_ROUND_UP(3 * ch->cmt->reg_delay, 2);
u32 reg;
if (ch->cmt->info->model > SH_CMT_16BIT) {
int ret = read_poll_timeout_atomic(sh_cmt_read_cmcsr, reg,
!(reg & SH_CMT32_CMCSR_WRFLG),
1, cmcnt_delay, false, ch);
if (ret < 0)
return ret;
}
ch->cmt->info->write_count(ch->ioctrl, CMCNT, value); ch->cmt->info->write_count(ch->ioctrl, CMCNT, value);
udelay(cmcnt_delay);
return 0;
} }
static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, u32 value) static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, u32 value)
{ {
ch->cmt->info->write_count(ch->ioctrl, CMCOR, value); u32 old_value = ch->cmt->info->read_count(ch->ioctrl, CMCOR);
if (value != old_value) {
ch->cmt->info->write_count(ch->ioctrl, CMCOR, value);
udelay(ch->cmt->reg_delay);
}
} }
static u32 sh_cmt_get_counter(struct sh_cmt_channel *ch, u32 *has_wrapped) static u32 sh_cmt_get_counter(struct sh_cmt_channel *ch, u32 *has_wrapped)
@ -319,7 +352,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
static int sh_cmt_enable(struct sh_cmt_channel *ch) static int sh_cmt_enable(struct sh_cmt_channel *ch)
{ {
int k, ret; int ret;
dev_pm_syscore_device(&ch->cmt->pdev->dev, true); dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
@ -347,26 +380,9 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
} }
sh_cmt_write_cmcor(ch, 0xffffffff); sh_cmt_write_cmcor(ch, 0xffffffff);
sh_cmt_write_cmcnt(ch, 0); ret = sh_cmt_write_cmcnt(ch, 0);
/* if (ret || sh_cmt_read_cmcnt(ch)) {
* According to the sh73a0 user's manual, as CMCNT can be operated
* only by the RCLK (Pseudo 32 kHz), there's one restriction on
* modifying CMCNT register; two RCLK cycles are necessary before
* this register is either read or any modification of the value
* it holds is reflected in the LSI's actual operation.
*
* While at it, we're supposed to clear out the CMCNT as of this
* moment, so make sure it's processed properly here. This will
* take RCLKx2 at maximum.
*/
for (k = 0; k < 100; k++) {
if (!sh_cmt_read_cmcnt(ch))
break;
udelay(1);
}
if (sh_cmt_read_cmcnt(ch)) {
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n", dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
ch->index); ch->index);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
@ -995,8 +1011,8 @@ MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
{ {
unsigned int mask; unsigned int mask, i;
unsigned int i; unsigned long rate;
int ret; int ret;
cmt->pdev = pdev; cmt->pdev = pdev;
@ -1032,10 +1048,16 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto err_clk_unprepare; goto err_clk_unprepare;
if (cmt->info->width == 16) rate = clk_get_rate(cmt->clk);
cmt->rate = clk_get_rate(cmt->clk) / 512; if (!rate) {
else ret = -EINVAL;
cmt->rate = clk_get_rate(cmt->clk) / 8; goto err_clk_disable;
}
/* We shall wait 2 input clks after register writes */
if (cmt->info->model >= SH_CMT_48BIT)
cmt->reg_delay = DIV_ROUND_UP(2UL * USEC_PER_SEC, rate);
cmt->rate = rate / (cmt->info->width == 16 ? 512 : 8);
/* Map the memory resource(s). */ /* Map the memory resource(s). */
ret = sh_cmt_map_memory(cmt); ret = sh_cmt_map_memory(cmt);

View File

@ -188,6 +188,7 @@ static void __init npcm7xx_clocksource_init(void)
static int __init npcm7xx_timer_init(struct device_node *np) static int __init npcm7xx_timer_init(struct device_node *np)
{ {
struct clk *clk;
int ret; int ret;
ret = timer_of_init(np, &npcm7xx_to); ret = timer_of_init(np, &npcm7xx_to);
@ -199,6 +200,15 @@ static int __init npcm7xx_timer_init(struct device_node *np)
npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate / npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
(NPCM7XX_Tx_MIN_PRESCALE + 1); (NPCM7XX_Tx_MIN_PRESCALE + 1);
/* Enable the clock for timer1, if it exists */
clk = of_clk_get(np, 1);
if (clk) {
if (!IS_ERR(clk))
clk_prepare_enable(clk);
else
pr_warn("%pOF: Failed to get clock for timer1: %pe", np, clk);
}
npcm7xx_clocksource_init(); npcm7xx_clocksource_init();
npcm7xx_clockevents_init(); npcm7xx_clockevents_init();

View File

@ -155,14 +155,14 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static inline void timer_shutdown(struct clock_event_device *evt) static inline void evt_timer_shutdown(struct clock_event_device *evt)
{ {
writel(0, common_clkevt->ctrl); writel(0, common_clkevt->ctrl);
} }
static int sp804_shutdown(struct clock_event_device *evt) static int sp804_shutdown(struct clock_event_device *evt)
{ {
timer_shutdown(evt); evt_timer_shutdown(evt);
return 0; return 0;
} }
@ -171,7 +171,7 @@ static int sp804_set_periodic(struct clock_event_device *evt)
unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
timer_shutdown(evt); evt_timer_shutdown(evt);
writel(common_clkevt->reload, common_clkevt->load); writel(common_clkevt->reload, common_clkevt->load);
writel(ctrl, common_clkevt->ctrl); writel(ctrl, common_clkevt->ctrl);
return 0; return 0;

View File

@ -345,8 +345,10 @@ static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
return error; return error;
r = clk_get_rate(clock); r = clk_get_rate(clock);
if (!r) if (!r) {
clk_disable_unprepare(clock);
return -ENODEV; return -ENODEV;
}
if (is_ick) if (is_ick)
t->ick = clock; t->ick = clock;

View File

@ -633,6 +633,8 @@ static struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *n
static int omap_dm_timer_free(struct omap_dm_timer *cookie) static int omap_dm_timer_free(struct omap_dm_timer *cookie)
{ {
struct dmtimer *timer; struct dmtimer *timer;
struct device *dev;
int rc;
timer = to_dmtimer(cookie); timer = to_dmtimer(cookie);
if (unlikely(!timer)) if (unlikely(!timer))
@ -640,10 +642,21 @@ static int omap_dm_timer_free(struct omap_dm_timer *cookie)
WARN_ON(!timer->reserved); WARN_ON(!timer->reserved);
timer->reserved = 0; timer->reserved = 0;
dev = &timer->pdev->dev;
rc = pm_runtime_resume_and_get(dev);
if (rc)
return rc;
/* Clear timer configuration */
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
pm_runtime_put_sync(dev);
return 0; return 0;
} }
int omap_dm_timer_get_irq(struct omap_dm_timer *cookie) static int omap_dm_timer_get_irq(struct omap_dm_timer *cookie)
{ {
struct dmtimer *timer = to_dmtimer(cookie); struct dmtimer *timer = to_dmtimer(cookie);
if (timer) if (timer)
@ -1135,6 +1148,10 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
goto err_disable; goto err_disable;
} }
__omap_dm_timer_init_regs(timer); __omap_dm_timer_init_regs(timer);
/* Clear timer configuration */
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, 0);
pm_runtime_put(dev); pm_runtime_put(dev);
} }
@ -1258,7 +1275,7 @@ static struct platform_driver omap_dm_timer_driver = {
.remove = omap_dm_timer_remove, .remove = omap_dm_timer_remove,
.driver = { .driver = {
.name = "omap_timer", .name = "omap_timer",
.of_match_table = of_match_ptr(omap_timer_match), .of_match_table = omap_timer_match,
.pm = &omap_dm_timer_pm_ops, .pm = &omap_dm_timer_pm_ops,
}, },
}; };

View File

@ -1116,8 +1116,8 @@ cleanup:
if (ctlx == get_active_ctlx(hw)) { if (ctlx == get_active_ctlx(hw)) {
spin_unlock_irqrestore(&hw->ctlxq.lock, flags); spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
del_singleshot_timer_sync(&hw->reqtimer); del_timer_sync(&hw->reqtimer);
del_singleshot_timer_sync(&hw->resptimer); del_timer_sync(&hw->resptimer);
hw->req_timer_done = 1; hw->req_timer_done = 1;
hw->resp_timer_done = 1; hw->resp_timer_done = 1;
usb_kill_urb(&hw->ctlx_urb); usb_kill_urb(&hw->ctlx_urb);

View File

@ -170,9 +170,9 @@ static void prism2sta_disconnect_usb(struct usb_interface *interface)
*/ */
prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
del_singleshot_timer_sync(&hw->throttle); del_timer_sync(&hw->throttle);
del_singleshot_timer_sync(&hw->reqtimer); del_timer_sync(&hw->reqtimer);
del_singleshot_timer_sync(&hw->resptimer); del_timer_sync(&hw->resptimer);
/* Unlink all the URBs. This "removes the wheels" /* Unlink all the URBs. This "removes the wheels"
* from the entire CTLX handling mechanism. * from the entire CTLX handling mechanism.

View File

@ -62,8 +62,6 @@
struct omap_dm_timer { struct omap_dm_timer {
}; };
int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
u32 omap_dm_timer_modify_idlect_mask(u32 inputmask); u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
/* /*

View File

@ -45,6 +45,7 @@ struct time_namespace *copy_time_ns(unsigned long flags,
void free_time_ns(struct time_namespace *ns); void free_time_ns(struct time_namespace *ns);
void timens_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk); void timens_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk);
struct vdso_data *arch_get_vdso_data(void *vvar_page); struct vdso_data *arch_get_vdso_data(void *vvar_page);
struct page *find_timens_vvar_page(struct vm_area_struct *vma);
static inline void put_time_ns(struct time_namespace *ns) static inline void put_time_ns(struct time_namespace *ns)
{ {
@ -141,6 +142,11 @@ static inline void timens_on_fork(struct nsproxy *nsproxy,
return; return;
} }
static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
return NULL;
}
static inline void timens_add_monotonic(struct timespec64 *ts) { } static inline void timens_add_monotonic(struct timespec64 *ts) { }
static inline void timens_add_boottime(struct timespec64 *ts) { } static inline void timens_add_boottime(struct timespec64 *ts) { }

View File

@ -169,7 +169,6 @@ static inline int timer_pending(const struct timer_list * timer)
} }
extern void add_timer_on(struct timer_list *timer, int cpu); extern void add_timer_on(struct timer_list *timer, int cpu);
extern int del_timer(struct timer_list * timer);
extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer(struct timer_list *timer, unsigned long expires);
extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
extern int timer_reduce(struct timer_list *timer, unsigned long expires); extern int timer_reduce(struct timer_list *timer, unsigned long expires);
@ -183,14 +182,36 @@ extern int timer_reduce(struct timer_list *timer, unsigned long expires);
extern void add_timer(struct timer_list *timer); extern void add_timer(struct timer_list *timer);
extern int try_to_del_timer_sync(struct timer_list *timer); extern int try_to_del_timer_sync(struct timer_list *timer);
extern int timer_delete_sync(struct timer_list *timer);
extern int timer_delete(struct timer_list *timer);
extern int timer_shutdown_sync(struct timer_list *timer);
extern int timer_shutdown(struct timer_list *timer);
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) /**
extern int del_timer_sync(struct timer_list *timer); * del_timer_sync - Delete a pending timer and wait for a running callback
#else * @timer: The timer to be deleted
# define del_timer_sync(t) del_timer(t) *
#endif * See timer_delete_sync() for detailed explanation.
*
* Do not use in new code. Use timer_delete_sync() instead.
*/
static inline int del_timer_sync(struct timer_list *timer)
{
return timer_delete_sync(timer);
}
#define del_singleshot_timer_sync(t) del_timer_sync(t) /**
* del_timer - Delete a pending timer
* @timer: The timer to be deleted
*
* See timer_delete() for detailed explanation.
*
* Do not use in new code. Use timer_delete() instead.
*/
static inline int del_timer(struct timer_list *timer)
{
return timer_delete(timer);
}
extern void init_timers(void); extern void init_timers(void);
struct hrtimer; struct hrtimer;

View File

@ -35,7 +35,7 @@ struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head)
{ {
struct rb_node *leftmost = rb_first_cached(&head->rb_root); struct rb_node *leftmost = rb_first_cached(&head->rb_root);
return rb_entry(leftmost, struct timerqueue_node, node); return rb_entry_safe(leftmost, struct timerqueue_node, node);
} }
static inline void timerqueue_init(struct timerqueue_node *node) static inline void timerqueue_init(struct timerqueue_node *node)

View File

@ -76,7 +76,7 @@ static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt,
} }
/** /**
* clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds * clockevent_delta2ns - Convert a latch value (device ticks) to nanoseconds
* @latch: value to convert * @latch: value to convert
* @evt: pointer to clock event device descriptor * @evt: pointer to clock event device descriptor
* *

View File

@ -192,6 +192,24 @@ static void timens_setup_vdso_data(struct vdso_data *vdata,
offset[CLOCK_BOOTTIME_ALARM] = boottime; offset[CLOCK_BOOTTIME_ALARM] = boottime;
} }
struct page *find_timens_vvar_page(struct vm_area_struct *vma)
{
if (likely(vma->vm_mm == current->mm))
return current->nsproxy->time_ns->vvar_page;
/*
* VM_PFNMAP | VM_IO protect .fault() handler from being called
* through interfaces like /proc/$pid/mem or
* process_vm_{readv,writev}() as long as there's no .access()
* in special_mapping_vmops().
* For more details check_vma_flags() and __access_remote_vm()
*/
WARN(1, "vvar_page accessed remotely");
return NULL;
}
/* /*
* Protects possibly multiple offsets writers racing each other * Protects possibly multiple offsets writers racing each other
* and tasks entering the namespace. * and tasks entering the namespace.

View File

@ -1017,7 +1017,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
unsigned int idx = UINT_MAX; unsigned int idx = UINT_MAX;
int ret = 0; int ret = 0;
BUG_ON(!timer->function); debug_assert_init(timer);
/* /*
* This is a common optimization triggered by the networking code - if * This is a common optimization triggered by the networking code - if
@ -1044,6 +1044,14 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
* dequeue/enqueue dance. * dequeue/enqueue dance.
*/ */
base = lock_timer_base(timer, &flags); base = lock_timer_base(timer, &flags);
/*
* Has @timer been shutdown? This needs to be evaluated
* while holding base lock to prevent a race against the
* shutdown code.
*/
if (!timer->function)
goto out_unlock;
forward_timer_base(base); forward_timer_base(base);
if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) && if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) &&
@ -1070,6 +1078,14 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
} }
} else { } else {
base = lock_timer_base(timer, &flags); base = lock_timer_base(timer, &flags);
/*
* Has @timer been shutdown? This needs to be evaluated
* while holding base lock to prevent a race against the
* shutdown code.
*/
if (!timer->function)
goto out_unlock;
forward_timer_base(base); forward_timer_base(base);
} }
@ -1083,7 +1099,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
/* /*
* We are trying to schedule the timer on the new base. * We are trying to schedule the timer on the new base.
* However we can't change timer's base while it is running, * However we can't change timer's base while it is running,
* otherwise del_timer_sync() can't detect that the timer's * otherwise timer_delete_sync() can't detect that the timer's
* handler yet has not finished. This also guarantees that the * handler yet has not finished. This also guarantees that the
* timer is serialized wrt itself. * timer is serialized wrt itself.
*/ */
@ -1121,14 +1137,20 @@ out_unlock:
} }
/** /**
* mod_timer_pending - modify a pending timer's timeout * mod_timer_pending - Modify a pending timer's timeout
* @timer: the pending timer to be modified * @timer: The pending timer to be modified
* @expires: new timeout in jiffies * @expires: New absolute timeout in jiffies
* *
* mod_timer_pending() is the same for pending timers as mod_timer(), * mod_timer_pending() is the same for pending timers as mod_timer(), but
* but will not re-activate and modify already deleted timers. * will not activate inactive timers.
* *
* It is useful for unserialized use of timers. * If @timer->function == NULL then the start operation is silently
* discarded.
*
* Return:
* * %0 - The timer was inactive and not modified or was in
* shutdown state and the operation was discarded
* * %1 - The timer was active and requeued to expire at @expires
*/ */
int mod_timer_pending(struct timer_list *timer, unsigned long expires) int mod_timer_pending(struct timer_list *timer, unsigned long expires)
{ {
@ -1137,24 +1159,31 @@ int mod_timer_pending(struct timer_list *timer, unsigned long expires)
EXPORT_SYMBOL(mod_timer_pending); EXPORT_SYMBOL(mod_timer_pending);
/** /**
* mod_timer - modify a timer's timeout * mod_timer - Modify a timer's timeout
* @timer: the timer to be modified * @timer: The timer to be modified
* @expires: new timeout in jiffies * @expires: New absolute timeout in jiffies
*
* mod_timer() is a more efficient way to update the expire field of an
* active timer (if the timer is inactive it will be activated)
* *
* mod_timer(timer, expires) is equivalent to: * mod_timer(timer, expires) is equivalent to:
* *
* del_timer(timer); timer->expires = expires; add_timer(timer); * del_timer(timer); timer->expires = expires; add_timer(timer);
* *
* mod_timer() is more efficient than the above open coded sequence. In
* case that the timer is inactive, the del_timer() part is a NOP. The
* timer is in any case activated with the new expiry time @expires.
*
* Note that if there are multiple unserialized concurrent users of the * Note that if there are multiple unserialized concurrent users of the
* same timer, then mod_timer() is the only safe way to modify the timeout, * same timer, then mod_timer() is the only safe way to modify the timeout,
* since add_timer() cannot modify an already running timer. * since add_timer() cannot modify an already running timer.
* *
* The function returns whether it has modified a pending timer or not. * If @timer->function == NULL then the start operation is silently
* (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an * discarded. In this case the return value is 0 and meaningless.
* active timer returns 1.) *
* Return:
* * %0 - The timer was inactive and started or was in shutdown
* state and the operation was discarded
* * %1 - The timer was active and requeued to expire at @expires or
* the timer was active and not modified because @expires did
* not change the effective expiry time
*/ */
int mod_timer(struct timer_list *timer, unsigned long expires) int mod_timer(struct timer_list *timer, unsigned long expires)
{ {
@ -1165,11 +1194,22 @@ EXPORT_SYMBOL(mod_timer);
/** /**
* timer_reduce - Modify a timer's timeout if it would reduce the timeout * timer_reduce - Modify a timer's timeout if it would reduce the timeout
* @timer: The timer to be modified * @timer: The timer to be modified
* @expires: New timeout in jiffies * @expires: New absolute timeout in jiffies
* *
* timer_reduce() is very similar to mod_timer(), except that it will only * timer_reduce() is very similar to mod_timer(), except that it will only
* modify a running timer if that would reduce the expiration time (it will * modify an enqueued timer if that would reduce the expiration time. If
* start a timer that isn't running). * @timer is not enqueued it starts the timer.
*
* If @timer->function == NULL then the start operation is silently
* discarded.
*
* Return:
* * %0 - The timer was inactive and started or was in shutdown
* state and the operation was discarded
* * %1 - The timer was active and requeued to expire at @expires or
* the timer was active and not modified because @expires
* did not change the effective expiry time such that the
* timer would expire earlier than already scheduled
*/ */
int timer_reduce(struct timer_list *timer, unsigned long expires) int timer_reduce(struct timer_list *timer, unsigned long expires)
{ {
@ -1178,39 +1218,51 @@ int timer_reduce(struct timer_list *timer, unsigned long expires)
EXPORT_SYMBOL(timer_reduce); EXPORT_SYMBOL(timer_reduce);
/** /**
* add_timer - start a timer * add_timer - Start a timer
* @timer: the timer to be added * @timer: The timer to be started
* *
* The kernel will do a ->function(@timer) callback from the * Start @timer to expire at @timer->expires in the future. @timer->expires
* timer interrupt at the ->expires point in the future. The * is the absolute expiry time measured in 'jiffies'. When the timer expires
* current time is 'jiffies'. * timer->function(timer) will be invoked from soft interrupt context.
* *
* The timer's ->expires, ->function fields must be set prior calling this * The @timer->expires and @timer->function fields must be set prior
* function. * to calling this function.
* *
* Timers with an ->expires field in the past will be executed in the next * If @timer->function == NULL then the start operation is silently
* timer tick. * discarded.
*
* If @timer->expires is already in the past @timer will be queued to
* expire at the next timer tick.
*
* This can only operate on an inactive timer. Attempts to invoke this on
* an active timer are rejected with a warning.
*/ */
void add_timer(struct timer_list *timer) void add_timer(struct timer_list *timer)
{ {
BUG_ON(timer_pending(timer)); if (WARN_ON_ONCE(timer_pending(timer)))
return;
__mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING); __mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING);
} }
EXPORT_SYMBOL(add_timer); EXPORT_SYMBOL(add_timer);
/** /**
* add_timer_on - start a timer on a particular CPU * add_timer_on - Start a timer on a particular CPU
* @timer: the timer to be added * @timer: The timer to be started
* @cpu: the CPU to start it on * @cpu: The CPU to start it on
* *
* This is not very scalable on SMP. Double adds are not possible. * Same as add_timer() except that it starts the timer on the given CPU.
*
* See add_timer() for further details.
*/ */
void add_timer_on(struct timer_list *timer, int cpu) void add_timer_on(struct timer_list *timer, int cpu)
{ {
struct timer_base *new_base, *base; struct timer_base *new_base, *base;
unsigned long flags; unsigned long flags;
BUG_ON(timer_pending(timer) || !timer->function); debug_assert_init(timer);
if (WARN_ON_ONCE(timer_pending(timer)))
return;
new_base = get_timer_cpu_base(timer->flags, cpu); new_base = get_timer_cpu_base(timer->flags, cpu);
@ -1220,6 +1272,13 @@ void add_timer_on(struct timer_list *timer, int cpu)
* wrong base locked. See lock_timer_base(). * wrong base locked. See lock_timer_base().
*/ */
base = lock_timer_base(timer, &flags); base = lock_timer_base(timer, &flags);
/*
* Has @timer been shutdown? This needs to be evaluated while
* holding base lock to prevent a race against the shutdown code.
*/
if (!timer->function)
goto out_unlock;
if (base != new_base) { if (base != new_base) {
timer->flags |= TIMER_MIGRATING; timer->flags |= TIMER_MIGRATING;
@ -1233,22 +1292,27 @@ void add_timer_on(struct timer_list *timer, int cpu)
debug_timer_activate(timer); debug_timer_activate(timer);
internal_add_timer(base, timer); internal_add_timer(base, timer);
out_unlock:
raw_spin_unlock_irqrestore(&base->lock, flags); raw_spin_unlock_irqrestore(&base->lock, flags);
} }
EXPORT_SYMBOL_GPL(add_timer_on); EXPORT_SYMBOL_GPL(add_timer_on);
/** /**
* del_timer - deactivate a timer. * __timer_delete - Internal function: Deactivate a timer
* @timer: the timer to be deactivated * @timer: The timer to be deactivated
* @shutdown: If true, this indicates that the timer is about to be
* shutdown permanently.
* *
* del_timer() deactivates a timer - this works on both active and inactive * If @shutdown is true then @timer->function is set to NULL under the
* timers. * timer base lock which prevents further rearming of the time. In that
* case any attempt to rearm @timer after this function returns will be
* silently ignored.
* *
* The function returns whether it has deactivated a pending timer or not. * Return:
* (ie. del_timer() of an inactive timer returns 0, del_timer() of an * * %0 - The timer was not pending
* active timer returns 1.) * * %1 - The timer was pending and deactivated
*/ */
int del_timer(struct timer_list *timer) static int __timer_delete(struct timer_list *timer, bool shutdown)
{ {
struct timer_base *base; struct timer_base *base;
unsigned long flags; unsigned long flags;
@ -1256,24 +1320,90 @@ int del_timer(struct timer_list *timer)
debug_assert_init(timer); debug_assert_init(timer);
if (timer_pending(timer)) { /*
* If @shutdown is set then the lock has to be taken whether the
* timer is pending or not to protect against a concurrent rearm
* which might hit between the lockless pending check and the lock
* aquisition. By taking the lock it is ensured that such a newly
* enqueued timer is dequeued and cannot end up with
* timer->function == NULL in the expiry code.
*
* If timer->function is currently executed, then this makes sure
* that the callback cannot requeue the timer.
*/
if (timer_pending(timer) || shutdown) {
base = lock_timer_base(timer, &flags); base = lock_timer_base(timer, &flags);
ret = detach_if_pending(timer, base, true); ret = detach_if_pending(timer, base, true);
if (shutdown)
timer->function = NULL;
raw_spin_unlock_irqrestore(&base->lock, flags); raw_spin_unlock_irqrestore(&base->lock, flags);
} }
return ret; return ret;
} }
EXPORT_SYMBOL(del_timer);
/** /**
* try_to_del_timer_sync - Try to deactivate a timer * timer_delete - Deactivate a timer
* @timer: timer to delete * @timer: The timer to be deactivated
* *
* This function tries to deactivate a timer. Upon successful (ret >= 0) * The function only deactivates a pending timer, but contrary to
* exit the timer is not queued and the handler is not running on any CPU. * timer_delete_sync() it does not take into account whether the timer's
* callback function is concurrently executed on a different CPU or not.
* It neither prevents rearming of the timer. If @timer can be rearmed
* concurrently then the return value of this function is meaningless.
*
* Return:
* * %0 - The timer was not pending
* * %1 - The timer was pending and deactivated
*/ */
int try_to_del_timer_sync(struct timer_list *timer) int timer_delete(struct timer_list *timer)
{
return __timer_delete(timer, false);
}
EXPORT_SYMBOL(timer_delete);
/**
* timer_shutdown - Deactivate a timer and prevent rearming
* @timer: The timer to be deactivated
*
* The function does not wait for an eventually running timer callback on a
* different CPU but it prevents rearming of the timer. Any attempt to arm
* @timer after this function returns will be silently ignored.
*
* This function is useful for teardown code and should only be used when
* timer_shutdown_sync() cannot be invoked due to locking or context constraints.
*
* Return:
* * %0 - The timer was not pending
* * %1 - The timer was pending
*/
int timer_shutdown(struct timer_list *timer)
{
return __timer_delete(timer, true);
}
EXPORT_SYMBOL_GPL(timer_shutdown);
/**
* __try_to_del_timer_sync - Internal function: Try to deactivate a timer
* @timer: Timer to deactivate
* @shutdown: If true, this indicates that the timer is about to be
* shutdown permanently.
*
* If @shutdown is true then @timer->function is set to NULL under the
* timer base lock which prevents further rearming of the timer. Any
* attempt to rearm @timer after this function returns will be silently
* ignored.
*
* This function cannot guarantee that the timer cannot be rearmed
* right after dropping the base lock if @shutdown is false. That
* needs to be prevented by the calling code if necessary.
*
* Return:
* * %0 - The timer was not pending
* * %1 - The timer was pending and deactivated
* * %-1 - The timer callback function is running on a different CPU
*/
static int __try_to_del_timer_sync(struct timer_list *timer, bool shutdown)
{ {
struct timer_base *base; struct timer_base *base;
unsigned long flags; unsigned long flags;
@ -1285,11 +1415,34 @@ int try_to_del_timer_sync(struct timer_list *timer)
if (base->running_timer != timer) if (base->running_timer != timer)
ret = detach_if_pending(timer, base, true); ret = detach_if_pending(timer, base, true);
if (shutdown)
timer->function = NULL;
raw_spin_unlock_irqrestore(&base->lock, flags); raw_spin_unlock_irqrestore(&base->lock, flags);
return ret; return ret;
} }
/**
* try_to_del_timer_sync - Try to deactivate a timer
* @timer: Timer to deactivate
*
* This function tries to deactivate a timer. On success the timer is not
* queued and the timer callback function is not running on any CPU.
*
* This function does not guarantee that the timer cannot be rearmed right
* after dropping the base lock. That needs to be prevented by the calling
* code if necessary.
*
* Return:
* * %0 - The timer was not pending
* * %1 - The timer was pending and deactivated
* * %-1 - The timer callback function is running on a different CPU
*/
int try_to_del_timer_sync(struct timer_list *timer)
{
return __try_to_del_timer_sync(timer, false);
}
EXPORT_SYMBOL(try_to_del_timer_sync); EXPORT_SYMBOL(try_to_del_timer_sync);
#ifdef CONFIG_PREEMPT_RT #ifdef CONFIG_PREEMPT_RT
@ -1365,44 +1518,29 @@ static inline void timer_sync_wait_running(struct timer_base *base) { }
static inline void del_timer_wait_running(struct timer_list *timer) { } static inline void del_timer_wait_running(struct timer_list *timer) { }
#endif #endif
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
/** /**
* del_timer_sync - deactivate a timer and wait for the handler to finish. * __timer_delete_sync - Internal function: Deactivate a timer and wait
* @timer: the timer to be deactivated * for the handler to finish.
* @timer: The timer to be deactivated
* @shutdown: If true, @timer->function will be set to NULL under the
* timer base lock which prevents rearming of @timer
* *
* This function only differs from del_timer() on SMP: besides deactivating * If @shutdown is not set the timer can be rearmed later. If the timer can
* the timer it also makes sure the handler has finished executing on other * be rearmed concurrently, i.e. after dropping the base lock then the
* CPUs. * return value is meaningless.
* *
* Synchronization rules: Callers must prevent restarting of the timer, * If @shutdown is set then @timer->function is set to NULL under timer
* otherwise this function is meaningless. It must not be called from * base lock which prevents rearming of the timer. Any attempt to rearm
* interrupt contexts unless the timer is an irqsafe one. The caller must * a shutdown timer is silently ignored.
* not hold locks which would prevent completion of the timer's
* handler. The timer's handler must not call add_timer_on(). Upon exit the
* timer is not queued and the handler is not running on any CPU.
* *
* Note: For !irqsafe timers, you must not hold locks that are held in * If the timer should be reused after shutdown it has to be initialized
* interrupt context while calling this function. Even if the lock has * again.
* nothing to do with the timer in question. Here's why::
* *
* CPU0 CPU1 * Return:
* ---- ---- * * %0 - The timer was not pending
* <SOFTIRQ> * * %1 - The timer was pending and deactivated
* call_timer_fn();
* base->running_timer = mytimer;
* spin_lock_irq(somelock);
* <IRQ>
* spin_lock(somelock);
* del_timer_sync(mytimer);
* while (base->running_timer == mytimer);
*
* Now del_timer_sync() will never return and never release somelock.
* The interrupt on the other CPU is waiting to grab somelock but
* it has interrupted the softirq that CPU0 is waiting to finish.
*
* The function returns whether it has deactivated a pending timer or not.
*/ */
int del_timer_sync(struct timer_list *timer) static int __timer_delete_sync(struct timer_list *timer, bool shutdown)
{ {
int ret; int ret;
@ -1422,7 +1560,7 @@ int del_timer_sync(struct timer_list *timer)
* don't use it in hardirq context, because it * don't use it in hardirq context, because it
* could lead to deadlock. * could lead to deadlock.
*/ */
WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); WARN_ON(in_hardirq() && !(timer->flags & TIMER_IRQSAFE));
/* /*
* Must be able to sleep on PREEMPT_RT because of the slowpath in * Must be able to sleep on PREEMPT_RT because of the slowpath in
@ -1432,7 +1570,7 @@ int del_timer_sync(struct timer_list *timer)
lockdep_assert_preemption_enabled(); lockdep_assert_preemption_enabled();
do { do {
ret = try_to_del_timer_sync(timer); ret = __try_to_del_timer_sync(timer, shutdown);
if (unlikely(ret < 0)) { if (unlikely(ret < 0)) {
del_timer_wait_running(timer); del_timer_wait_running(timer);
@ -1442,8 +1580,96 @@ int del_timer_sync(struct timer_list *timer)
return ret; return ret;
} }
EXPORT_SYMBOL(del_timer_sync);
#endif /**
* timer_delete_sync - Deactivate a timer and wait for the handler to finish.
* @timer: The timer to be deactivated
*
* Synchronization rules: Callers must prevent restarting of the timer,
* otherwise this function is meaningless. It must not be called from
* interrupt contexts unless the timer is an irqsafe one. The caller must
* not hold locks which would prevent completion of the timer's callback
* function. The timer's handler must not call add_timer_on(). Upon exit
* the timer is not queued and the handler is not running on any CPU.
*
* For !irqsafe timers, the caller must not hold locks that are held in
* interrupt context. Even if the lock has nothing to do with the timer in
* question. Here's why::
*
* CPU0 CPU1
* ---- ----
* <SOFTIRQ>
* call_timer_fn();
* base->running_timer = mytimer;
* spin_lock_irq(somelock);
* <IRQ>
* spin_lock(somelock);
* timer_delete_sync(mytimer);
* while (base->running_timer == mytimer);
*
* Now timer_delete_sync() will never return and never release somelock.
* The interrupt on the other CPU is waiting to grab somelock but it has
* interrupted the softirq that CPU0 is waiting to finish.
*
* This function cannot guarantee that the timer is not rearmed again by
* some concurrent or preempting code, right after it dropped the base
* lock. If there is the possibility of a concurrent rearm then the return
* value of the function is meaningless.
*
* If such a guarantee is needed, e.g. for teardown situations then use
* timer_shutdown_sync() instead.
*
* Return:
* * %0 - The timer was not pending
* * %1 - The timer was pending and deactivated
*/
int timer_delete_sync(struct timer_list *timer)
{
return __timer_delete_sync(timer, false);
}
EXPORT_SYMBOL(timer_delete_sync);
/**
* timer_shutdown_sync - Shutdown a timer and prevent rearming
* @timer: The timer to be shutdown
*
* When the function returns it is guaranteed that:
* - @timer is not queued
* - The callback function of @timer is not running
* - @timer cannot be enqueued again. Any attempt to rearm
* @timer is silently ignored.
*
* See timer_delete_sync() for synchronization rules.
*
* This function is useful for final teardown of an infrastructure where
* the timer is subject to a circular dependency problem.
*
* A common pattern for this is a timer and a workqueue where the timer can
* schedule work and work can arm the timer. On shutdown the workqueue must
* be destroyed and the timer must be prevented from rearming. Unless the
* code has conditionals like 'if (mything->in_shutdown)' to prevent that
* there is no way to get this correct with timer_delete_sync().
*
* timer_shutdown_sync() is solving the problem. The correct ordering of
* calls in this case is:
*
* timer_shutdown_sync(&mything->timer);
* workqueue_destroy(&mything->workqueue);
*
* After this 'mything' can be safely freed.
*
* This obviously implies that the timer is not required to be functional
* for the rest of the shutdown operation.
*
* Return:
* * %0 - The timer was not pending
* * %1 - The timer was pending
*/
int timer_shutdown_sync(struct timer_list *timer)
{
return __timer_delete_sync(timer, true);
}
EXPORT_SYMBOL_GPL(timer_shutdown_sync);
static void call_timer_fn(struct timer_list *timer, static void call_timer_fn(struct timer_list *timer,
void (*fn)(struct timer_list *), void (*fn)(struct timer_list *),
@ -1465,8 +1691,8 @@ static void call_timer_fn(struct timer_list *timer,
#endif #endif
/* /*
* Couple the lock chain with the lock chain at * Couple the lock chain with the lock chain at
* del_timer_sync() by acquiring the lock_map around the fn() * timer_delete_sync() by acquiring the lock_map around the fn()
* call here and in del_timer_sync(). * call here and in timer_delete_sync().
*/ */
lock_map_acquire(&lockdep_map); lock_map_acquire(&lockdep_map);
@ -1509,6 +1735,12 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
fn = timer->function; fn = timer->function;
if (WARN_ON_ONCE(!fn)) {
/* Should never happen. Emphasis on should! */
base->running_timer = NULL;
continue;
}
if (timer->flags & TIMER_IRQSAFE) { if (timer->flags & TIMER_IRQSAFE) {
raw_spin_unlock(&base->lock); raw_spin_unlock(&base->lock);
call_timer_fn(timer, fn, baseclk); call_timer_fn(timer, fn, baseclk);
@ -1933,7 +2165,7 @@ signed long __sched schedule_timeout(signed long timeout)
timer_setup_on_stack(&timer.timer, process_timeout, 0); timer_setup_on_stack(&timer.timer, process_timeout, 0);
__mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING); __mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING);
schedule(); schedule();
del_singleshot_timer_sync(&timer.timer); del_timer_sync(&timer.timer);
/* Remove the timer from the object tracker */ /* Remove the timer from the object tracker */
destroy_timer_on_stack(&timer.timer); destroy_timer_on_stack(&timer.timer);
@ -2017,8 +2249,6 @@ int timers_dead_cpu(unsigned int cpu)
struct timer_base *new_base; struct timer_base *new_base;
int b, i; int b, i;
BUG_ON(cpu_online(cpu));
for (b = 0; b < NR_BASES; b++) { for (b = 0; b < NR_BASES; b++) {
old_base = per_cpu_ptr(&timer_bases[b], cpu); old_base = per_cpu_ptr(&timer_bases[b], cpu);
new_base = get_cpu_ptr(&timer_bases[b]); new_base = get_cpu_ptr(&timer_bases[b]);
@ -2035,7 +2265,8 @@ int timers_dead_cpu(unsigned int cpu)
*/ */
forward_timer_base(new_base); forward_timer_base(new_base);
BUG_ON(old_base->running_timer); WARN_ON_ONCE(old_base->running_timer);
old_base->running_timer = NULL;
for (i = 0; i < WHEEL_SIZE; i++) for (i = 0; i < WHEEL_SIZE; i++)
migrate_timer_list(new_base, old_base->vectors + i); migrate_timer_list(new_base, old_base->vectors + i);

View File

@ -1164,7 +1164,7 @@ xprt_request_enqueue_receive(struct rpc_task *task)
spin_unlock(&xprt->queue_lock); spin_unlock(&xprt->queue_lock);
/* Turn off autodisconnect */ /* Turn off autodisconnect */
del_singleshot_timer_sync(&xprt->timer); del_timer_sync(&xprt->timer);
return 0; return 0;
} }