mirror of
https://github.com/drasko/codezero.git
synced 2026-04-17 17:29:04 +02:00
Fixed few more anomalies with threaded irqs.
There is a bug that causes the sleeping irq thread to never wake up. Investigating.
This commit is contained in:
@@ -63,6 +63,9 @@ BEGIN_PROC(__l4_mutex_unlock)
|
|||||||
mov pc, lr
|
mov pc, lr
|
||||||
END_PROC(__l4_mutex_unlock)
|
END_PROC(__l4_mutex_unlock)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r0 = byte address to read from.
|
||||||
|
*/
|
||||||
BEGIN_PROC(l4_atomic_dest_readb)
|
BEGIN_PROC(l4_atomic_dest_readb)
|
||||||
mov r1, r0 @ Move byte address to r1
|
mov r1, r0 @ Move byte address to r1
|
||||||
mov r2, #0 @ Move 0 to r2
|
mov r2, #0 @ Move 0 to r2
|
||||||
|
|||||||
@@ -42,17 +42,20 @@ static inline void disable_irqs()
|
|||||||
/* Disable the irqs unconditionally, but also keep the previous state such that
|
/* Disable the irqs unconditionally, but also keep the previous state such that
|
||||||
* if it was already disabled before the call, the restore call would retain
|
* if it was already disabled before the call, the restore call would retain
|
||||||
* this state. */
|
* this state. */
|
||||||
static inline void irq_local_disable_save(unsigned long *state)
|
void irq_local_disable_save(unsigned long *state);
|
||||||
|
#if 0
|
||||||
{
|
{
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
__asm__ __volatile__ (
|
__asm__ __volatile__ (
|
||||||
"mrs %0, cpsr_fc\n"
|
"mrs %0, cpsr_fc\n"
|
||||||
"orr %1, %0, #0x80\n"
|
"orr %2, %0, #0x80\n"
|
||||||
"msr cpsr_fc, %1\n"
|
"msr cpsr_fc, %2\n"
|
||||||
: "=r" (*state)
|
: "=r" (*state)
|
||||||
: "r" (*state),"r" (temp)
|
: "r" (*state),"r" (temp)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Simply change it back to original state supplied in @flags. This might enable
|
/* Simply change it back to original state supplied in @flags. This might enable
|
||||||
* or retain disabled state of the irqs for example. Useful for nested calls. */
|
* or retain disabled state of the irqs for example. Useful for nested calls. */
|
||||||
static inline void irq_local_restore(unsigned long state)
|
static inline void irq_local_restore(unsigned long state)
|
||||||
|
|||||||
11
include/l4/arch/arm/v5/irq.h
Normal file
11
include/l4/arch/arm/v5/irq.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __ARM_V5_IRQ_H__
|
||||||
|
#define __ARM_V5_IRQ_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Destructive atomic-read.
|
||||||
|
*
|
||||||
|
* Write 0 to byte at @location as its contents are read back.
|
||||||
|
*/
|
||||||
|
char l4_atomic_dest_readb(void *location);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -73,7 +73,8 @@
|
|||||||
#define MR0_REGISTER r3
|
#define MR0_REGISTER r3
|
||||||
#define MR_RETURN_REGISTER r3
|
#define MR_RETURN_REGISTER r3
|
||||||
|
|
||||||
#define TASK_NOTIFY_MAX 8
|
#define TASK_NOTIFY_SLOTS 8
|
||||||
|
#define TASK_NOTIFY_MAXVALUE 255
|
||||||
|
|
||||||
/* Primaries aren't used for memcopy. Those ops use this as a parameter */
|
/* Primaries aren't used for memcopy. Those ops use this as a parameter */
|
||||||
#define L4_UTCB_FULL_BUFFER_SIZE (MR_REST * sizeof(int))
|
#define L4_UTCB_FULL_BUFFER_SIZE (MR_REST * sizeof(int))
|
||||||
@@ -85,7 +86,7 @@ struct utcb {
|
|||||||
u32 mr[MR_TOTAL]; /* MRs that are mapped to real registers */
|
u32 mr[MR_TOTAL]; /* MRs that are mapped to real registers */
|
||||||
u32 saved_tag; /* Saved tag field for stacked ipcs */
|
u32 saved_tag; /* Saved tag field for stacked ipcs */
|
||||||
u32 saved_sender; /* Saved sender field for stacked ipcs */
|
u32 saved_sender; /* Saved sender field for stacked ipcs */
|
||||||
u8 notify[TASK_NOTIFY_MAX]; /* Irq notification slots */
|
u8 notify[TASK_NOTIFY_SLOTS]; /* Irq notification slots */
|
||||||
u32 mr_rest[MR_REST]; /* Complete the utcb for up to 64 words */
|
u32 mr_rest[MR_REST]; /* Complete the utcb for up to 64 words */
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <l4/generic/tcb.h>
|
#include <l4/generic/tcb.h>
|
||||||
#include INC_GLUE(message.h)
|
#include INC_GLUE(message.h)
|
||||||
#include <l4/lib/wait.h>
|
#include <l4/lib/wait.h>
|
||||||
|
#include INC_SUBARCH(irq.h)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default function that handles userspace
|
* Default function that handles userspace
|
||||||
@@ -57,12 +58,13 @@ int irq_thread_notify(struct irq_desc *desc)
|
|||||||
utcb = (struct utcb *)desc->task->utcb_address;
|
utcb = (struct utcb *)desc->task->utcb_address;
|
||||||
|
|
||||||
/* Atomic increment (See above comments) with no wraparound */
|
/* Atomic increment (See above comments) with no wraparound */
|
||||||
if (utcb->notify[desc->task_notify_slot] != TASK_NOTIFY_MAX)
|
if (utcb->notify[desc->task_notify_slot] != TASK_NOTIFY_MAXVALUE)
|
||||||
utcb->notify[desc->task_notify_slot]++;
|
utcb->notify[desc->task_notify_slot]++;
|
||||||
|
|
||||||
/* Async wake up any waiter irq threads */
|
/* Async wake up any waiter irq threads */
|
||||||
wake_up(&desc->task->wqh_notify, WAKEUP_ASYNC);
|
wake_up(&desc->wqh_irq, WAKEUP_ASYNC);
|
||||||
|
|
||||||
|
BUG_ON(!irqs_enabled());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,10 +113,13 @@ int irq_wait(l4id_t irq_index)
|
|||||||
|
|
||||||
/* Wait until the irq changes slot value */
|
/* Wait until the irq changes slot value */
|
||||||
WAIT_EVENT(&desc->wqh_irq,
|
WAIT_EVENT(&desc->wqh_irq,
|
||||||
!utcb->notify[desc->task_notify_slot],
|
utcb->notify[desc->task_notify_slot] != 0,
|
||||||
ret);
|
ret);
|
||||||
|
printk("Didn't sleep. utcb->notify[%d]=%d\n", desc->task_notify_slot, utcb->notify[desc->task_notify_slot]);
|
||||||
return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
else
|
||||||
|
return l4_atomic_dest_readb(&utcb->notify[desc->task_notify_slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
Import('env')
|
Import('env')
|
||||||
|
|
||||||
# The set of source files associated with this SConscript file.
|
# The set of source files associated with this SConscript file.
|
||||||
src_local = ['mm.c', 'mmu_ops.S', 'mutex.S']
|
src_local = ['mm.c', 'mmu_ops.S', 'mutex.S', 'irq.S']
|
||||||
|
|
||||||
obj = env.Object(src_local)
|
obj = env.Object(src_local)
|
||||||
Return('obj')
|
Return('obj')
|
||||||
|
|||||||
27
src/arch/arm/v5/irq.S
Normal file
27
src/arch/arm/v5/irq.S
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include INC_ARCH(asm.h)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r0 = unsigned long *state, stores current irq state.
|
||||||
|
*/
|
||||||
|
BEGIN_PROC(irq_local_disable_save)
|
||||||
|
mov r1, r0 @ Move address of state to r1
|
||||||
|
mrs r2, cpsr_fc @ Read cpsr
|
||||||
|
orr r3, r2, #0x80 @ Disable irq bit in cpsr
|
||||||
|
msr cpsr_fc, r3 @ Write to cpsr
|
||||||
|
str r2, [r1] @ Store original cpsr in r2 to state
|
||||||
|
mov pc, lr
|
||||||
|
END_PROC(irq_local_disable_save)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* r0 = byte address to read from.
|
||||||
|
*/
|
||||||
|
BEGIN_PROC(l4_atomic_dest_readb)
|
||||||
|
mov r1, r0 @ Move byte address to r1
|
||||||
|
mov r2, #0 @ Move 0 to r2
|
||||||
|
swpb r0, r2, [r1] @ Write 0 to byte location, while reading its value to r0
|
||||||
|
mov pc, lr @ Return byte location value
|
||||||
|
END_PROC(l4_atomic_dest_readb)
|
||||||
|
|
||||||
@@ -42,6 +42,9 @@ int irq_register(struct ktcb *task, int notify_slot, l4id_t irq_index)
|
|||||||
this_desc->task = task;
|
this_desc->task = task;
|
||||||
this_desc->task_notify_slot = notify_slot;
|
this_desc->task_notify_slot = notify_slot;
|
||||||
|
|
||||||
|
/* Setup irq desc waitqueue */
|
||||||
|
waitqueue_head_init(&this_desc->wqh_irq);
|
||||||
|
|
||||||
/* Enable the irq */
|
/* Enable the irq */
|
||||||
irq_enable(irq_index);
|
irq_enable(irq_index);
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ void sched_lock_runqueues(unsigned long *irqflags)
|
|||||||
{
|
{
|
||||||
spin_lock_irq(&scheduler.sched_rq[0].lock, irqflags);
|
spin_lock_irq(&scheduler.sched_rq[0].lock, irqflags);
|
||||||
spin_lock(&scheduler.sched_rq[1].lock);
|
spin_lock(&scheduler.sched_rq[1].lock);
|
||||||
|
BUG_ON(irqs_enabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_unlock_runqueues(unsigned long irqflags)
|
void sched_unlock_runqueues(unsigned long irqflags)
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ void wake_up(struct waitqueue_head *wqh, unsigned int flags)
|
|||||||
task_unset_wqh(sleeper);
|
task_unset_wqh(sleeper);
|
||||||
if (flags & WAKEUP_INTERRUPT)
|
if (flags & WAKEUP_INTERRUPT)
|
||||||
sleeper->flags |= TASK_INTERRUPTED;
|
sleeper->flags |= TASK_INTERRUPTED;
|
||||||
//printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid);
|
printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid);
|
||||||
spin_unlock_irq(&wqh->slock, irqflags);
|
spin_unlock_irq(&wqh->slock, irqflags);
|
||||||
|
|
||||||
if (flags & WAKEUP_SYNC)
|
if (flags & WAKEUP_SYNC)
|
||||||
|
|||||||
Reference in New Issue
Block a user