lx_emul: unify udelay implementation

Implement udelay for all architectures within common lx_emul code,
remove driver-specific version.

Always do busy looping in udelay and use cpu_relax()
like the original Linux code. Thereby, we profit from architecture specific
instructions (cpu cool down), and jiffies are updated if irqs are on.

Ref genodelabs/genode#4778
This commit is contained in:
Stefan Kalkowski 2023-03-02 12:43:15 +01:00 committed by Christian Helmuth
parent 50541c68ec
commit 6a7a30ceaa
17 changed files with 65 additions and 198 deletions

View File

@ -37,6 +37,7 @@ SRC_C += lx_emul/shadow/kernel/sched/sched.c
SRC_C += lx_emul/shadow/kernel/smp.c
SRC_C += lx_emul/shadow/kernel/stop_machine.c
SRC_C += lx_emul/shadow/lib/cpumask.c
SRC_C += lx_emul/shadow/lib/delay.c
SRC_C += lx_emul/shadow/mm/percpu.c
SRC_C += lx_emul/shadow/mm/slab_common.c
SRC_C += lx_emul/shadow/mm/slub.c

View File

@ -0,0 +1,25 @@
/*
* \brief Shadows Linux kernel arch/arm/include/asm/delay.h
* \author Stefan Kalkowski
* \date 2023-03-03
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef __ASM_DELAY_H
#define __ASM_DELAY_H
/*
* We shadow the original arm variant and use the generic version instead,
* like x86 and arm64. Thereby, we can simply use one and the same backend
* function for udelay, which is part of our emulation codebase anyway.
*/
#include <asm-generic/delay.h>
#endif

View File

@ -0,0 +1,38 @@
/*
* \brief Supplement for emulation for arch-specific lib/delay.c
* \author Stefan Kalkowski
* \date 2023-03-02
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <asm-generic/delay.h>
#include <asm/vdso/processor.h>
#include <linux/delay.h>
#include <lx_emul.h>
#include <lx_emul/time.h>
void __const_udelay(unsigned long xloops)
{
unsigned long const usecs = xloops / 0x10C7UL;
__udelay(usecs);
}
void __udelay(unsigned long usecs)
{
/*
* if interrupts are open, jiffies get updated implicitely
* by call of cpu_relax()
*/
unsigned long long end = lx_emul_time_counter() + usecs;
while (lx_emul_time_counter() < end) cpu_relax();
}

View File

@ -48,7 +48,6 @@ SRC_C += lx_emul/mapping.c
SRC_C += lx_emul/page_alloc.c
SRC_C += lx_emul/sched_core.c
SRC_C += lx_emul/vmalloc.c
SRC_C += lx_emul/delay.c
SRC_C += lx_emul/shadow/fs/libfs.c
SRC_C += lx_emul/shadow/lib/logic_iomem.c

View File

@ -12,7 +12,6 @@ SRC_CC += wlan.cc
SRC_CC += firmware.cc
SRC_CC += socket_call.cc
SRC_CC += lx_emul/random.cc
SRC_CC += time.cc
SRC_C += dummies.c
SRC_C += lx_emul.c

View File

