lx_kit: adjust to 4.16.3

This commit is contained in:
Alexander Boettcher 2018-04-10 16:54:01 +02:00 committed by Josef Söntgen
parent bb8e532361
commit 2efc64ace7
36 changed files with 466 additions and 160 deletions

View File

@ -42,8 +42,8 @@
#define ATOMIC_INIT(i) { (i) }
typedef struct atomic { long counter; } atomic_t;
typedef atomic_t atomic_long_t;
typedef struct atomic { int counter; } atomic_t;
typedef struct { long counter; } atomic_long_t;
static inline int atomic_read(const atomic_t *p) { return p->counter; }
static inline void atomic_set(atomic_t *p, int i) { p->counter = i; }
@ -60,10 +60,10 @@ static inline int atomic_inc_return(atomic_t *p) { return atomic_add_return(1
static inline int atomic_dec_and_test(atomic_t *p) { return atomic_sub_and_test(1, p); }
static inline int atomic_inc_not_zero(atomic_t *p) { return p->counter ? atomic_inc_return(p) : 0; }
static inline void atomic_long_inc(atomic_long_t *p) { atomic_add(1, p); }
static inline void atomic_long_sub(int i, atomic_long_t *p) { atomic_sub(i, p); }
static inline long atomic_long_add_return(long i, atomic_long_t *p) { return atomic_add_return(i, p); }
static inline long atomic_long_read(atomic_long_t *p) { return atomic_read(p); }
static inline void atomic_long_inc(atomic_long_t *p) { p->counter += 1; }
static inline void atomic_long_sub(long i, atomic_long_t *p) { p->counter -= i; }
static inline long atomic_long_add_return(long i, atomic_long_t *p) { p->counter += i; return p->counter; }
static inline long atomic_long_read(atomic_long_t *p) { return p->counter; }
static inline int atomic_cmpxchg(atomic_t *v, int old, int n)
{
@ -101,6 +101,16 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
return ret != u;
}
static inline int atomic_dec_if_positive(atomic_t *v)
{
int c = atomic_read(v);
if (c >= 0)
atomic_dec(v);
return c - 1;
}
#define smp_mb__before_atomic_dec()

View File

@ -30,6 +30,7 @@
#define BIT(nr) (1UL << (nr))
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define BIT_ULL(nr) (1ULL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
@ -85,6 +86,11 @@ static inline unsigned long __ffs64(u64 word)
(bit) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1))
#define for_each_clear_bit(bit, addr, size) \
for ((bit) = find_first_zero_bit((addr), (size)); \
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
static inline int get_bitmask_order(unsigned int count) {
return __builtin_clz(count) ^ 0x1f; }
@ -109,3 +115,7 @@ static inline __u16 ror16(__u16 word, unsigned int shift)
return (word >> shift) | (word << (16 - shift));
}
#define BITS_PER_LONG_LONG (sizeof(long long) * 8)
#define GENMASK_ULL(h, l) \
(((~0ULL) - (1ULL << (l)) + 1) & \
(~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))

View File

@ -39,8 +39,14 @@
#define BUG_ON(condition) do { if (condition) BUG(); } while(0)
#define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e))))
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); }))
#define BUILD_BUG_ON_MSG(cond,msg) ({ \
extern int __attribute__((error(msg))) build_bug(); \
if (cond) { build_bug(); } })
#define BUILD_BUG() BUILD_BUG_ON_MSG(1,"BUILD_BUG failed")
#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \
BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))

View File

@ -60,10 +60,15 @@
#define WRITE_ONCE(x, val) \
({ \
barrier(); \
__builtin_memcpy((void *)&(x), (const void *)&(val), sizeof(x)); \
union { typeof(x) v; char c[1]; } u = \
{ .v = (typeof(x)) (val) }; \
__builtin_memcpy((void *)&(x), (const void *)u.c, sizeof(x)); \
barrier(); \
})
/* XXX alpha, powerpc, blackfin needs proper implementation */
#define smp_read_barrier_depends() do { } while (0)
#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
/**************************
** linux/compiler-gcc.h **
@ -73,5 +78,9 @@
#define __packed __attribute__((packed))
#endif
#define __aligned(x) __attribute__((aligned(x)))
#define uninitialized_var(x) x = x
#define unreachable() \
do { __builtin_unreachable(); } while (0)

View File

@ -21,7 +21,9 @@
struct completion;
void complete(struct completion *);
void complete_all(struct completion *);
void init_completion(struct completion *c);
bool try_wait_for_completion(struct completion *);
void wait_for_completion(struct completion *c);
unsigned long wait_for_completion_timeout(struct completion *c,

View File

@ -35,6 +35,8 @@ enum {
EIO = 5,
ENXIO = 6,
E2BIG = 7,
ENOEXEC = 8,
EBADF = 9,
EDEADLK = 11,
ENOMEM = 12,
EACCES = 13,
@ -103,6 +105,8 @@ enum {
EPROBE_DEFER = 210,
EL3RST = 211,
ENOKEY = 212,
ECHRNG = 213,
MAX_ERRNO = 4095,
};
@ -112,10 +116,10 @@ enum {
** linux/err.h **
*****************/
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)(0UL-MAX_ERRNO))
static inline bool IS_ERR(void const *ptr) {
return (unsigned long)(ptr) > (unsigned long)(-1000); }
return (unsigned long)(ptr) >= (unsigned long)(0UL-MAX_ERRNO); }
static inline void * ERR_PTR(long error) {
return (void *) error; }

