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:
Alexander Boettcher 2022-07-26 14:05:01 +02:00 committed by Christian Helmuth
parent 6c5d2253c9
commit e2b61231ae
2 changed files with 41 additions and 11 deletions

View File

@ -19,9 +19,6 @@
#ifndef __ASSEMBLY__
#include <linux/delay.h>
#include <linux/jiffies.h>
extern u64 jiffies_64;
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)
{
/* break busy loop of slchi() in drivers/i2c/algos/i2c-algo-bit.c */
u64 const us = jiffies_to_usecs(1);
usleep_range(us, us);
__udelay(100);
}
#endif /* __ASSEMBLY__ */

View File

@ -1,6 +1,7 @@
/*
* \brief Supplement for emulation for linux/include/asm-generic/delay.h
* \author Josef Soentgen
* \author Alexander Boettcher
* \date 2022-05-05
*/
@ -14,21 +15,54 @@
#include <asm-generic/delay.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <lx_emul.h>
void __const_udelay(unsigned long xloops)
{
unsigned long usecs = xloops / 0x10C7UL;
if (usecs < 100)
lx_emul_time_udelay(usecs);
else
usleep_range(usecs, usecs * 10);
unsigned long const usecs = xloops / 0x10C7UL;
__udelay(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;
}
}