@ -26,8 +26,6 @@ extern "C" {
struct dma_fence_work;
struct dma_fence_work_ops;
void lx_emul_time_udelay(unsigned long usec);
void *emul_alloc_shmem_file_buffer(unsigned long);
void emul_free_shmem_file_buffer(void *);

View File

@ -9,7 +9,6 @@ INC_DIR += $(REL_PRG_DIR)
SRC_CC += main.cc
SRC_CC += emul.cc
SRC_CC += time.cc
SRC_CC += opregion_io_mem.cc
SRC_C += dummies.c
SRC_C += pci.c

View File

@ -1,25 +0,0 @@
/*
* \brief Lx_emul udelay function for very short delays
* \author Stefan Kalkowski
* \date 2021-07-10
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/log.h>
#include <lx_kit/env.h>
extern "C" void lx_emul_time_udelay(unsigned long usec);
extern "C" void lx_emul_time_udelay(unsigned long usec)
{
if (usec > 100)
Genode::error("Cannot delay that long ", usec, " microseconds");
unsigned long long start = Lx_kit::env().timer.curr_time().trunc_to_plain_us().value;
while (Lx_kit::env().timer.curr_time().trunc_to_plain_us().value < (start + usec)) { ; }
}

View File

@ -19,13 +19,3 @@
/* fix for missing include in linux/dynamic_debug.h */
#include <linux/compiler_attributes.h>
#ifdef __cplusplus
extern "C" {
#endif
void lx_emul_time_udelay(unsigned long usec);
#ifdef __cplusplus
}
#endif

View File

@ -7,7 +7,6 @@ LIBS := base pc_lx_emul jitterentropy
INC_DIR += $(REL_PRG_DIR)
SRC_CC += main.cc
SRC_CC += time.cc
SRC_CC += lx_emul/shared_dma_buffer.cc
SRC_C += dummies.c
SRC_C += lx_emul.c

View File

@ -1,25 +0,0 @@
/*
* \brief Lx_emul udelay function for very short delays
* \author Stefan Kalkowski
* \date 2021-07-10
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/log.h>
#include <lx_kit/env.h>
extern "C" void lx_emul_time_udelay(unsigned long usec);
extern "C" void lx_emul_time_udelay(unsigned long usec)
{
if (usec > 100)
Genode::error("Cannot delay that long ", usec, " microseconds");
unsigned long long start = Lx_kit::env().timer.curr_time().trunc_to_plain_us().value;
while (Lx_kit::env().timer.curr_time().trunc_to_plain_us().value < (start + usec)) { ; }
}

View File

@ -1,68 +0,0 @@
/*
* \brief Supplement for emulation for linux/include/asm-generic/delay.h
* \author Josef Soentgen
* \author Alexander Boettcher
* \date 2022-05-05
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#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 const usecs = xloops / 0x10C7UL;
__udelay(usecs);
}
void __udelay(unsigned long 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;
}
}

View File

@ -24,8 +24,6 @@
extern "C" {
#endif
void lx_emul_time_udelay(unsigned long usec);
int lx_emul_rfkill_get_any(void);
void lx_emul_rfkill_switch_all(int blocked);

View File

@ -1,25 +0,0 @@
/*
* \brief Lx_emul udelay function for very short delays
* \author Stefan Kalkowski
* \date 2021-07-10
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/log.h>
#include <lx_kit/env.h>
extern "C" void lx_emul_time_udelay(unsigned long usec);
extern "C" void lx_emul_time_udelay(unsigned long usec)
{
if (usec > 100)
Genode::error("Cannot delay that long ", usec, " microseconds");
unsigned long long start = Lx_kit::env().timer.curr_time().trunc_to_plain_us().value;
while (Lx_kit::env().timer.curr_time().trunc_to_plain_us().value < (start + usec)) { ; }
}

View File

@ -10,14 +10,3 @@
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifdef __cplusplus
extern "C" {
#endif
void lx_emul_time_udelay(unsigned long usec);
#ifdef __cplusplus
}
#endif

View File

@ -3,7 +3,7 @@ REQUIRES := x86_64
TARGET := test-driver_time
LIBS := base pc_lx_emul jitterentropy
SRC_CC += main.cc time.cc
SRC_CC += main.cc
SRC_C += lx_user.c
SRC_C += dummies.c
SRC_C += generated_dummies.c

View File

@ -1,25 +0,0 @@
/*
* \brief Lx_emul udelay function for very short delays
* \author Stefan Kalkowski
* \date 2021-07-10
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/log.h>
#include <lx_kit/env.h>
extern "C" void lx_emul_time_udelay(unsigned long usec);
extern "C" void lx_emul_time_udelay(unsigned long usec)
{
if (usec > 100)
Genode::error("Cannot delay that long ", usec, " microseconds");
unsigned long long start = Lx_kit::env().timer.curr_time().trunc_to_plain_us().value;
while (Lx_kit::env().timer.curr_time().trunc_to_plain_us().value < (start + usec)) { ; }
}