View File

@ -24,13 +24,12 @@ enum {
__GFP_HIGHMEM = 0x00000002u,
__GFP_DMA32 = 0x00000004u,
__GFP_MOVABLE = 0x00000008u,
__GFP_WAIT = 0x00000010u,
__GFP_RECLAIMABLE = 0x00000010u,
__GFP_HIGH = 0x00000020u,
__GFP_IO = 0x00000040u,
__GFP_FS = 0x00000080u,
__GFP_COLD = 0x00000100u,
__GFP_NOWARN = 0x00000200u,
__GFP_REPEAT = 0x00000400u,
__GFP_RETRY_MAYFAIL = 0x00000400u,
__GFP_NOFAIL = 0x00000800u,
__GFP_NORETRY = 0x00001000u,
__GFP_MEMALLOC = 0x00002000u,
@ -39,24 +38,24 @@ enum {
__GFP_NOMEMALLOC = 0x00010000u,
__GFP_HARDWALL = 0x00020000u,
__GFP_THISNODE = 0x00040000u,
__GFP_RECLAIMABLE = 0x00080000u,
__GFP_KMEMCG = 0x00100000u,
__GFP_NOTRACK = 0x00200000u,
__GFP_NO_KSWAPD = 0x00400000u,
__GFP_OTHER_NODE = 0x00800000u,
__GFP_WRITE = 0x01000000u,
__GFP_DIRECT_RECLAIM = 0x400000u,
__GFP_KSWAPD_RECLAIM = 0x2000000u,
__GFP_ATOMIC = 0x00080000u,
__GFP_ACCOUNT = 0x00100000u,
__GFP_DIRECT_RECLAIM = 0x00200000u,
__GFP_WRITE = 0x00800000u,
__GFP_KSWAPD_RECLAIM = 0x01000000u,
GFP_LX_DMA = 0x80000000u,
__GFP_RECLAIM = __GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM,
GFP_LX_DMA = 0x80000000u,
__GFP_RECLAIM = __GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM,
GFP_ATOMIC = __GFP_HIGH,
GFP_ATOMIC = (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM),
GFP_DMA = __GFP_DMA,
GFP_DMA32 = __GFP_DMA32,
GFP_KERNEL = __GFP_WAIT | __GFP_IO | __GFP_FS,
GFP_KERNEL = __GFP_RECLAIM | __GFP_IO | __GFP_FS,
/*
GFP_TEMPORARY = __GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_RECLAIMABLE,
GFP_USER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL,
GFP_HIGHUSER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL |
__GFP_HIGHMEM,
*/
GFP_USER = __GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL,
GFP_HIGHUSER = GFP_USER | __GFP_HIGHMEM,
};
#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)

View File

@ -24,13 +24,14 @@ void init_waitqueue_head(wait_queue_head_t *wq)
wq->list = new (&Lx_kit::env().heap()) Wait_list;
}
void remove_wait_queue(wait_queue_head_t *wq, wait_queue_t *wait)
void add_wait_queue(wait_queue_head_t *q, wait_queue_entry_t *wait)
{
Wait_list *list = static_cast<Wait_list*>(wq->list);
if (!list) { return; }
printk("%s called\n", __func__);
}
destroy(&Lx_kit::env().heap(), list);
void remove_wait_queue(wait_queue_head_t *wq, wait_queue_entry_t *wait)
{
printk("%s called\n", __func__);
}
@ -87,12 +88,32 @@ void init_completion(struct completion *work)
void complete(struct completion *work)
{
work->done = 1;
if (work->done != UINT_MAX)
work->done++;
Lx::Task *task = static_cast<Lx::Task*>(work->task);
if (task) { task->unblock(); }
}
void complete_all(struct completion *work)
{
work->done = UINT_MAX;
Lx::Task *task = static_cast<Lx::Task*>(work->task);
if (task) { task->unblock(); }
}
bool try_wait_for_completion(struct completion *work)
{
int ret = 1;
if (!work->done)
ret = 0;
else if (work->done != UINT_MAX)
work->done--;
return ret;
}
unsigned long wait_for_completion_timeout(struct completion *work,
unsigned long timeout)

View File

@ -34,7 +34,11 @@ static inline void __delay_timer(unsigned long usecs)
_delay_timer->usleep(usecs);
}
void udelay(unsigned long usecs) { __delay_timer(usecs); }
void udelay(unsigned long usecs)
{
__delay_timer(usecs);
Lx::timer_update_jiffies();
}
void msleep(unsigned int msecs)

View File

