OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [src/] [api/] [irq.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Userspace irq handling and management
3
 *
4
 * Copyright (C) 2009 Bahadir Balban
5
 */
6
#include <l4/api/irq.h>
7
#include <l4/api/errno.h>
8
#include <l4/generic/scheduler.h>
9
#include <l4/generic/thread.h>
10
#include <l4/generic/capability.h>
11
#include <l4/generic/irq.h>
12
#include <l4/generic/tcb.h>
13
#include INC_GLUE(message.h)
14
#include <l4/lib/wait.h>
15
#include INC_SUBARCH(irq.h)
16
 
17
/*
18
 * Default function that handles userspace
19
 * threaded irqs. Increases irq count and wakes
20
 * up any waiters.
21
 *
22
 * The increment is a standard read/update/write, and
23
 * it is atomic due to multiple reasons:
24
 *
25
 * - We are atomic with regard to the task because we are
26
 *   in irq context. Task cannot run during the period where
27
 *   we read update and write the value.
28
 *
29
 * - The task does an atomic swap on reads, writing 0 to the
30
 *   location in the same instruction as it reads it. As a
31
 *   result task updates on the slot are atomic, and cannot
32
 *   interfere with the read/update/write of the irq.
33
 *
34
 * - Recursive irqs are enabled, but we are also protected
35
 *   from them because the current irq number is masked.
36
 *
37
 *   FIXME: Instead of UTCB, do it by incrementing a semaphore.
38
 */
39
int irq_thread_notify(struct irq_desc *desc)
40
{
41
        struct utcb *utcb;
42
        int err;
43
 
44
        /* Make sure irq thread's utcb is mapped */
45
        if ((err = tcb_check_and_lazy_map_utcb(desc->task,
46
                                               0)) < 0) {
47
                printk("%s: Irq occured but registered task's utcb "
48
                       "is inaccessible without a page fault. "
49
                       "task id=0x%x err=%d\n"
50
                       "Destroying task.", __FUNCTION__,
51
                       desc->task->tid, err);
52
                /* FIXME: Racy for irqs. */
53
                thread_destroy(desc->task);
54
                /* FIXME: Deregister and disable irq as well */
55
        }
56
 
57
        /* Get thread's utcb */
58
        utcb = (struct utcb *)desc->task->utcb_address;
59
 
60
        /* Atomic increment (See above comments) with no wraparound */
61
        if (utcb->notify[desc->task_notify_slot] != TASK_NOTIFY_MAXVALUE)
62
                utcb->notify[desc->task_notify_slot]++;
63
 
64
        /* Async wake up any waiter irq threads */
65
        wake_up(&desc->wqh_irq, WAKEUP_ASYNC);
66
 
67
        BUG_ON(!irqs_enabled());
68
        return 0;
69
}
70
 
71
/*
72
 * Register the given globally unique irq number with the
73
 * current thread with given flags
74
 */
75
int irq_control_register(struct ktcb *task, int slot, l4id_t irqnum)
76
{
77
        int err;
78
 
79
        /*
80
         * Check that utcb memory accesses won't fault us.
81
         *
82
         * We make sure that the irq registrar has its utcb mapped,
83
         * so that if an irq occurs, the utcb address must be at
84
         * least readily available to be copied over to the page
85
         * tables of the task runnable at the time of the irq.
86
         */
87
        if ((err = tcb_check_and_lazy_map_utcb(current, 1)) < 0)
88
                return err;
89
 
90
        /* Register the irq for thread notification */
91
        if ((err = irq_register(current, slot, irqnum)) < 0)
92
                return err;
93
 
94
        /* Make thread a real-time task */
95
        current->flags |= TASK_REALTIME;
96
 
97
        return 0;
98
}
99
 
100
/*
101
 * Makes current task wait on the given irq
102
 */
103
int irq_wait(l4id_t irq_index)
104
{
105
        struct irq_desc *desc = irq_desc_array + irq_index;
106
        struct utcb *utcb = (struct utcb *)current->utcb_address;
107
        int ret;
108
 
109
        /* Index must be valid */
110
        if (irq_index > IRQS_MAX || irq_index < 0)
111
                return -EINVAL;
112
 
113
        /* UTCB must be mapped */
114
        if ((ret = tcb_check_and_lazy_map_utcb(current, 1)) < 0)
115
                return ret;
116
 
117
        /* Wait until the irq changes slot value */
118
        WAIT_EVENT(&desc->wqh_irq,
119
                   utcb->notify[desc->task_notify_slot] != 0,
120
                   ret);
121
 
122
        if (ret < 0)
123
                return ret;
124
        else
125
                return l4_atomic_dest_readb(&utcb->notify[desc->task_notify_slot]);
126
}
127
 
128
 
129
/*
130
 * Register/deregister device irqs. Optional synchronous and
131
 * asynchronous irq handling.
132
 */
133
int sys_irq_control(unsigned int req, unsigned int flags, l4id_t irqnum)
134
{
135
        /* Currently a task is allowed to register only for itself */
136
        struct ktcb *task = current;
137
        int err;
138
 
139
        if ((err = cap_irq_check(task, req, flags, irqnum)) < 0)
140
                return err;
141
 
142
        switch (req) {
143
        case IRQ_CONTROL_REGISTER:
144
                return irq_control_register(task, flags, irqnum);
145
        case IRQ_CONTROL_WAIT:
146
                return irq_wait(irqnum);
147
        default:
148
                return -EINVAL;
149
        }
150
 
151
        return 0;
152
}
153
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.