OsdSchedule.c revision 145352
167760Smsmith/*-
267760Smsmith * Copyright (c) 2000 Michael Smith
367760Smsmith * Copyright (c) 2000 BSDi
467760Smsmith * All rights reserved.
567760Smsmith *
667760Smsmith * Redistribution and use in source and binary forms, with or without
767760Smsmith * modification, are permitted provided that the following conditions
867760Smsmith * are met:
967760Smsmith * 1. Redistributions of source code must retain the above copyright
1067760Smsmith *    notice, this list of conditions and the following disclaimer.
1167760Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1267760Smsmith *    notice, this list of conditions and the following disclaimer in the
1367760Smsmith *    documentation and/or other materials provided with the distribution.
1467760Smsmith *
1567760Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1667760Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1767760Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1867760Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1967760Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2067760Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2167760Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2267760Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2367760Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2467760Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2567760Smsmith * SUCH DAMAGE.
2667760Smsmith *
2767760Smsmith *	$FreeBSD: head/sys/dev/acpica/Osd/OsdSchedule.c 145352 2005-04-21 06:13:48Z njl $
2867760Smsmith */
2967760Smsmith
3067760Smsmith/*
3167760Smsmith * 6.3 : Scheduling services
3267760Smsmith */
3367760Smsmith
3488420Siwasaki#include "opt_acpi.h"
3588420Siwasaki#include <sys/param.h>
3688420Siwasaki#include <sys/systm.h>
3788420Siwasaki#include <sys/bus.h>
3888420Siwasaki#include <sys/interrupt.h>
3967760Smsmith#include <sys/kernel.h>
4088420Siwasaki#include <sys/kthread.h>
4167760Smsmith#include <sys/malloc.h>
4277466Smsmith#include <sys/proc.h>
4367760Smsmith#include <sys/taskqueue.h>
4467760Smsmith#include <machine/clock.h>
4567760Smsmith
46128228Snjl#include "acpi.h"
4788420Siwasaki#include <dev/acpica/acpivar.h>
4888420Siwasaki
4977432Smsmith#define _COMPONENT	ACPI_OS_SERVICES
5091128SmsmithACPI_MODULE_NAME("SCHEDULE")
5171875Smsmith
5267760Smsmith/*
53145352Snjl * Allow the user to tune the number of task threads we start.  It seems
54145352Snjl * some systems have problems with increased parallelism.
55145352Snjl */
56145352Snjlstatic int acpi_max_threads = ACPI_MAX_THREADS;
57145352SnjlTUNABLE_INT("debug.acpi.max_threads", &acpi_max_threads);
58145352Snjl
59145352Snjl/*
6067760Smsmith * This is a little complicated due to the fact that we need to build and then
6167760Smsmith * free a 'struct task' for each task we enqueue.
6267760Smsmith */
6367760Smsmith
6467760SmsmithMALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
6567760Smsmith
6667760Smsmithstatic void	AcpiOsExecuteQueue(void *arg, int pending);
6767760Smsmith
6867760Smsmithstruct acpi_task {
6967760Smsmith    struct task			at_task;
70138300Smarks    ACPI_OSD_EXEC_CALLBACK	at_function;
7167760Smsmith    void			*at_context;
7267760Smsmith};
7367760Smsmith
7488420Siwasakistruct acpi_task_queue {
7588420Siwasaki    STAILQ_ENTRY(acpi_task_queue) at_q;
7688420Siwasaki    struct acpi_task		*at;
7788420Siwasaki};
7888420Siwasaki
7988420Siwasaki/*
8088420Siwasaki * Private task queue definition for ACPI
8188420Siwasaki */
8288420SiwasakiTASKQUEUE_DECLARE(acpi);
8388420Siwasakistatic void	*taskqueue_acpi_ih;
8488420Siwasaki
8588420Siwasakistatic void
8688420Siwasakitaskqueue_acpi_enqueue(void *context)
8788420Siwasaki{
8888900Sjhb    swi_sched(taskqueue_acpi_ih, 0);
8988420Siwasaki}
9088420Siwasaki
9188420Siwasakistatic void
9288420Siwasakitaskqueue_acpi_run(void *dummy)
9388420Siwasaki{
9488420Siwasaki    taskqueue_run(taskqueue_acpi);
9588420Siwasaki}
9688420Siwasaki
9788420SiwasakiTASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0,
9888420Siwasaki		 swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL,
9988420Siwasaki		     SWI_TQ, 0, &taskqueue_acpi_ih));
10088420Siwasaki
101128990Snjlstatic STAILQ_HEAD(, acpi_task_queue) acpi_task_queue;
102133627SnjlACPI_LOCK_DECL(taskq, "ACPI task queue");
10388420Siwasaki
10488420Siwasakistatic void
10588420Siwasakiacpi_task_thread(void *arg)
10688420Siwasaki{
10788420Siwasaki    struct acpi_task_queue	*atq;
108138300Smarks    ACPI_OSD_EXEC_CALLBACK	Function;
10988420Siwasaki    void			*Context;
11088420Siwasaki
111133627Snjl    ACPI_LOCK(taskq);
11288420Siwasaki    for (;;) {
113133627Snjl	while ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL)
114133627Snjl	    msleep(&acpi_task_queue, &taskq_mutex, PCATCH, "actask", 0);
11588420Siwasaki	STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q);
116133627Snjl	ACPI_UNLOCK(taskq);
11788420Siwasaki
118138300Smarks	Function = (ACPI_OSD_EXEC_CALLBACK)atq->at->at_function;
11988420Siwasaki	Context = atq->at->at_context;
12088420Siwasaki
12188420Siwasaki	Function(Context);
12288420Siwasaki
12388420Siwasaki	free(atq->at, M_ACPITASK);
12488420Siwasaki	free(atq, M_ACPITASK);
125133627Snjl	ACPI_LOCK(taskq);
12688420Siwasaki    }
12788420Siwasaki
12888420Siwasaki    kthread_exit(0);
12988420Siwasaki}
13088420Siwasaki
13188420Siwasakiint
13288420Siwasakiacpi_task_thread_init(void)
13388420Siwasaki{
13488420Siwasaki    int		i, err;
13588420Siwasaki    struct proc	*acpi_kthread_proc;
13688420Siwasaki
13788420Siwasaki    err = 0;
13888420Siwasaki    STAILQ_INIT(&acpi_task_queue);
13988420Siwasaki
140145352Snjl    for (i = 0; i < acpi_max_threads; i++) {
14188420Siwasaki	err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc,
142104354Sscottl			     0, 0, "acpi_task%d", i);
14388420Siwasaki	if (err != 0) {
14488420Siwasaki	    printf("%s: kthread_create failed(%d)\n", __func__, err);
14588420Siwasaki	    break;
14688420Siwasaki	}
14788420Siwasaki    }
14888420Siwasaki    return (err);
14988420Siwasaki}
15088420Siwasaki
151128228Snjl/* This function is called in interrupt context. */
15267760SmsmithACPI_STATUS
153138300SmarksAcpiOsQueueForExecution(UINT32 Priority, ACPI_OSD_EXEC_CALLBACK Function,
154128228Snjl    void *Context)
15567760Smsmith{
15667760Smsmith    struct acpi_task	*at;
15785503Sjhb    int pri;
15867760Smsmith
15996926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
16071875Smsmith
16167760Smsmith    if (Function == NULL)
162128228Snjl	return_ACPI_STATUS (AE_BAD_PARAMETER);
16367760Smsmith
164128228Snjl    at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT | M_ZERO);
16571418Speter    if (at == NULL)
166128228Snjl	return_ACPI_STATUS (AE_NO_MEMORY);
16767760Smsmith
16867760Smsmith    at->at_function = Function;
16967760Smsmith    at->at_context = Context;
17067760Smsmith    switch (Priority) {
17170236Siwasaki    case OSD_PRIORITY_GPE:
17285503Sjhb	pri = 4;
17370236Siwasaki	break;
17467760Smsmith    case OSD_PRIORITY_HIGH:
17585503Sjhb	pri = 3;
17667760Smsmith	break;
17767760Smsmith    case OSD_PRIORITY_MED:
17885503Sjhb	pri = 2;
17967760Smsmith	break;
18067760Smsmith    case OSD_PRIORITY_LO:
18185503Sjhb	pri = 1;
18267760Smsmith	break;
18367760Smsmith    default:
18467760Smsmith	free(at, M_ACPITASK);
185128228Snjl	return_ACPI_STATUS (AE_BAD_PARAMETER);
18667760Smsmith    }
18785503Sjhb    TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at);
18867760Smsmith
189128228Snjl    taskqueue_enqueue(taskqueue_acpi, (struct task *)at);
190128228Snjl
191128228Snjl    return_ACPI_STATUS (AE_OK);
19267760Smsmith}
19367760Smsmith
19467760Smsmithstatic void
19567760SmsmithAcpiOsExecuteQueue(void *arg, int pending)
19667760Smsmith{
19788420Siwasaki    struct acpi_task_queue	*atq;
198138300Smarks    ACPI_OSD_EXEC_CALLBACK	Function;
19967760Smsmith    void			*Context;
20067760Smsmith
20196926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
20271875Smsmith
20388420Siwasaki    atq = NULL;
20488420Siwasaki    Function = NULL;
20588420Siwasaki    Context = NULL;
20688420Siwasaki
20788420Siwasaki    atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT);
20888420Siwasaki    if (atq == NULL) {
20988420Siwasaki	printf("%s: no memory\n", __func__);
21088420Siwasaki	return;
21188420Siwasaki    }
212133627Snjl    atq->at = (struct acpi_task *)arg;
21388420Siwasaki
214133627Snjl    ACPI_LOCK(taskq);
21588420Siwasaki    STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q);
21688420Siwasaki    wakeup_one(&acpi_task_queue);
217133627Snjl    ACPI_UNLOCK(taskq);
21867760Smsmith
21971875Smsmith    return_VOID;
22067760Smsmith}
22167760Smsmith
22267760Smsmithvoid
223138300SmarksAcpiOsSleep(ACPI_INTEGER Milliseconds)
22467760Smsmith{
22567760Smsmith    int		timo;
22677432Smsmith    static int	dummy;
22767760Smsmith
22896926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
22971875Smsmith
230138300Smarks    timo = Milliseconds * hz / 1000;
231120662Snjl
232120662Snjl    /*
233120662Snjl     * If requested sleep time is less than our hz resolution, use
234120662Snjl     * DELAY instead for better granularity.
235120662Snjl     */
236120662Snjl    if (timo > 0)
237120662Snjl	tsleep(&dummy, 0, "acpislp", timo);
238120662Snjl    else
239120662Snjl	DELAY(Milliseconds * 1000);
240120662Snjl
24171875Smsmith    return_VOID;
24267760Smsmith}
24367760Smsmith
244138300Smarks/*
245138300Smarks * Return the current time in 100 nanosecond units
246138300Smarks */
247138300SmarksUINT64
248138300SmarksAcpiOsGetTimer(void)
249138300Smarks{
250138300Smarks    struct bintime bt;
251138300Smarks    UINT64 t;
252138300Smarks
253138300Smarks    /* XXX During early boot there is no (decent) timer available yet. */
254138300Smarks    if (cold)
255138300Smarks	panic("acpi: timer op not yet supported during boot");
256138300Smarks
257138300Smarks    binuptime(&bt);
258138300Smarks    t = ((UINT64)10000000 * (uint32_t)(bt.frac >> 32)) >> 32;
259138300Smarks    t += bt.sec * 10000000;
260138300Smarks
261138300Smarks    return (t);
262138300Smarks}
263138300Smarks
26467760Smsmithvoid
265120662SnjlAcpiOsStall(UINT32 Microseconds)
26667760Smsmith{
26796926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
26871875Smsmith
269120607Snjl    DELAY(Microseconds);
27071875Smsmith    return_VOID;
27167760Smsmith}
27277432Smsmith
27377432SmsmithUINT32
274120662SnjlAcpiOsGetThreadId(void)
27577432Smsmith{
276105279Sjhb    struct proc *p;
27777432Smsmith
278128228Snjl    /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */
279128228Snjl
280105279Sjhb    p = curproc;
281105279Sjhb    KASSERT(p != NULL, ("%s: curproc is NULL!", __func__));
282128228Snjl
283128228Snjl    /* Returning 0 is not allowed. */
284128228Snjl    return (p->p_pid + 1);
28577432Smsmith}
286