@ -18,13 +18,18 @@
#include <lx_kit/env.h>
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
struct page *alloc_pages(gfp_t const gfp_mask, unsigned int order)
{
using Genode::Cache_attribute;
struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
size_t size = PAGE_SIZE << order;
Genode::Ram_dataspace_capability ds_cap = Lx::backend_alloc(size, Genode::UNCACHED);
gfp_t const dma_mask = (GFP_DMA | GFP_LX_DMA | GFP_DMA32);
Cache_attribute const cached = (gfp_mask & dma_mask) ? Genode::UNCACHED
: Genode::CACHED;
Genode::Ram_dataspace_capability ds_cap = Lx::backend_alloc(size, cached);
page->addr = Lx_kit::env().rm().attach(ds_cap);
page->paddr = Genode::Dataspace_client(ds_cap).phys_addr();
@ -57,3 +62,9 @@ void get_page(struct page *page)
{
atomic_inc(&page->_count);
}
void put_page(struct page *page)
{
TRACE;
}

View File

@ -34,7 +34,7 @@ void mutex_destroy(struct mutex *m)
Lx::Task::List *waiters = static_cast<Lx::Task::List *>(m->waiters);
/* FIXME potentially blocked tasks are not unblocked */
if (waiters->first()) {
if (waiters && waiters->first()) {
Genode::error(__func__, "destroying non-empty waiters list");
}

View File

@ -1,6 +1,7 @@
/*
* \brief Implementation of linux/sched.h
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2015-09-09
*/
@ -14,26 +15,33 @@
/* Linux kit includes */
#include <lx_kit/scheduler.h>
struct process_timer {
struct timer_list timer;
Lx::Task &task;
static void unblock_task(unsigned long task)
process_timer(Lx::Task &task) : task(task) {}
};
static void process_timeout(struct timer_list *list)
{
Lx::Task *t = (Lx::Task *)task;
t->unblock();
struct process_timer *timeout = from_timer(timeout, list, timer);
timeout->task.unblock();
}
signed long schedule_timeout(signed long timeout)
{
struct timer_list timer;
Lx::Task & cur_task = *Lx::scheduler().current();
struct process_timer timer { cur_task };
timer_setup(&timer.timer, process_timeout, 0);
unsigned long expire = timeout + jiffies;
setup_timer(&timer, unblock_task, (unsigned long)Lx::scheduler().current());
mod_timer(&timer, expire);
mod_timer(&timer.timer, expire);
Lx::scheduler().current()->block_and_schedule();
cur_task.block_and_schedule();
del_timer(&timer);
del_timer(&timer.timer);
timeout = (expire - jiffies);

View File

@ -46,6 +46,12 @@ void *kzalloc(size_t size, gfp_t flags)
}
void *kvzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
void *kzalloc_node(size_t size, gfp_t flags, int node)
{
return kzalloc(size, 0);
@ -171,6 +177,17 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align
}
struct kmem_cache *kmem_cache_create_usercopy(const char *name, size_t size,
size_t align, slab_flags_t flags,
size_t useroffset, size_t usersize,
void (*ctor)(void *))
{
/* XXX copied from above */
enum { SLAB_LX_DMA = 0x80000000ul, };
return new (Lx::Malloc::mem()) kmem_cache(size, flags & SLAB_LX_DMA, ctor);
}
void kmem_cache_destroy(struct kmem_cache *cache)
{
destroy(Lx::Malloc::mem(), cache);

View File

@ -15,9 +15,6 @@
#include <lx_kit/timer.h>
void init_timer(struct timer_list *timer) { }
int mod_timer(struct timer_list *timer, unsigned long expires)
{
if (!Lx::timer().find(timer))
@ -27,12 +24,12 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
}
void setup_timer(struct timer_list *timer,void (*function)(unsigned long),
unsigned long data)
void timer_setup(struct timer_list *timer,
void (*function)(struct timer_list *),
unsigned int flags)
{
timer->function = function;
timer->data = data;
init_timer(timer);
timer->flags = flags;
}
@ -59,7 +56,7 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode m
int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
unsigned long delta_ns, const enum hrtimer_mode mode)
{
unsigned long expires = tim.tv64 / (NSEC_PER_MSEC * HZ);
unsigned long expires = tim / (NSEC_PER_MSEC * HZ);
/*
* Prevent truncation through rounding the values by adding 1 jiffy
@ -74,6 +71,12 @@ int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
}
bool hrtimer_active(const struct hrtimer *timer)
{
return Lx::timer().find(timer);
}
int hrtimer_cancel(struct hrtimer *timer)
{
int rv = Lx::timer().del(timer);

View File

@ -15,7 +15,7 @@
#include <lx_kit/scheduler.h>
void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *w, int state)
void prepare_to_wait(wait_queue_head_t *q, wait_queue_entry_t *w, int state)
{
if (!q) { return; }
@ -26,13 +26,13 @@ void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *w, int state)
}
void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *w, int state)
void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_entry_t *w, int state)
{
prepare_to_wait(q, w, state);
}
void finish_wait(wait_queue_head_t *q, wait_queue_t *w)
void finish_wait(wait_queue_head_t *q, wait_queue_entry_t *w)
{
if (!q) { return; }

View File

@ -27,6 +27,13 @@ bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
work->wq = wq;
/* a invalid func pointer will lead to pagefault with ip=0 sp=0 */
if (!work || !work->func) {
Genode::error("invalid work, called from ",
__builtin_return_address(0));
return false;
}
/* check for separate work queue task */
if (wq && wq->task) {
Lx::Work *lx_work = (Lx::Work *)wq->task;
@ -41,20 +48,10 @@ bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
}
static void _schedule_delayed_work(unsigned long w)
void delayed_work_timer_fn(struct timer_list *t)
{
delayed_work *work = (delayed_work *)w;
workqueue_struct *wq = work->wq;
/* check for separate work queue task */
if (wq && wq->task) {
Lx::Work *lx_work = (Lx::Work *)wq->task;
lx_work->schedule_delayed(work, 0);
lx_work->unblock();
} else {
Lx::Work::work_queue().schedule_delayed(work, 0);
Lx::Work::work_queue().unblock();
}
struct delayed_work *dwork = from_timer(dwork, t, timer);
queue_work(dwork->wq, &dwork->work);
}
@ -65,10 +62,10 @@ bool queue_delayed_work(struct workqueue_struct *wq,
/* treat delayed work without delay like any other work */
if (delay == 0) {
_schedule_delayed_work((unsigned long)dwork);
delayed_work_timer_fn(&dwork->timer);
} else {
setup_timer(&dwork->timer, _schedule_delayed_work, (unsigned long)dwork);
mod_timer(&dwork->timer, delay);
timer_setup(&dwork->timer, delayed_work_timer_fn, 0);
mod_timer(&dwork->timer, jiffies + delay);
}
return true;
}
@ -82,7 +79,13 @@ int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
bool cancel_work_sync(struct work_struct *work)
{
return Lx::Work::work_queue().cancel_work(work, true);
/* check for separate work queue task */
if (work->wq && work->wq->task) {
Lx::Work *lx_work = (Lx::Work *)work->wq->task;
return lx_work->cancel_work(work, true);
}
return false;
}
@ -101,12 +104,8 @@ bool cancel_delayed_work_sync(struct delayed_work *dwork)
bool pending = cancel_delayed_work(dwork);
if (pending) {
Genode::warning("WARN: delayed_work ", dwork, " is executed directly in "
"current '", Lx::scheduler().current()->name(), "' routine");
dwork->work.func(&dwork->work);
}
return pending;
}

View File

@ -22,6 +22,9 @@
#define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_UNSET 0x20000000
#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
struct resource
{
@ -31,6 +34,20 @@ struct resource
unsigned long flags;
};
/* helpers to define resources */
#define DEFINE_RES_NAMED(_start, _size, _name, _flags) \
{ \
.start = (_start), \
.end = (_start) + (_size) - 1, \
.name = (_name), \
.flags = (_flags), \
}
#define DEFINE_RES_MEM_NAMED(_start, _size, _name) \
DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_MEM)
#define DEFINE_RES_MEM(_start, _size) \
DEFINE_RES_MEM_NAMED((_start), (_size), NULL)
struct device;
struct resource *request_region(resource_size_t start, resource_size_t n,
@ -44,4 +61,22 @@ struct resource * devm_request_mem_region(struct device *dev, resource_size_t st
void release_region(resource_size_t start, resource_size_t n);
void release_mem_region(resource_size_t start, resource_size_t n);
resource_size_t resource_size(const struct resource *res);
static inline resource_size_t resource_size(const struct resource *res)
{
return res->end - res->start + 1;
}
static inline unsigned long resource_type(const struct resource *res)
{
return res->flags & IORESOURCE_TYPE_BITS;
}
/* True iff r1 completely contains r2 */
static inline bool resource_contains(struct resource *r1, struct resource *r2)
{
if (resource_type(r1) != resource_type(r2))
return false;
if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET)
return false;
return r1->start <= r2->start && r1->end >= r2->end;
}

View File

@ -19,9 +19,13 @@
** linux/kconfig.h **
*********************/
#define IS_ENABLED(x) x
#define IS_BUILTIN(x) x
#define __ARG_PLACEHOLDER_1 0,
#define __take_second_arg(__ignored, val, ...) val
#define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0)
#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val)
#define __is_defined(x) ___is_defined(x)
#define IS_BUILTIN(option) __is_defined(option)
#define IS_ENABLED(option) IS_BUILTIN(option)
/********************
** linux/kernel.h **
@ -185,3 +189,4 @@ void might_sleep();
#define swap(a, b) \
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
#define max3(x, y, z) max((typeof(x))max(x, y), z)

View File

@ -31,10 +31,11 @@
#define LIST_POISON1 nullptr
#define LIST_POISON2 nullptr
#else
#define LIST_POISON1 ((void *)0x00100100)
#define LIST_POISON2 ((void *)0x00200200)
#define LIST_POISON1 ((void *)0x00000100)
#define LIST_POISON2 ((void *)0x00000200)
#endif /* __cplusplus */
#define POISON_INUSE 0x5a
/******************
** linux/list.h **

View File

@ -50,7 +50,7 @@
struct module;
#define module_init(fn) void module_##fn(void) { fn(); }
#define module_init(fn) int module_##fn(void) { return fn(); }
#define module_exit(fn) void module_exit_##fn(void) { fn(); }
void module_put_and_exit(int);

View File

@ -26,7 +26,9 @@ typedef struct pm_message { int event; } pm_message_t;
struct dev_pm_info
{
pm_message_t power_state;
bool is_prepared;
bool is_prepared:1;
bool is_suspended:1;
atomic_t usage_count;
};
struct dev_pm_ops {

View File

@ -30,5 +30,6 @@ void down_read(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);
void down_write(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem);
int down_write_killable(struct rw_semaphore *);
#define __RWSEM_INITIALIZER(name) { 0 }

View File

@ -20,10 +20,12 @@
**********************/
typedef struct spinlock { unsigned unused; } spinlock_t;
typedef struct raw_spinlock { unsigned dummy; } raw_spinlock_t;
#define DEFINE_SPINLOCK(name) spinlock_t name
void spin_lock(spinlock_t *lock);
void spin_lock_nested(spinlock_t *lock, int subclass);
void spin_lock_irqsave_nested(spinlock_t *lock, unsigned flags, int subclass);
void spin_unlock(spinlock_t *lock);
void spin_lock_init(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
@ -36,6 +38,8 @@ void spin_lock_bh(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
int spin_trylock(spinlock_t *lock);
void raw_spin_lock_init(raw_spinlock_t *);
#define __RAW_SPIN_LOCK_UNLOCKED(raw_spinlock_t) {0}
/****************************
** linux/spinlock_types.h **

View File

@ -50,9 +50,21 @@ enum {
** linux/ktime.h **
*******************/
union ktime { s64 tv64; };
typedef s64 ktime_t;
typedef union ktime ktime_t;
static inline int ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
{
if (cmp1 < cmp2)
return -1;
if (cmp1 > cmp2)
return 1;
return 0;
}
static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2)
{
return ktime_compare(cmp1, cmp2) < 0;
}
ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
@ -61,29 +73,35 @@ static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec)
return ktime_add_ns(kt, usec * 1000);
}
static inline ktime_t ktime_add_ms(const ktime_t kt, const u64 msec)
{
return ktime_add_ns(kt, msec * NSEC_PER_MSEC);
}
static inline ktime_t ktime_get(void)
{
return (ktime_t){ .tv64 = (s64)jiffies * HZ * NSEC_PER_MSEC /* ns */ };
return (ktime_t){ (s64)jiffies * HZ * NSEC_PER_MSEC /* ns */ };
}
static inline ktime_t ktime_set(const long sec, const unsigned long nsec)
{
return (ktime_t){ .tv64 = (s64)sec * NSEC_PER_SEC + (s64)nsec /* ns */ };
return (ktime_t){ (s64)sec * NSEC_PER_SEC + (s64)nsec /* ns */ };
}
static inline ktime_t ktime_add(const ktime_t a, const ktime_t b)
{
return (ktime_t){ .tv64 = a.tv64 + b.tv64 /* ns */ };
return (ktime_t){ a + b /* ns */ };
}
s64 ktime_ms_delta(const ktime_t, const ktime_t);
s64 ktime_us_delta(const ktime_t later, const ktime_t earlier);
static inline struct timeval ktime_to_timeval(const ktime_t kt)
{
struct timeval tv;
tv.tv_sec = kt.tv64 / NSEC_PER_SEC;
tv.tv_usec = (kt.tv64 - (tv.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC;
tv.tv_sec = kt / NSEC_PER_SEC;
tv.tv_usec = (kt - (tv.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC;
return tv;
}
@ -91,3 +109,4 @@ ktime_t ktime_get_real(void);
ktime_t ktime_sub(const ktime_t, const ktime_t);
ktime_t ktime_get_monotonic_offset(void);
ktime_t ktime_get_boottime(void);

View File

@ -3,6 +3,7 @@
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Stefan Kalkowski
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
@ -24,38 +25,40 @@ extern struct tvec_base boot_tvec_bases; /* needed by 'dwc_common_linux.c' */
struct timer_list
{
void (*function)(unsigned long);
unsigned long data;
void *timer;
unsigned long expires;
struct tvec_base *base; /* needed by 'dwc_common_linux.c' */
void (*function)(struct timer_list*);
unsigned int flags;
unsigned long data; /* keep for compat with 4.4.3 drivers */
};
void init_timer(struct timer_list *);
void init_timer_deferrable(struct timer_list *);
int mod_timer(struct timer_list *timer, unsigned long expires);
int del_timer(struct timer_list * timer);
void setup_timer(struct timer_list *timer, void (*function)(unsigned long),
unsigned long data);
int timer_pending(const struct timer_list * timer);
int mod_timer(struct timer_list *timer, unsigned long expires);
int del_timer(struct timer_list * timer);
void timer_setup(struct timer_list *timer,
void (*callback)(struct timer_list *), unsigned int flags);
int timer_pending(const struct timer_list * timer);
unsigned long round_jiffies(unsigned long j);
unsigned long round_jiffies_relative(unsigned long j);
unsigned long round_jiffies_up(unsigned long j);
void set_timer_slack(struct timer_list *time, int slack_hz);
static inline void add_timer(struct timer_list *timer) { mod_timer(timer, timer->expires); }
static inline
int del_timer_sync(struct timer_list * timer) { return del_timer(timer); }
static inline void add_timer(struct timer_list *timer) {
mod_timer(timer, timer->expires); }
static inline int del_timer_sync(struct timer_list * timer) {
return del_timer(timer); }
/*********************
** linux/hrtimer.h **
*********************/
enum hrtimer_mode { HRTIMER_MODE_ABS = 0 };
enum hrtimer_restart { HRTIMER_NORESTART = 0 };
enum hrtimer_mode {
HRTIMER_MODE_ABS = 0,
HRTIMER_MODE_REL = 0x1,
HRTIMER_MODE_REL_PINNED = 0x03,
};
enum hrtimer_restart {
HRTIMER_NORESTART,
HRTIMER_RESTART,
};
struct hrtimer
{
@ -64,8 +67,9 @@ struct hrtimer
void *timer;
};
int hrtimer_start_range_ns(struct hrtimer *, ktime_t,
unsigned long, const enum hrtimer_mode);
int hrtimer_start_range_ns(struct hrtimer *, ktime_t,
unsigned long, const enum hrtimer_mode);
void hrtimer_init(struct hrtimer *, clockid_t, enum hrtimer_mode);
int hrtimer_cancel(struct hrtimer *);
int hrtimer_cancel(struct hrtimer *);
bool hrtimer_active(const struct hrtimer *);

View File

@ -106,3 +106,5 @@ typedef u16 wchar_t;
* XXX 'mode_t' is 'unsigned int' on x86_64
*/
typedef unsigned short mode_t;
typedef unsigned slab_flags_t;

View File

@ -20,8 +20,10 @@
***********************/
enum {
WQ_MEM_RECLAIM,
WQ_CPU_INTENSIVE,
WQ_FREEZABLE = 1 << 2,
WQ_MEM_RECLAIM = 1 << 3,
WQ_HIGHPRI = 1 << 4,
WQ_CPU_INTENSIVE = 1 << 5,
};
struct work_struct;
@ -45,13 +47,14 @@ struct delayed_work {
bool cancel_work_sync(struct work_struct *work);
bool cancel_delayed_work_sync(struct delayed_work *work);
bool cancel_delayed_work(struct delayed_work *dwork);
int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
int schedule_work(struct work_struct *work);
int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
int schedule_work(struct work_struct *work);
void flush_scheduled_work(void);
bool flush_work(struct work_struct *work);
bool flush_work_sync(struct work_struct *work);
void delayed_work_timer_fn(struct timer_list *t);
#define PREPARE_WORK(_work, _func) \
do { (_work)->func = (_func); } while (0)
@ -71,7 +74,7 @@ bool flush_work_sync(struct work_struct *work);
#define INIT_DELAYED_WORK(_work, _func) \
do { \
INIT_WORK(&(_work)->work, (_func)); \
init_timer(&(_work)->timer); \
timer_setup(&(_work)->timer, delayed_work_timer_fn, 0); \
} while (0)
@ -87,6 +90,8 @@ void flush_workqueue(struct workqueue_struct *wq);
bool queue_delayed_work(struct workqueue_struct *, struct delayed_work *, unsigned long);
bool flush_delayed_work(struct delayed_work *dwork);
bool queue_work(struct workqueue_struct *wq, struct work_struct *work);
struct work_struct *current_work(void);
void drain_workqueue(struct workqueue_struct *);
#define DECLARE_DELAYED_WORK(n, f) \
struct delayed_work n = { .work = { .func = f }, .timer = { .function = 0 } }
@ -100,6 +105,8 @@ static inline struct delayed_work *to_delayed_work(struct work_struct *work)
}
extern struct workqueue_struct *system_wq;
extern struct workqueue_struct *system_unbound_wq;
extern struct workqueue_struct *system_long_wq;
enum {
WORK_STRUCT_STATIC = 0,
@ -138,28 +145,31 @@ enum {
** linux/wait.h **
******************/
typedef struct wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
typedef struct wait_queue_entry wait_queue_entry_t;
typedef int (*wait_queue_func_t)(wait_queue_entry_t *, unsigned, int, void *);
typedef struct wait_queue_head { void *list; } wait_queue_head_t;
struct wait_queue
{
wait_queue_func_t func;
void *private;
struct wait_queue_entry {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct list_head entry;
};
void init_wait_entry(struct wait_queue_entry *, int);
#define DEFINE_WAIT(name) \
wait_queue_t name;
wait_queue_entry_t name;
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { 0 }
#define DECLARE_WAITQUEUE(name, tsk) \
wait_queue_t name
wait_queue_entry_t name
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
#define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name
wait_queue_entry_t name
/* simplified signature */
void __wake_up(wait_queue_head_t *q, bool all);
@ -176,14 +186,14 @@ int waitqueue_active(wait_queue_head_t *);
void wake_up_interruptible_sync_poll(wait_queue_head_t *, int);
void wake_up_interruptible_poll(wait_queue_head_t *, int);
void prepare_to_wait(wait_queue_head_t *, wait_queue_t *, int);
void prepare_to_wait_exclusive(wait_queue_head_t *, wait_queue_t *, int);
void finish_wait(wait_queue_head_t *, wait_queue_t *);
void prepare_to_wait(wait_queue_head_t *, wait_queue_entry_t *, int);
void prepare_to_wait_exclusive(wait_queue_head_t *, wait_queue_entry_t *, int);
void finish_wait(wait_queue_head_t *, wait_queue_entry_t *);
int autoremove_wake_function(wait_queue_t *, unsigned, int, void *);
void add_wait_queue(wait_queue_head_t *, wait_queue_t *);
void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_t *);
void remove_wait_queue(wait_queue_head_t *, wait_queue_t *);
int autoremove_wake_function(wait_queue_entry_t *, unsigned, int, void *);
void add_wait_queue(wait_queue_head_t *, wait_queue_entry_t *);
void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_entry_t *);
void remove_wait_queue(wait_queue_head_t *, wait_queue_entry_t *);
/* our wait event implementation - it's okay as value */
void ___wait_event(wait_queue_head_t*);

View File

@ -76,6 +76,8 @@ class Lx::Addr_to_page_mapping : public Lx_kit::List<Addr_to_page_mapping>::Elem
return 0;
}
static struct page* find_page_by_paddr(unsigned long paddr);
};

View File

@ -59,6 +59,8 @@ class Lx::Io_port
case 1: _port->outb(port, val); break;
case 2: _port->outw(port, val); break;
case 4: _port->outl(port, val); break;
default:
return false;
}
return true;
@ -74,6 +76,8 @@ class Lx::Io_port
case 1: *val = _port->inb(port); break;
case 2: *val = _port->inw(port); break;
case 4: *val = _port->inl(port); break;
default:
return false;
}
return true;

View File

@ -35,12 +35,14 @@ namespace Lx {
/**
* Return singleton 'Platform::Connection'
*
* Implementation must be privided by the driver.
* Implementation must be provided by the driver.
*/
Platform::Connection *pci();
template <typename FUNC>
static inline void for_each_pci_device(FUNC const &func);
static inline void for_each_pci_device(FUNC const &func,
unsigned const device_class = 0,
unsigned const class_mask = 0);
}
@ -220,7 +222,8 @@ class Lx::Pci_dev : public pci_dev, public Lx_kit::List<Pci_dev>::Element
* released at the platform driver.
*/
template <typename FUNC>
void Lx::for_each_pci_device(FUNC const &func)
void Lx::for_each_pci_device(FUNC const &func, unsigned const device_class,
unsigned const class_mask)
{
/*
* Obtain first device, the operation may exceed the session quota.
@ -228,7 +231,7 @@ void Lx::for_each_pci_device(FUNC const &func)
*/
Platform::Device_capability cap =
Lx::pci()->with_upgrade([&] () {
return Lx::pci()->first_device(); });
return Lx::pci()->first_device(device_class, class_mask); });
/*
* Iterate over the devices of the platform session.
@ -247,7 +250,7 @@ void Lx::for_each_pci_device(FUNC const &func)
*/
Platform::Device_capability next_cap =
Lx::pci()->with_upgrade([&] () {
return pci()->next_device(cap); });
return pci()->next_device(cap, device_class, class_mask); });
Lx::pci()->release_device(cap);
cap = next_cap;

