mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-30 10:38:55 +00:00
pc: avoid use usleep_range in m/udelay emulation
m/udelay is called with closed interrupts. Linux contrib code expects no other task to be run respectively to be re-scheduled. usleep_range leads to executing other tasks, which causes assertions in "spinlock taken twice" or "unexpected preempt count" errors, seen on runtime with wifi_drv and intel_fb. The assertion triggered with the changes by #4562.
This commit is contained in:
parent
6c5d2253c9
commit
e2b61231ae
@ -19,9 +19,6 @@
|
|||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/jiffies.h>
|
|
||||||
|
|
||||||
extern u64 jiffies_64;
|
|
||||||
|
|
||||||
|
|
||||||
static __always_inline void rep_nop(void)
|
static __always_inline void rep_nop(void)
|
||||||
@ -33,8 +30,7 @@ static __always_inline void rep_nop(void)
|
|||||||
static __always_inline void cpu_relax(void)
|
static __always_inline void cpu_relax(void)
|
||||||
{
|
{
|
||||||
/* break busy loop of slchi() in drivers/i2c/algos/i2c-algo-bit.c */
|
/* break busy loop of slchi() in drivers/i2c/algos/i2c-algo-bit.c */
|
||||||
u64 const us = jiffies_to_usecs(1);
|
__udelay(100);
|
||||||
usleep_range(us, us);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Supplement for emulation for linux/include/asm-generic/delay.h
|
* \brief Supplement for emulation for linux/include/asm-generic/delay.h
|
||||||
* \author Josef Soentgen
|
* \author Josef Soentgen
|
||||||
|
* \author Alexander Boettcher
|
||||||
* \date 2022-05-05
|
* \date 2022-05-05
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -14,21 +15,54 @@
|
|||||||
|
|
||||||
#include <asm-generic/delay.h>
|
#include <asm-generic/delay.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
|
||||||
|
|
||||||
void __const_udelay(unsigned long xloops)
|
void __const_udelay(unsigned long xloops)
|
||||||
{
|
{
|
||||||
unsigned long usecs = xloops / 0x10C7UL;
|
unsigned long const usecs = xloops / 0x10C7UL;
|
||||||
if (usecs < 100)
|
__udelay(usecs);
|
||||||
lx_emul_time_udelay(usecs);
|
|
||||||
else
|
|
||||||
usleep_range(usecs, usecs * 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void __udelay(unsigned long usecs)
|
void __udelay(unsigned long usecs)
|
||||||
{
|
{
|
||||||
lx_emul_time_udelay(usecs);
|
/*
|
||||||
|
* Account for delays summing up to equivalent of 1 jiffie during
|
||||||
|
* jiffies_64 stays same. When 1 jiffie is reached in sum,
|
||||||
|
* increase jiffie_64 to break endless loops, seen in
|
||||||
|
* * intel_fb - cpu_relax(void) emulation used by
|
||||||
|
* busy loop of slchi() in drivers/i2c/algos/i2c-algo-bit.c
|
||||||
|
* * wifi_drv - net/wireless/intel/iwlwif* code during error code handling
|
||||||
|
*/
|
||||||
|
static uint64_t last_jiffie = 0;
|
||||||
|
static unsigned long delayed_sum = 0;
|
||||||
|
|
||||||
|
if (jiffies_64 == last_jiffie) {
|
||||||
|
delayed_sum += usecs;
|
||||||
|
} else {
|
||||||
|
last_jiffie = jiffies_64;
|
||||||
|
delayed_sum = usecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usecs < 100)
|
||||||
|
lx_emul_time_udelay(usecs);
|
||||||
|
else {
|
||||||
|
unsigned long slept = 0;
|
||||||
|
while (slept < usecs) {
|
||||||
|
lx_emul_time_udelay(100);
|
||||||
|
slept += 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When delays sum up to the equivalent of 1 jiffie,
|
||||||
|
* increase it to break endless loops.
|
||||||
|
*/
|
||||||
|
if (delayed_sum >= jiffies_to_usecs(1)) {
|
||||||
|
jiffies_64 ++;
|
||||||
|
delayed_sum = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user