OsdSchedule.c revision 148318
1/*-
2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/*
29 * 6.3 : Scheduling services
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/dev/acpica/Osd/OsdSchedule.c 148318 2005-07-22 23:10:02Z njl $");
34
35#include "opt_acpi.h"
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/bus.h>
39#include <sys/interrupt.h>
40#include <sys/kernel.h>
41#include <sys/kthread.h>
42#include <sys/malloc.h>
43#include <sys/proc.h>
44#include <sys/taskqueue.h>
45#include <machine/clock.h>
46
47#include "acpi.h"
48#include <dev/acpica/acpivar.h>
49
50#define _COMPONENT	ACPI_OS_SERVICES
51ACPI_MODULE_NAME("SCHEDULE")
52
53/*
54 * Allow the user to tune the number of task threads we start.  It seems
55 * some systems have problems with increased parallelism.
56 */
57static int acpi_max_threads = ACPI_MAX_THREADS;
58TUNABLE_INT("debug.acpi.max_threads", &acpi_max_threads);
59
60MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
61
62struct acpi_task_ctx {
63    struct task			at_task;
64    ACPI_OSD_EXEC_CALLBACK	at_function;
65    void 			*at_context;
66};
67
68/*
69 * Private task queue definition for ACPI
70 */
71static struct proc *
72acpi_task_start_threads(struct taskqueue **tqp)
73{
74    struct proc	*acpi_kthread_proc;
75    int	err, i;
76
77    KASSERT(*tqp != NULL, ("acpi taskqueue not created before threads"));
78
79    /* Start one or more threads to service our taskqueue. */
80    for (i = 0; i < acpi_max_threads; i++) {
81	err = kthread_create(taskqueue_thread_loop, tqp, &acpi_kthread_proc,
82	    0, 0, "acpi_task%d", i);
83	if (err) {
84	    printf("%s: kthread_create failed (%d)\n", __func__, err);
85	    break;
86	}
87    }
88    return (acpi_kthread_proc);
89}
90
91TASKQUEUE_DEFINE(acpi, taskqueue_thread_enqueue, &taskqueue_acpi,
92    taskqueue_acpi_proc = acpi_task_start_threads(&taskqueue_acpi));
93
94/*
95 * Bounce through this wrapper function since ACPI-CA doesn't understand
96 * the pending argument for its callbacks.
97 */
98static void
99acpi_task_execute(void *context, int pending)
100{
101    struct acpi_task_ctx *at;
102
103    at = (struct acpi_task_ctx *)context;
104    at->at_function(at->at_context);
105    free(at, M_ACPITASK);
106}
107
108/*
109 * This function may be called in interrupt context, i.e. when a GPE fires.
110 * We allocate and queue a task for one of our taskqueue threads to process.
111 */
112ACPI_STATUS
113AcpiOsQueueForExecution(UINT32 Priority, ACPI_OSD_EXEC_CALLBACK Function,
114    void *Context)
115{
116    struct acpi_task_ctx *at;
117    int pri;
118
119    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
120
121    if (Function == NULL)
122	return_ACPI_STATUS (AE_BAD_PARAMETER);
123
124    at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT);
125    if (at == NULL)
126	return_ACPI_STATUS (AE_NO_MEMORY);
127
128    at->at_function = Function;
129    at->at_context = Context;
130    switch (Priority) {
131    case OSD_PRIORITY_GPE:
132	pri = 4;
133	break;
134    case OSD_PRIORITY_HIGH:
135	pri = 3;
136	break;
137    case OSD_PRIORITY_MED:
138	pri = 2;
139	break;
140    case OSD_PRIORITY_LO:
141	pri = 1;
142	break;
143    default:
144	free(at, M_ACPITASK);
145	return_ACPI_STATUS (AE_BAD_PARAMETER);
146    }
147
148    TASK_INIT(&at->at_task, pri, acpi_task_execute, at);
149    taskqueue_enqueue(taskqueue_acpi, &at->at_task);
150
151    return_ACPI_STATUS (AE_OK);
152}
153
154void
155AcpiOsSleep(ACPI_INTEGER Milliseconds)
156{
157    int		timo;
158    static int	dummy;
159
160    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
161
162    timo = Milliseconds * hz / 1000;
163
164    /*
165     * If requested sleep time is less than our hz resolution, use
166     * DELAY instead for better granularity.
167     */
168    if (timo > 0)
169	tsleep(&dummy, 0, "acpislp", timo);
170    else
171	DELAY(Milliseconds * 1000);
172
173    return_VOID;
174}
175
176/*
177 * Return the current time in 100 nanosecond units
178 */
179UINT64
180AcpiOsGetTimer(void)
181{
182    struct bintime bt;
183    UINT64 t;
184
185    /* XXX During early boot there is no (decent) timer available yet. */
186    if (cold)
187	panic("acpi: timer op not yet supported during boot");
188
189    binuptime(&bt);
190    t = ((UINT64)10000000 * (uint32_t)(bt.frac >> 32)) >> 32;
191    t += bt.sec * 10000000;
192
193    return (t);
194}
195
196void
197AcpiOsStall(UINT32 Microseconds)
198{
199    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
200
201    DELAY(Microseconds);
202    return_VOID;
203}
204
205UINT32
206AcpiOsGetThreadId(void)
207{
208    struct proc *p;
209
210    /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */
211
212    p = curproc;
213    KASSERT(p != NULL, ("%s: curproc is NULL!", __func__));
214
215    /* Returning 0 is not allowed. */
216    return (p->p_pid + 1);
217}
218