File: [local] / sys / kern / kern_workq.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:15:05 2008 UTC (16 years, 4 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: kern_workq.c,v 1.3 2007/06/11 22:15:11 thib Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
* Copyright (c) 2007 Ted Unangst <tedu@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/pool.h>
#include <sys/queue.h>
#include <sys/kthread.h>
#include <sys/workq.h>
struct workq_task {
int wqt_flags;
workq_fn wqt_func;
void *wqt_arg1;
void *wqt_arg2;
SIMPLEQ_ENTRY(workq_task) wqt_entry;
};
struct workq {
int wq_flags;
#define WQ_F_RUNNING (1<<0)
int wq_running;
int wq_busy;
int wq_max;
const char *wq_name;
SIMPLEQ_HEAD(, workq_task) wq_tasklist;
};
struct pool workq_task_pool;
struct workq workq_syswq = {
WQ_F_RUNNING,
0,
0,
1,
"syswq"
};
void workq_init(void); /* called in init_main.c */
void workq_init_syswq(void *);
void workq_create_thread(void *);
void workq_thread(void *);
void
workq_init(void)
{
pool_init(&workq_task_pool, sizeof(struct workq_task), 0, 0,
0, "wqtasks", NULL);
SIMPLEQ_INIT(&workq_syswq.wq_tasklist);
kthread_create_deferred(workq_init_syswq, NULL);
}
void
workq_init_syswq(void *arg)
{
if (kthread_create(workq_thread, &workq_syswq, NULL, "%s",
workq_syswq.wq_name) != 0)
panic("unable to create system work queue thread");
workq_syswq.wq_running++;
}
struct workq *
workq_create(const char *name, int maxqs)
{
struct workq *wq;
wq = malloc(sizeof(*wq), M_DEVBUF, M_NOWAIT);
if (wq == NULL)
return (NULL);
wq->wq_flags = WQ_F_RUNNING;
wq->wq_running = 0;
wq->wq_busy = 0;
wq->wq_max = maxqs;
wq->wq_name = name;
SIMPLEQ_INIT(&wq->wq_tasklist);
/* try to create a thread to guarantee that tasks will be serviced */
kthread_create_deferred(workq_create_thread, wq);
return (wq);
}
void
workq_destroy(struct workq *wq)
{
int s;
s = splhigh();
wq->wq_flags &= ~WQ_F_RUNNING;
while (wq->wq_running != 0) {
wakeup(wq);
tsleep(&wq->wq_running, PWAIT, "wqdestroy", 0);
}
splx(s);
free(wq, M_DEVBUF);
}
int
workq_add_task(struct workq *wq, int flags, workq_fn func,
void *a1, void *a2)
{
struct workq_task *wqt;
int wake = 1;
int s;
if (wq == NULL)
wq = &workq_syswq;
s = splhigh();
wqt = pool_get(&workq_task_pool, (flags & WQ_WAITOK) ?
PR_WAITOK : PR_NOWAIT);
splx(s);
if (!wqt)
return (ENOMEM);
wqt->wqt_flags = flags;
wqt->wqt_func = func;
wqt->wqt_arg1 = a1;
wqt->wqt_arg2 = a2;
s = splhigh();
SIMPLEQ_INSERT_TAIL(&wq->wq_tasklist, wqt, wqt_entry);
if ((wq->wq_running < wq->wq_max) && (wq->wq_running == wq->wq_busy)) {
kthread_create_deferred(workq_create_thread, wq);
wake = 0;
}
splx(s);
if (wake)
wakeup_one(wq);
return (0);
}
void
workq_create_thread(void *arg)
{
struct workq *wq = arg;
int rv;
rv = kthread_create(workq_thread, wq, NULL, "%s", wq->wq_name);
if (rv != 0) {
printf("unable to create \"%s\" workq thread\n", wq->wq_name);
return;
}
wq->wq_running++;
}
void
workq_thread(void *arg)
{
struct workq *wq = arg;
struct workq_task *wqt;
int s;
s = splhigh();
while (wq->wq_flags & WQ_F_RUNNING) {
while ((wqt = SIMPLEQ_FIRST(&wq->wq_tasklist)) != NULL) {
SIMPLEQ_REMOVE_HEAD(&wq->wq_tasklist, wqt_entry);
wq->wq_busy++;
splx(s);
if (wqt->wqt_flags & WQ_MPSAFE)
;
wqt->wqt_func(wqt->wqt_arg1, wqt->wqt_arg2);
if (wqt->wqt_flags & WQ_MPSAFE)
;
s = splhigh();
wq->wq_busy--;
pool_put(&workq_task_pool, wqt);
}
tsleep(wq, PWAIT, "bored", 0);
}
wq->wq_running--;
splx(s);
wakeup(&wq->wq_running);
kthread_exit(0);
}