View File

@ -17,6 +17,7 @@
/* Linux emulation environment includes */
#include <lx_kit/pci.h>
#include <lx_kit/internal/pci_dev.h>
#include <io_port_session/connection.h>
namespace Lx {
@ -27,7 +28,7 @@ namespace Lx {
*
* Implementation must be provided by the driver.
*/
Pci_dev_registry *pci_dev_registry();
Pci_dev_registry *pci_dev_registry(Genode::Env *env = nullptr);
}
@ -35,15 +36,23 @@ class Lx::Pci_dev_registry
{
private:
Lx_kit::List<Pci_dev> _devs;
Lx_kit::List<Pci_dev> _devs;
Genode::Env &_env;
public:
Pci_dev_registry(Genode::Env &env) : _env(env) { }
void insert(Pci_dev *pci_dev)
{
_devs.insert(pci_dev);
}
void remove(Pci_dev *pci_dev)
{
_devs.remove(pci_dev);
}
Pci_dev* first() { return _devs.first(); }
Genode::Io_mem_dataspace_capability io_mem(Genode::addr_t phys,
@ -89,17 +98,50 @@ class Lx::Pci_dev_registry
return value;
}
try {
Genode::Io_port_connection iox(_env, port, sizeof(T));
switch (sizeof(T)) {
case 1:
return iox.inb(port);
case 2:
return iox.inw(port);
case 4:
return iox.inl(port);
}
} catch (...) {
Genode::error("unknown exception io_read");
}
Genode::warning("I/O port(", port, ") read failed");
return (T)~0;
return (T)~0U;
}
template <typename T>
void io_write(unsigned port, T value)
{
/* try I/O access on all PCI devices, return on first success */
for (Pci_dev *d = _devs.first(); d; d = d->next())
for (Pci_dev *d = _devs.first(); d; d = d->next()) {
if (d->io_port().out<T>(port, value))
return;
}
try {
Genode::Io_port_connection iox(_env, port, sizeof(T));
switch (sizeof(T)) {
case 1:
iox.outb(port, value);
return;
case 2:
iox.outw(port, value);
return;
case 4:
iox.outl(port, value);
return;
}
} catch (...) {
Genode::error("unknown exception io_write");
}
Genode::warning("I/O port(", port, ") write failed");
}

View File

@ -19,6 +19,7 @@
namespace Lx {
class Work;
class Task;
}
@ -34,16 +35,23 @@ class Lx::Work
*/
virtual void unblock() = 0;
/**
* Execute all queued work items
*
* The calling task is woken up afterwards.
*/
virtual void flush(Task &) = 0;
/**
* Wakeup calling task after work item was executed
*/
virtual void wakeup_for(void const * const, Task &) = 0;
/**
* Schedule work
*/
virtual void schedule(struct ::work_struct *) = 0;
/**
* Schedule delayed work
*/
virtual void schedule_delayed(struct ::delayed_work *, unsigned long delay) = 0;
/**
* Schedule delayed work
*/
@ -53,6 +61,11 @@ class Lx::Work
* Cancel work item
*/
virtual bool cancel_work(struct ::work_struct *, bool sync = false) = 0;
/**
* Check if work is currently queued
*/
virtual bool work_queued(void const * const) = 0;
/**
* Return task name

View File

@ -90,6 +90,8 @@ void Lx::pci_init(Genode::Env &env, Genode::Ram_session &ram,
_global_pci.construct(env);
_global_ram = &ram;
_global_md_alloc = &md_alloc;
Lx::pci_dev_registry(&env);
}
@ -99,9 +101,9 @@ Platform::Connection *Lx::pci()
}
Lx::Pci_dev_registry *Lx::pci_dev_registry()
Lx::Pci_dev_registry *Lx::pci_dev_registry(Genode::Env *env)
{
static Lx::Pci_dev_registry _pci_dev_registry;
static Lx::Pci_dev_registry _pci_dev_registry(*env);
return &_pci_dev_registry;
}

View File

@ -76,7 +76,7 @@ class Lx::Format_command
if (!format[++consumed]) return;
/* check for %$x syntax */
prefix = (format[consumed] == '#');
prefix = (format[consumed] == '#') || (format[consumed] == '.');
if (prefix && !format[++consumed]) return;
/* heading zero indicates zero-padding */

View File

@ -61,7 +61,7 @@ class Lx_kit::Timer : public Lx::Timer
{
timer_list *t = static_cast<timer_list *>(timer);
if (t->function)
t->function(t->data);
t->function(t);
}
break;

View File

@ -36,6 +36,8 @@ class Lx_kit::Work : public Lx::Work
*/
struct Context : public Lx_kit::List<Context>::Element
{
Lx::Task *waiting_task { nullptr };
void *work;
enum Type { NORMAL, DELAYED, TASKLET } type;
@ -86,6 +88,9 @@ class Lx_kit::Work : public Lx::Work
public:
Lx::Task *_waiting_task = nullptr;
Work(Genode::Allocator &alloc, char const *name = "work_queue")
: _task(Work::run_work, reinterpret_cast<void*>(this), name,
Lx::Task::PRIORITY_2, Lx::scheduler()),
@ -99,6 +104,12 @@ class Lx_kit::Work : public Lx::Work
while (Context *c = _list.first()) {
_list.remove(c);
c->exec();
if (c->waiting_task) {
c->waiting_task->unblock();
c->waiting_task = nullptr;
}
destroy(&_work_alloc, c);
}
}
@ -108,6 +119,12 @@ class Lx_kit::Work : public Lx::Work
Work *work_queue = reinterpret_cast<Work*>(wq);
while (1) {
work_queue->exec();
if (work_queue->_waiting_task) {
work_queue->_waiting_task->unblock();
work_queue->_waiting_task = nullptr;
}
Lx::scheduler().current()->block_and_schedule();
}
}
@ -116,15 +133,41 @@ class Lx_kit::Work : public Lx::Work
** Lx::Work interface **
************************/
void unblock() { _task.unblock(); }
void unblock()
{
_task.unblock();
}
void flush(Lx::Task &task)
{
_task.unblock();
_waiting_task = &task;
}
void wakeup_for(void const * const work, Lx::Task &task)
{
Context *ctx = nullptr;
for (Context *c = _list.first(); c; c = c->next()) {
if (c->work == work) {
ctx = c;
break;
}
}
if (!ctx) {
Genode::error("BUG: no work queued for wakeup_for call");
Genode::sleep_forever();
}
ctx->waiting_task = &task;
_task.unblock();
}
void schedule(struct work_struct *work) {
_schedule(work); }
void schedule_delayed(struct delayed_work *work,
unsigned long /*delay*/) {
_schedule(work); }
void schedule_tasklet(struct tasklet_struct *tasklet) {
_schedule(tasklet); }
@ -144,6 +187,17 @@ class Lx_kit::Work : public Lx::Work
return false;
}
bool work_queued(void const * const work)
{
for (Context *c = _list.first(); c; c = c->next()) {
if (c->work == work) {
return true;
}
}
return false;
}
char const *task_name() override { return _task.name(); }
};