ia64/xen-unstable

view extras/mini-os/lwip-arch.c @ 19557:226ef307cd2e

AMD IOMMU: Fix ioapic interrupt remapping

A few ioapic redirection entries are initialized by hypervisor before
enabling iommu hardware. This patch copies those entries from ioapic
redirection table into interrupt remapping table after interrupt
remapping table has been allocated.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Apr 17 13:16:39 2009 +0100 (2009-04-17)
parents 3c49ae5641b0
children
line source
1 /*
2 * lwip-arch.c
3 *
4 * Arch-specific semaphores and mailboxes for lwIP running on mini-os
5 *
6 * Tim Deegan <Tim.Deegan@eu.citrix.net>, July 2007
7 */
9 #include <os.h>
10 #include <time.h>
11 #include <console.h>
12 #include <xmalloc.h>
13 #include <lwip/sys.h>
14 #include <stdarg.h>
16 /* Is called to initialize the sys_arch layer */
17 void sys_init(void)
18 {
19 }
21 /* Creates and returns a new semaphore. The "count" argument specifies
22 * the initial state of the semaphore. */
23 sys_sem_t sys_sem_new(u8_t count)
24 {
25 struct semaphore *sem = xmalloc(struct semaphore);
26 sem->count = count;
27 init_waitqueue_head(&sem->wait);
28 return sem;
29 }
31 /* Deallocates a semaphore. */
32 void sys_sem_free(sys_sem_t sem)
33 {
34 xfree(sem);
35 }
37 /* Signals a semaphore. */
38 void sys_sem_signal(sys_sem_t sem)
39 {
40 up(sem);
41 }
43 /* Blocks the thread while waiting for the semaphore to be
44 * signaled. If the "timeout" argument is non-zero, the thread should
45 * only be blocked for the specified time (measured in
46 * milliseconds).
47 *
48 * If the timeout argument is non-zero, the return value is the number of
49 * milliseconds spent waiting for the semaphore to be signaled. If the
50 * semaphore wasn't signaled within the specified time, the return value is
51 * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
52 * (i.e., it was already signaled), the function may return zero. */
53 u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
54 {
55 /* Slightly more complicated than the normal minios semaphore:
56 * need to wake on timeout *or* signal */
57 sys_prot_t prot;
58 s64_t then = NOW();
59 s64_t deadline;
61 if (timeout == 0)
62 deadline = 0;
63 else
64 deadline = then + MILLISECS(timeout);
66 while(1) {
67 wait_event_deadline(sem->wait, (sem->count > 0), deadline);
69 prot = sys_arch_protect();
70 /* Atomically check that we can proceed */
71 if (sem->count > 0 || (deadline && NOW() >= deadline))
72 break;
73 sys_arch_unprotect(prot);
74 }
76 if (sem->count > 0) {
77 sem->count--;
78 sys_arch_unprotect(prot);
79 return NSEC_TO_MSEC(NOW() - then);
80 }
82 sys_arch_unprotect(prot);
83 return SYS_ARCH_TIMEOUT;
84 }
86 /* Creates an empty mailbox. */
87 sys_mbox_t sys_mbox_new(int size)
88 {
89 struct mbox *mbox = xmalloc(struct mbox);
90 if (!size)
91 size = 32;
92 else if (size == 1)
93 size = 2;
94 mbox->count = size;
95 mbox->messages = xmalloc_array(void*, size);
96 init_SEMAPHORE(&mbox->read_sem, 0);
97 mbox->reader = 0;
98 init_SEMAPHORE(&mbox->write_sem, size);
99 mbox->writer = 0;
100 return mbox;
101 }
103 /* Deallocates a mailbox. If there are messages still present in the
104 * mailbox when the mailbox is deallocated, it is an indication of a
105 * programming error in lwIP and the developer should be notified. */
106 void sys_mbox_free(sys_mbox_t mbox)
107 {
108 ASSERT(mbox->reader == mbox->writer);
109 xfree(mbox->messages);
110 xfree(mbox);
111 }
113 /* Posts the "msg" to the mailbox, internal version that actually does the
114 * post. */
115 static void do_mbox_post(sys_mbox_t mbox, void *msg)
116 {
117 /* The caller got a semaphore token, so we are now allowed to increment
118 * writer, but we still need to prevent concurrency between writers
119 * (interrupt handler vs main) */
120 sys_prot_t prot = sys_arch_protect();
121 mbox->messages[mbox->writer] = msg;
122 mbox->writer = (mbox->writer + 1) % mbox->count;
123 ASSERT(mbox->reader != mbox->writer);
124 sys_arch_unprotect(prot);
125 up(&mbox->read_sem);
126 }
128 /* Posts the "msg" to the mailbox. */
129 void sys_mbox_post(sys_mbox_t mbox, void *msg)
130 {
131 if (mbox == SYS_MBOX_NULL)
132 return;
133 down(&mbox->write_sem);
134 do_mbox_post(mbox, msg);
135 }
137 /* Try to post the "msg" to the mailbox. */
138 err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
139 {
140 if (mbox == SYS_MBOX_NULL)
141 return ERR_BUF;
142 if (!trydown(&mbox->write_sem))
143 return ERR_MEM;
144 do_mbox_post(mbox, msg);
145 return ERR_OK;
146 }
148 /*
149 * Fetch a message from a mailbox. Internal version that actually does the
150 * fetch.
151 */
152 static void do_mbox_fetch(sys_mbox_t mbox, void **msg)
153 {
154 sys_prot_t prot;
155 /* The caller got a semaphore token, so we are now allowed to increment
156 * reader, but we may still need to prevent concurrency between readers.
157 * FIXME: can there be concurrent readers? */
158 prot = sys_arch_protect();
159 ASSERT(mbox->reader != mbox->writer);
160 if (msg != NULL)
161 *msg = mbox->messages[mbox->reader];
162 mbox->reader = (mbox->reader + 1) % mbox->count;
163 sys_arch_unprotect(prot);
164 up(&mbox->write_sem);
165 }
167 /* Blocks the thread until a message arrives in the mailbox, but does
168 * not block the thread longer than "timeout" milliseconds (similar to
169 * the sys_arch_sem_wait() function). The "msg" argument is a result
170 * parameter that is set by the function (i.e., by doing "*msg =
171 * ptr"). The "msg" parameter maybe NULL to indicate that the message
172 * should be dropped.
173 *
174 * The return values are the same as for the sys_arch_sem_wait() function:
175 * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
176 * timeout. */
177 u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
178 {
179 u32 rv;
180 if (mbox == SYS_MBOX_NULL)
181 return SYS_ARCH_TIMEOUT;
183 rv = sys_arch_sem_wait(&mbox->read_sem, timeout);
184 if ( rv == SYS_ARCH_TIMEOUT )
185 return rv;
187 do_mbox_fetch(mbox, msg);
188 return 0;
189 }
191 /* This is similar to sys_arch_mbox_fetch, however if a message is not
192 * present in the mailbox, it immediately returns with the code
193 * SYS_MBOX_EMPTY. On success 0 is returned.
194 *
195 * To allow for efficient implementations, this can be defined as a
196 * function-like macro in sys_arch.h instead of a normal function. For
197 * example, a naive implementation could be:
198 * #define sys_arch_mbox_tryfetch(mbox,msg) \
199 * sys_arch_mbox_fetch(mbox,msg,1)
200 * although this would introduce unnecessary delays. */
202 u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) {
203 if (mbox == SYS_MBOX_NULL)
204 return SYS_ARCH_TIMEOUT;
206 if (!trydown(&mbox->read_sem))
207 return SYS_MBOX_EMPTY;
209 do_mbox_fetch(mbox, msg);
210 return 0;
211 }
214 /* Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
215 * each thread has a list of timeouts which is repressented as a linked
216 * list of sys_timeout structures. The sys_timeouts structure holds a
217 * pointer to a linked list of timeouts. This function is called by
218 * the lwIP timeout scheduler and must not return a NULL value.
219 *
220 * In a single threadd sys_arch implementation, this function will
221 * simply return a pointer to a global sys_timeouts variable stored in
222 * the sys_arch module. */
223 struct sys_timeouts *sys_arch_timeouts(void)
224 {
225 static struct sys_timeouts timeout;
226 return &timeout;
227 }
230 /* Starts a new thread with priority "prio" that will begin its execution in the
231 * function "thread()". The "arg" argument will be passed as an argument to the
232 * thread() function. The id of the new thread is returned. Both the id and
233 * the priority are system dependent. */
234 static struct thread *lwip_thread;
235 sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
236 {
237 struct thread *t;
238 if (stacksize > STACK_SIZE) {
239 printk("Can't start lwIP thread: stack size %d is too large for our %d\n", stacksize, STACK_SIZE);
240 do_exit();
241 }
242 lwip_thread = t = create_thread(name, thread, arg);
243 return t;
244 }
246 /* This optional function does a "fast" critical region protection and returns
247 * the previous protection level. This function is only called during very short
248 * critical regions. An embedded system which supports ISR-based drivers might
249 * want to implement this function by disabling interrupts. Task-based systems
250 * might want to implement this by using a mutex or disabling tasking. This
251 * function should support recursive calls from the same task or interrupt. In
252 * other words, sys_arch_protect() could be called while already protected. In
253 * that case the return value indicates that it is already protected.
254 *
255 * sys_arch_protect() is only required if your port is supporting an operating
256 * system. */
257 sys_prot_t sys_arch_protect(void)
258 {
259 unsigned long flags;
260 local_irq_save(flags);
261 return flags;
262 }
264 /* This optional function does a "fast" set of critical region protection to the
265 * value specified by pval. See the documentation for sys_arch_protect() for
266 * more information. This function is only required if your port is supporting
267 * an operating system. */
268 void sys_arch_unprotect(sys_prot_t pval)
269 {
270 local_irq_restore(pval);
271 }
273 /* non-fatal, print a message. */
274 void lwip_printk(char *fmt, ...)
275 {
276 va_list args;
277 va_start(args, fmt);
278 printk("lwIP: ");
279 print(0, fmt, args);
280 va_end(args);
281 }
283 /* fatal, print message and abandon execution. */
284 void lwip_die(char *fmt, ...)
285 {
286 va_list args;
287 va_start(args, fmt);
288 printk("lwIP assertion failed: ");
289 print(0, fmt, args);
290 va_end(args);
291 printk("\n");
292 BUG();
293 }