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) } #define ATOMIC_INIT(i) { (i) }
typedef struct atomic { long counter; } atomic_t; typedef struct atomic { int counter; } atomic_t;
typedef atomic_t atomic_long_t; typedef struct { long counter; } atomic_long_t;
static inline int atomic_read(const atomic_t *p) { return p->counter; } 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; } 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_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 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_inc(atomic_long_t *p) { p->counter += 1; }
static inline void atomic_long_sub(int i, atomic_long_t *p) { atomic_sub(i, p); } 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) { return atomic_add_return(i, p); } 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 atomic_read(p); } 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) 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; 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() #define smp_mb__before_atomic_dec()

View File

@ -30,6 +30,7 @@
#define BIT(nr) (1UL << (nr)) #define BIT(nr) (1UL << (nr))
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #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_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((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) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1)) (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) { static inline int get_bitmask_order(unsigned int count) {
return __builtin_clz(count) ^ 0x1f; } return __builtin_clz(count) ^ 0x1f; }
@ -109,3 +115,7 @@ static inline __u16 ror16(__u16 word, unsigned int shift)
return (word >> shift) | (word << (16 - 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 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) ({ \ #define BUILD_BUG_ON_MSG(cond,msg) ({ \
extern int __attribute__((error(msg))) build_bug(); \ extern int __attribute__((error(msg))) build_bug(); \
if (cond) { build_bug(); } }) if (cond) { build_bug(); } })
#define BUILD_BUG() BUILD_BUG_ON_MSG(1,"BUILD_BUG failed") #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) \ #define WRITE_ONCE(x, val) \
({ \ ({ \
barrier(); \ 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(); \ 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 ** ** linux/compiler-gcc.h **
@ -73,5 +78,9 @@
#define __packed __attribute__((packed)) #define __packed __attribute__((packed))
#endif #endif
#define __aligned(x) __attribute__((aligned(x)))
#define uninitialized_var(x) x = x #define uninitialized_var(x) x = x
#define unreachable() \
do { __builtin_unreachable(); } while (0)

View File

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

View File

@ -35,6 +35,8 @@ enum {
EIO = 5, EIO = 5,
ENXIO = 6, ENXIO = 6,
E2BIG = 7, E2BIG = 7,
ENOEXEC = 8,
EBADF = 9,
EDEADLK = 11, EDEADLK = 11,
ENOMEM = 12, ENOMEM = 12,
EACCES = 13, EACCES = 13,
@ -103,6 +105,8 @@ enum {
EPROBE_DEFER = 210, EPROBE_DEFER = 210,
EL3RST = 211, EL3RST = 211,
ENOKEY = 212,
ECHRNG = 213,
MAX_ERRNO = 4095, MAX_ERRNO = 4095,
}; };
@ -112,10 +116,10 @@ enum {
** linux/err.h ** ** 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) { 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) { static inline void * ERR_PTR(long error) {
return (void *) error; } return (void *) error; }

View File

@ -24,13 +24,12 @@ enum {
__GFP_HIGHMEM = 0x00000002u, __GFP_HIGHMEM = 0x00000002u,
__GFP_DMA32 = 0x00000004u, __GFP_DMA32 = 0x00000004u,
__GFP_MOVABLE = 0x00000008u, __GFP_MOVABLE = 0x00000008u,
__GFP_WAIT = 0x00000010u, __GFP_RECLAIMABLE = 0x00000010u,
__GFP_HIGH = 0x00000020u, __GFP_HIGH = 0x00000020u,
__GFP_IO = 0x00000040u, __GFP_IO = 0x00000040u,
__GFP_FS = 0x00000080u, __GFP_FS = 0x00000080u,
__GFP_COLD = 0x00000100u,
__GFP_NOWARN = 0x00000200u, __GFP_NOWARN = 0x00000200u,
__GFP_REPEAT = 0x00000400u, __GFP_RETRY_MAYFAIL = 0x00000400u,
__GFP_NOFAIL = 0x00000800u, __GFP_NOFAIL = 0x00000800u,
__GFP_NORETRY = 0x00001000u, __GFP_NORETRY = 0x00001000u,
__GFP_MEMALLOC = 0x00002000u, __GFP_MEMALLOC = 0x00002000u,
@ -39,24 +38,24 @@ enum {
__GFP_NOMEMALLOC = 0x00010000u, __GFP_NOMEMALLOC = 0x00010000u,
__GFP_HARDWALL = 0x00020000u, __GFP_HARDWALL = 0x00020000u,
__GFP_THISNODE = 0x00040000u, __GFP_THISNODE = 0x00040000u,
__GFP_RECLAIMABLE = 0x00080000u, __GFP_ATOMIC = 0x00080000u,
__GFP_KMEMCG = 0x00100000u, __GFP_ACCOUNT = 0x00100000u,
__GFP_NOTRACK = 0x00200000u, __GFP_DIRECT_RECLAIM = 0x00200000u,
__GFP_NO_KSWAPD = 0x00400000u, __GFP_WRITE = 0x00800000u,
__GFP_OTHER_NODE = 0x00800000u, __GFP_KSWAPD_RECLAIM = 0x01000000u,
__GFP_WRITE = 0x01000000u,
__GFP_DIRECT_RECLAIM = 0x400000u,
__GFP_KSWAPD_RECLAIM = 0x2000000u,
GFP_LX_DMA = 0x80000000u, GFP_LX_DMA = 0x80000000u,
__GFP_RECLAIM = __GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM, __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_DMA = __GFP_DMA,
GFP_DMA32 = __GFP_DMA32, 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_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_USER = __GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL,
__GFP_HIGHMEM, 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; wq->list = new (&Lx_kit::env().heap()) Wait_list;
} }
void add_wait_queue(wait_queue_head_t *q, wait_queue_entry_t *wait)
void remove_wait_queue(wait_queue_head_t *wq, wait_queue_t *wait)
{ {
Wait_list *list = static_cast<Wait_list*>(wq->list); printk("%s called\n", __func__);
if (!list) { return; } }
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) void complete(struct completion *work)
{ {
work->done = 1; if (work->done != UINT_MAX)
work->done++;
Lx::Task *task = static_cast<Lx::Task*>(work->task); Lx::Task *task = static_cast<Lx::Task*>(work->task);
if (task) { task->unblock(); } 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 wait_for_completion_timeout(struct completion *work,
unsigned long timeout) unsigned long timeout)

View File

@ -34,7 +34,11 @@ static inline void __delay_timer(unsigned long usecs)
_delay_timer->usleep(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) void msleep(unsigned int msecs)

View File

@ -18,13 +18,18 @@
#include <lx_kit/env.h> #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); struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
size_t size = PAGE_SIZE << order; 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->addr = Lx_kit::env().rm().attach(ds_cap);
page->paddr = Genode::Dataspace_client(ds_cap).phys_addr(); page->paddr = Genode::Dataspace_client(ds_cap).phys_addr();
@ -57,3 +62,9 @@ void get_page(struct page *page)
{ {
atomic_inc(&page->_count); 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); Lx::Task::List *waiters = static_cast<Lx::Task::List *>(m->waiters);
/* FIXME potentially blocked tasks are not unblocked */ /* FIXME potentially blocked tasks are not unblocked */
if (waiters->first()) { if (waiters && waiters->first()) {
Genode::error(__func__, "destroying non-empty waiters list"); Genode::error(__func__, "destroying non-empty waiters list");
} }

View File

@ -1,6 +1,7 @@
/* /*
* \brief Implementation of linux/sched.h * \brief Implementation of linux/sched.h
* \author Norman Feske * \author Norman Feske
* \author Stefan Kalkowski
* \date 2015-09-09 * \date 2015-09-09
*/ */
@ -14,26 +15,33 @@
/* Linux kit includes */ /* Linux kit includes */
#include <lx_kit/scheduler.h> #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; struct process_timer *timeout = from_timer(timeout, list, timer);
timeout->task.unblock();
t->unblock();
} }
signed long schedule_timeout(signed long timeout) 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; unsigned long expire = timeout + jiffies;
setup_timer(&timer, unblock_task, (unsigned long)Lx::scheduler().current()); mod_timer(&timer.timer, expire);
mod_timer(&timer, expire);
Lx::scheduler().current()->block_and_schedule(); cur_task.block_and_schedule();
del_timer(&timer); del_timer(&timer.timer);
timeout = (expire - jiffies); 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) void *kzalloc_node(size_t size, gfp_t flags, int node)
{ {
return kzalloc(size, 0); 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) void kmem_cache_destroy(struct kmem_cache *cache)
{ {
destroy(Lx::Malloc::mem(), cache); destroy(Lx::Malloc::mem(), cache);

View File

@ -15,9 +15,6 @@
#include <lx_kit/timer.h> #include <lx_kit/timer.h>
void init_timer(struct timer_list *timer) { }
int mod_timer(struct timer_list *timer, unsigned long expires) int mod_timer(struct timer_list *timer, unsigned long expires)
{ {
if (!Lx::timer().find(timer)) 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), void timer_setup(struct timer_list *timer,
unsigned long data) void (*function)(struct timer_list *),
unsigned int flags)
{ {
timer->function = function; timer->function = function;
timer->data = data; timer->flags = flags;
init_timer(timer);
} }
@ -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, int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
unsigned long delta_ns, const enum hrtimer_mode mode) 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 * 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 hrtimer_cancel(struct hrtimer *timer)
{ {
int rv = Lx::timer().del(timer); int rv = Lx::timer().del(timer);

View File

@ -15,7 +15,7 @@
#include <lx_kit/scheduler.h> #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; } 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); 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; } if (!q) { return; }

View File

@ -27,6 +27,13 @@ bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
{ {
work->wq = wq; 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 */ /* check for separate work queue task */
if (wq && wq->task) { if (wq && wq->task) {
Lx::Work *lx_work = (Lx::Work *)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; struct delayed_work *dwork = from_timer(dwork, t, timer);
workqueue_struct *wq = work->wq; queue_work(dwork->wq, &dwork->work);
/* 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();
}
} }
@ -65,10 +62,10 @@ bool queue_delayed_work(struct workqueue_struct *wq,
/* treat delayed work without delay like any other work */ /* treat delayed work without delay like any other work */
if (delay == 0) { if (delay == 0) {
_schedule_delayed_work((unsigned long)dwork); delayed_work_timer_fn(&dwork->timer);
} else { } else {
setup_timer(&dwork->timer, _schedule_delayed_work, (unsigned long)dwork); timer_setup(&dwork->timer, delayed_work_timer_fn, 0);
mod_timer(&dwork->timer, delay); mod_timer(&dwork->timer, jiffies + delay);
} }
return true; 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) 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); bool pending = cancel_delayed_work(dwork);
if (pending) { if (pending) {
Genode::warning("WARN: delayed_work ", dwork, " is executed directly in "
"current '", Lx::scheduler().current()->name(), "' routine");
dwork->work.func(&dwork->work); dwork->work.func(&dwork->work);
} }
return pending; return pending;
} }

View File

@ -22,6 +22,9 @@
#define IORESOURCE_IO 0x00000100 #define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200 #define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_UNSET 0x20000000
#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
struct resource struct resource
{ {
@ -31,6 +34,20 @@ struct resource
unsigned long flags; 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 device;
struct resource *request_region(resource_size_t start, resource_size_t n, 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_region(resource_size_t start, resource_size_t n);
void release_mem_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 ** ** linux/kconfig.h **
*********************/ *********************/
#define IS_ENABLED(x) x #define __ARG_PLACEHOLDER_1 0,
#define IS_BUILTIN(x) x #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 ** ** linux/kernel.h **
@ -185,3 +189,4 @@ void might_sleep();
#define swap(a, b) \ #define swap(a, b) \
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) 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_POISON1 nullptr
#define LIST_POISON2 nullptr #define LIST_POISON2 nullptr
#else #else
#define LIST_POISON1 ((void *)0x00100100) #define LIST_POISON1 ((void *)0x00000100)
#define LIST_POISON2 ((void *)0x00200200) #define LIST_POISON2 ((void *)0x00000200)
#endif /* __cplusplus */ #endif /* __cplusplus */
#define POISON_INUSE 0x5a
/****************** /******************
** linux/list.h ** ** linux/list.h **

View File

@ -50,7 +50,7 @@
struct module; 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(); } #define module_exit(fn) void module_exit_##fn(void) { fn(); }
void module_put_and_exit(int); 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 struct dev_pm_info
{ {
pm_message_t power_state; pm_message_t power_state;
bool is_prepared; bool is_prepared:1;
bool is_suspended:1;
atomic_t usage_count;
}; };
struct dev_pm_ops { 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 up_read(struct rw_semaphore *sem);
void down_write(struct rw_semaphore *sem); void down_write(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem); void up_write(struct rw_semaphore *sem);
int down_write_killable(struct rw_semaphore *);
#define __RWSEM_INITIALIZER(name) { 0 } #define __RWSEM_INITIALIZER(name) { 0 }

View File

@ -20,10 +20,12 @@
**********************/ **********************/
typedef struct spinlock { unsigned unused; } spinlock_t; typedef struct spinlock { unsigned unused; } spinlock_t;
typedef struct raw_spinlock { unsigned dummy; } raw_spinlock_t;
#define DEFINE_SPINLOCK(name) spinlock_t name #define DEFINE_SPINLOCK(name) spinlock_t name
void spin_lock(spinlock_t *lock); void spin_lock(spinlock_t *lock);
void spin_lock_nested(spinlock_t *lock, int subclass); 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_unlock(spinlock_t *lock);
void spin_lock_init(spinlock_t *lock); void spin_lock_init(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); 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); void spin_unlock_bh(spinlock_t *lock);
int spin_trylock(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 ** ** linux/spinlock_types.h **

View File

@ -50,9 +50,21 @@ enum {
** linux/ktime.h ** ** 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); 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); 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) 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) 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) 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); s64 ktime_us_delta(const ktime_t later, const ktime_t earlier);
static inline struct timeval ktime_to_timeval(const ktime_t kt) static inline struct timeval ktime_to_timeval(const ktime_t kt)
{ {
struct timeval tv; struct timeval tv;
tv.tv_sec = kt.tv64 / NSEC_PER_SEC; tv.tv_sec = kt / NSEC_PER_SEC;
tv.tv_usec = (kt.tv64 - (tv.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC; tv.tv_usec = (kt - (tv.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC;
return tv; 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_sub(const ktime_t, const ktime_t);
ktime_t ktime_get_monotonic_offset(void); ktime_t ktime_get_monotonic_offset(void);
ktime_t ktime_get_boottime(void);

View File

@ -3,6 +3,7 @@
* \author Norman Feske * \author Norman Feske
* \author Sebastian Sumpf * \author Sebastian Sumpf
* \author Josef Soentgen * \author Josef Soentgen
* \author Stefan Kalkowski
* \date 2014-08-21 * \date 2014-08-21
* *
* Based on the prototypes found in the Linux kernel's 'include/'. * 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 struct timer_list
{ {
void (*function)(unsigned long);
unsigned long data;
void *timer;
unsigned long expires; 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 *); int mod_timer(struct timer_list *timer, unsigned long expires);
void init_timer_deferrable(struct timer_list *); int del_timer(struct timer_list * timer);
int mod_timer(struct timer_list *timer, unsigned long expires); void timer_setup(struct timer_list *timer,
int del_timer(struct timer_list * timer); void (*callback)(struct timer_list *), unsigned int flags);
void setup_timer(struct timer_list *timer, void (*function)(unsigned long), int timer_pending(const struct timer_list * timer);
unsigned long data);
int timer_pending(const struct timer_list * timer);
unsigned long round_jiffies(unsigned long j); unsigned long round_jiffies(unsigned long j);
unsigned long round_jiffies_relative(unsigned long j); unsigned long round_jiffies_relative(unsigned long j);
unsigned long round_jiffies_up(unsigned long j); unsigned long round_jiffies_up(unsigned long j);
static inline void add_timer(struct timer_list *timer) {
void set_timer_slack(struct timer_list *time, int slack_hz); mod_timer(timer, timer->expires); }
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
int del_timer_sync(struct timer_list * timer) { return del_timer(timer); }
/********************* /*********************
** linux/hrtimer.h ** ** linux/hrtimer.h **
*********************/ *********************/
enum hrtimer_mode { HRTIMER_MODE_ABS = 0 }; enum hrtimer_mode {
enum hrtimer_restart { HRTIMER_NORESTART = 0 }; HRTIMER_MODE_ABS = 0,
HRTIMER_MODE_REL = 0x1,
HRTIMER_MODE_REL_PINNED = 0x03,
};
enum hrtimer_restart {
HRTIMER_NORESTART,
HRTIMER_RESTART,
};
struct hrtimer struct hrtimer
{ {
@ -64,8 +67,9 @@ struct hrtimer
void *timer; void *timer;
}; };
int hrtimer_start_range_ns(struct hrtimer *, ktime_t, int hrtimer_start_range_ns(struct hrtimer *, ktime_t,
unsigned long, const enum hrtimer_mode); unsigned long, const enum hrtimer_mode);
void hrtimer_init(struct hrtimer *, clockid_t, 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 * XXX 'mode_t' is 'unsigned int' on x86_64
*/ */
typedef unsigned short mode_t; typedef unsigned short mode_t;
typedef unsigned slab_flags_t;

View File

@ -20,8 +20,10 @@
***********************/ ***********************/
enum { enum {
WQ_MEM_RECLAIM, WQ_FREEZABLE = 1 << 2,
WQ_CPU_INTENSIVE, WQ_MEM_RECLAIM = 1 << 3,
WQ_HIGHPRI = 1 << 4,
WQ_CPU_INTENSIVE = 1 << 5,
}; };
struct work_struct; struct work_struct;
@ -45,13 +47,14 @@ struct delayed_work {
bool cancel_work_sync(struct work_struct *work); bool cancel_work_sync(struct work_struct *work);
bool cancel_delayed_work_sync(struct delayed_work *work); bool cancel_delayed_work_sync(struct delayed_work *work);
bool cancel_delayed_work(struct delayed_work *dwork); bool cancel_delayed_work(struct delayed_work *dwork);
int schedule_delayed_work(struct delayed_work *work, unsigned long delay); int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
int schedule_work(struct work_struct *work); int schedule_work(struct work_struct *work);
void flush_scheduled_work(void); void flush_scheduled_work(void);
bool flush_work(struct work_struct *work); bool flush_work(struct work_struct *work);
bool flush_work_sync(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) \ #define PREPARE_WORK(_work, _func) \
do { (_work)->func = (_func); } while (0) do { (_work)->func = (_func); } while (0)
@ -71,7 +74,7 @@ bool flush_work_sync(struct work_struct *work);
#define INIT_DELAYED_WORK(_work, _func) \ #define INIT_DELAYED_WORK(_work, _func) \
do { \ do { \
INIT_WORK(&(_work)->work, (_func)); \ INIT_WORK(&(_work)->work, (_func)); \
init_timer(&(_work)->timer); \ timer_setup(&(_work)->timer, delayed_work_timer_fn, 0); \
} while (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 queue_delayed_work(struct workqueue_struct *, struct delayed_work *, unsigned long);
bool flush_delayed_work(struct delayed_work *dwork); bool flush_delayed_work(struct delayed_work *dwork);
bool queue_work(struct workqueue_struct *wq, struct work_struct *work); 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) \ #define DECLARE_DELAYED_WORK(n, f) \
struct delayed_work n = { .work = { .func = f }, .timer = { .function = 0 } } 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_wq;
extern struct workqueue_struct *system_unbound_wq;
extern struct workqueue_struct *system_long_wq;
enum { enum {
WORK_STRUCT_STATIC = 0, WORK_STRUCT_STATIC = 0,
@ -138,28 +145,31 @@ enum {
** linux/wait.h ** ** linux/wait.h **
******************/ ******************/
typedef struct wait_queue wait_queue_t; typedef struct wait_queue_entry wait_queue_entry_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key); typedef int (*wait_queue_func_t)(wait_queue_entry_t *, unsigned, int, void *);
typedef struct wait_queue_head { void *list; } wait_queue_head_t; typedef struct wait_queue_head { void *list; } wait_queue_head_t;
struct wait_queue struct wait_queue_entry {
{ unsigned int flags;
wait_queue_func_t func; void *private;
void *private; wait_queue_func_t func;
struct list_head entry;
}; };
void init_wait_entry(struct wait_queue_entry *, int);
#define DEFINE_WAIT(name) \ #define DEFINE_WAIT(name) \
wait_queue_t name; wait_queue_entry_t name;
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { 0 } #define __WAIT_QUEUE_HEAD_INITIALIZER(name) { 0 }
#define DECLARE_WAITQUEUE(name, tsk) \ #define DECLARE_WAITQUEUE(name, tsk) \
wait_queue_t name wait_queue_entry_t name
#define DECLARE_WAIT_QUEUE_HEAD(name) \ #define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
#define DEFINE_WAIT_FUNC(name, function) \ #define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name wait_queue_entry_t name
/* simplified signature */ /* simplified signature */
void __wake_up(wait_queue_head_t *q, bool all); 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_sync_poll(wait_queue_head_t *, int);
void wake_up_interruptible_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(wait_queue_head_t *, wait_queue_entry_t *, int);
void prepare_to_wait_exclusive(wait_queue_head_t *, wait_queue_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_t *); void finish_wait(wait_queue_head_t *, wait_queue_entry_t *);
int autoremove_wake_function(wait_queue_t *, unsigned, int, void *); int autoremove_wake_function(wait_queue_entry_t *, unsigned, int, void *);
void add_wait_queue(wait_queue_head_t *, wait_queue_t *); void add_wait_queue(wait_queue_head_t *, wait_queue_entry_t *);
void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_t *); void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_entry_t *);
void remove_wait_queue(wait_queue_head_t *, wait_queue_t *); void remove_wait_queue(wait_queue_head_t *, wait_queue_entry_t *);
/* our wait event implementation - it's okay as value */ /* our wait event implementation - it's okay as value */
void ___wait_event(wait_queue_head_t*); 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; 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 1: _port->outb(port, val); break;
case 2: _port->outw(port, val); break; case 2: _port->outw(port, val); break;
case 4: _port->outl(port, val); break; case 4: _port->outl(port, val); break;
default:
return false;
} }
return true; return true;
@ -74,6 +76,8 @@ class Lx::Io_port
case 1: *val = _port->inb(port); break; case 1: *val = _port->inb(port); break;
case 2: *val = _port->inw(port); break; case 2: *val = _port->inw(port); break;
case 4: *val = _port->inl(port); break; case 4: *val = _port->inl(port); break;
default:
return false;
} }
return true; return true;

View File

@ -35,12 +35,14 @@ namespace Lx {
/** /**
* Return singleton 'Platform::Connection' * Return singleton 'Platform::Connection'
* *
* Implementation must be privided by the driver. * Implementation must be provided by the driver.
*/ */
Platform::Connection *pci(); Platform::Connection *pci();
template <typename FUNC> 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. * released at the platform driver.
*/ */
template <typename FUNC> 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. * 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 = Platform::Device_capability cap =
Lx::pci()->with_upgrade([&] () { 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. * 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 = Platform::Device_capability next_cap =
Lx::pci()->with_upgrade([&] () { Lx::pci()->with_upgrade([&] () {
return pci()->next_device(cap); }); return pci()->next_device(cap, device_class, class_mask); });
Lx::pci()->release_device(cap); Lx::pci()->release_device(cap);
cap = next_cap; cap = next_cap;

View File

@ -17,6 +17,7 @@
/* Linux emulation environment includes */ /* Linux emulation environment includes */
#include <lx_kit/pci.h> #include <lx_kit/pci.h>
#include <lx_kit/internal/pci_dev.h> #include <lx_kit/internal/pci_dev.h>
#include <io_port_session/connection.h>
namespace Lx { namespace Lx {
@ -27,7 +28,7 @@ namespace Lx {
* *
* Implementation must be provided by the driver. * 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: private:
Lx_kit::List<Pci_dev> _devs; Lx_kit::List<Pci_dev> _devs;
Genode::Env &_env;
public: public:
Pci_dev_registry(Genode::Env &env) : _env(env) { }
void insert(Pci_dev *pci_dev) void insert(Pci_dev *pci_dev)
{ {
_devs.insert(pci_dev); _devs.insert(pci_dev);
} }
void remove(Pci_dev *pci_dev)
{
_devs.remove(pci_dev);
}
Pci_dev* first() { return _devs.first(); } Pci_dev* first() { return _devs.first(); }
Genode::Io_mem_dataspace_capability io_mem(Genode::addr_t phys, Genode::Io_mem_dataspace_capability io_mem(Genode::addr_t phys,
@ -89,17 +98,50 @@ class Lx::Pci_dev_registry
return value; 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"); Genode::warning("I/O port(", port, ") read failed");
return (T)~0;
return (T)~0U;
} }
template <typename T> template <typename T>
void io_write(unsigned port, T value) void io_write(unsigned port, T value)
{ {
/* try I/O access on all PCI devices, return on first success */ /* 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)) if (d->io_port().out<T>(port, value))
return; 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"); Genode::warning("I/O port(", port, ") write failed");
} }

View File

@ -19,6 +19,7 @@
namespace Lx { namespace Lx {
class Work; class Work;
class Task;
} }
@ -34,16 +35,23 @@ class Lx::Work
*/ */
virtual void unblock() = 0; 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 * Schedule work
*/ */
virtual void schedule(struct ::work_struct *) = 0; virtual void schedule(struct ::work_struct *) = 0;
/**
* Schedule delayed work
*/
virtual void schedule_delayed(struct ::delayed_work *, unsigned long delay) = 0;
/** /**
* Schedule delayed work * Schedule delayed work
*/ */
@ -53,6 +61,11 @@ class Lx::Work
* Cancel work item * Cancel work item
*/ */
virtual bool cancel_work(struct ::work_struct *, bool sync = false) = 0; 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 * 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_pci.construct(env);
_global_ram = &ram; _global_ram = &ram;
_global_md_alloc = &md_alloc; _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; return &_pci_dev_registry;
} }

View File

@ -76,7 +76,7 @@ class Lx::Format_command
if (!format[++consumed]) return; if (!format[++consumed]) return;
/* check for %$x syntax */ /* check for %$x syntax */
prefix = (format[consumed] == '#'); prefix = (format[consumed] == '#') || (format[consumed] == '.');
if (prefix && !format[++consumed]) return; if (prefix && !format[++consumed]) return;
/* heading zero indicates zero-padding */ /* 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); timer_list *t = static_cast<timer_list *>(timer);
if (t->function) if (t->function)
t->function(t->data); t->function(t);
} }
break; break;

View File

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