OsdSchedule.c revision 133627
152284Sobrien/*-
290075Sobrien * Copyright (c) 2000 Michael Smith
3117395Skan * Copyright (c) 2000 BSDi
490075Sobrien * All rights reserved.
552284Sobrien *
6132718Skan * Redistribution and use in source and binary forms, with or without
752284Sobrien * modification, are permitted provided that the following conditions
8132718Skan * are met:
952284Sobrien * 1. Redistributions of source code must retain the above copyright
1052284Sobrien *    notice, this list of conditions and the following disclaimer.
1152284Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1252284Sobrien *    notice, this list of conditions and the following disclaimer in the
13132718Skan *    documentation and/or other materials provided with the distribution.
1452284Sobrien *
1552284Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1652284Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1752284Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1852284Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2252284Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2452284Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25132718Skan * SUCH DAMAGE.
2690075Sobrien *
2790075Sobrien *	$FreeBSD: head/sys/dev/acpica/Osd/OsdSchedule.c 133627 2004-08-13 06:22:26Z njl $
28132718Skan */
2990075Sobrien
30132718Skan/*
31132718Skan * 6.3 : Scheduling services
3290075Sobrien */
33132718Skan
3490075Sobrien#include "opt_acpi.h"
3552284Sobrien#include <sys/param.h>
3690075Sobrien#include <sys/systm.h>
3790075Sobrien#include <sys/bus.h>
38132718Skan#include <sys/interrupt.h>
39132718Skan#include <sys/kernel.h>
4090075Sobrien#include <sys/kthread.h>
4190075Sobrien#include <sys/malloc.h>
4290075Sobrien#include <sys/proc.h>
4352284Sobrien#include <sys/taskqueue.h>
4452284Sobrien#include <machine/clock.h>
4552284Sobrien
46132718Skan#include "acpi.h"
4752284Sobrien#include <dev/acpica/acpivar.h>
4890075Sobrien
49132718Skan#define _COMPONENT	ACPI_OS_SERVICES
50132718SkanACPI_MODULE_NAME("SCHEDULE")
51132718Skan
5252284Sobrien/*
5352284Sobrien * This is a little complicated due to the fact that we need to build and then
5452284Sobrien * free a 'struct task' for each task we enqueue.
5552284Sobrien */
5652284Sobrien
5752284SobrienMALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
5852284Sobrien
5952284Sobrienstatic void	AcpiOsExecuteQueue(void *arg, int pending);
6090075Sobrien
6190075Sobrienstruct acpi_task {
6290075Sobrien    struct task			at_task;
6390075Sobrien    OSD_EXECUTION_CALLBACK	at_function;
6490075Sobrien    void			*at_context;
6590075Sobrien};
6652284Sobrien
67132718Skanstruct acpi_task_queue {
6890075Sobrien    STAILQ_ENTRY(acpi_task_queue) at_q;
6990075Sobrien    struct acpi_task		*at;
7090075Sobrien};
7190075Sobrien
7290075Sobrien/*
7390075Sobrien * Private task queue definition for ACPI
7490075Sobrien */
7590075SobrienTASKQUEUE_DECLARE(acpi);
76132718Skanstatic void	*taskqueue_acpi_ih;
7752284Sobrien
78132718Skanstatic void
79132718Skantaskqueue_acpi_enqueue(void *context)
80132718Skan{
8152284Sobrien    swi_sched(taskqueue_acpi_ih, 0);
82132718Skan}
83132718Skan
84132718Skanstatic void
85132718Skantaskqueue_acpi_run(void *dummy)
8652284Sobrien{
87132718Skan    taskqueue_run(taskqueue_acpi);
88132718Skan}
89132718Skan
90132718SkanTASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0,
91132718Skan		 swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL,
92132718Skan		     SWI_TQ, 0, &taskqueue_acpi_ih));
93132718Skan
94132718Skanstatic STAILQ_HEAD(, acpi_task_queue) acpi_task_queue;
95132718SkanACPI_LOCK_DECL(taskq, "ACPI task queue");
96132718Skan
9752284Sobrienstatic void
98132718Skanacpi_task_thread(void *arg)
99132718Skan{
100132718Skan    struct acpi_task_queue	*atq;
101132718Skan    OSD_EXECUTION_CALLBACK	Function;
102132718Skan    void			*Context;
103132718Skan
104132718Skan    ACPI_LOCK(taskq);
105132718Skan    for (;;) {
106132718Skan	while ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL)
107132718Skan	    msleep(&acpi_task_queue, &taskq_mutex, PCATCH, "actask", 0);
10852284Sobrien	STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q);
109132718Skan	ACPI_UNLOCK(taskq);
110132718Skan
111132718Skan	Function = (OSD_EXECUTION_CALLBACK)atq->at->at_function;
112132718Skan	Context = atq->at->at_context;
113132718Skan
114132718Skan	Function(Context);
115132718Skan
116132718Skan	free(atq->at, M_ACPITASK);
117132718Skan	free(atq, M_ACPITASK);
118132718Skan	ACPI_LOCK(taskq);
11952284Sobrien    }
120132718Skan
121132718Skan    kthread_exit(0);
122132718Skan}
123132718Skan
124132718Skanint
125132718Skanacpi_task_thread_init(void)
126132718Skan{
127132718Skan    int		i, err;
128132718Skan    struct proc	*acpi_kthread_proc;
129132718Skan
13052284Sobrien    err = 0;
131132718Skan    STAILQ_INIT(&acpi_task_queue);
132132718Skan
133132718Skan    for (i = 0; i < ACPI_MAX_THREADS; i++) {
134132718Skan	err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc,
135132718Skan			     0, 0, "acpi_task%d", i);
136132718Skan	if (err != 0) {
137132718Skan	    printf("%s: kthread_create failed(%d)\n", __func__, err);
138132718Skan	    break;
139132718Skan	}
140132718Skan    }
14152284Sobrien    return (err);
142132718Skan}
143132718Skan
144132718Skan/* This function is called in interrupt context. */
145132718SkanACPI_STATUS
146132718SkanAcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function,
147132718Skan    void *Context)
14852284Sobrien{
149258428Spfg    struct acpi_task	*at;
150132718Skan    int pri;
151132718Skan
152132718Skan    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
153132718Skan
154132718Skan    if (Function == NULL)
155132718Skan	return_ACPI_STATUS (AE_BAD_PARAMETER);
156132718Skan
157132718Skan    at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT | M_ZERO);
15852284Sobrien    if (at == NULL)
159132718Skan	return_ACPI_STATUS (AE_NO_MEMORY);
160132718Skan
161132718Skan    at->at_function = Function;
162132718Skan    at->at_context = Context;
16352284Sobrien    switch (Priority) {
164132718Skan    case OSD_PRIORITY_GPE:
165132718Skan	pri = 4;
166132718Skan	break;
167132718Skan    case OSD_PRIORITY_HIGH:
168132718Skan	pri = 3;
169132718Skan	break;
170132718Skan    case OSD_PRIORITY_MED:
171132718Skan	pri = 2;
17252284Sobrien	break;
173132718Skan    case OSD_PRIORITY_LO:
174132718Skan	pri = 1;
175132718Skan	break;
17652284Sobrien    default:
177132718Skan	free(at, M_ACPITASK);
178132718Skan	return_ACPI_STATUS (AE_BAD_PARAMETER);
179132718Skan    }
18052284Sobrien    TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at);
181132718Skan
182132718Skan    taskqueue_enqueue(taskqueue_acpi, (struct task *)at);
183132718Skan
18452284Sobrien    return_ACPI_STATUS (AE_OK);
185132718Skan}
186132718Skan
187132718Skanstatic void
18852284SobrienAcpiOsExecuteQueue(void *arg, int pending)
189132718Skan{
190132718Skan    struct acpi_task_queue	*atq;
191132718Skan    OSD_EXECUTION_CALLBACK	Function;
19252284Sobrien    void			*Context;
193132718Skan
194132718Skan    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
19552284Sobrien
19652284Sobrien    atq = NULL;
197132718Skan    Function = NULL;
198132718Skan    Context = NULL;
199132718Skan
200132718Skan    atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT);
20190075Sobrien    if (atq == NULL) {
202132718Skan	printf("%s: no memory\n", __func__);
203132718Skan	return;
204132718Skan    }
205132718Skan    atq->at = (struct acpi_task *)arg;
206132718Skan
207169689Skan    ACPI_LOCK(taskq);
208132718Skan    STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q);
209132718Skan    wakeup_one(&acpi_task_queue);
210132718Skan    ACPI_UNLOCK(taskq);
211132718Skan
212132718Skan    return_VOID;
213132718Skan}
214132718Skan
215132718Skanvoid
216132718SkanAcpiOsSleep(UINT32 Seconds, UINT32 Milliseconds)
217132718Skan{
218132718Skan    int		timo;
219132718Skan    static int	dummy;
220132718Skan
221132718Skan    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
222132718Skan
223132718Skan    timo = (Seconds * hz) + Milliseconds * hz / 1000;
224132718Skan
225132718Skan    /*
226132718Skan     * If requested sleep time is less than our hz resolution, use
227169689Skan     * DELAY instead for better granularity.
228132718Skan     */
229132718Skan    if (timo > 0)
23090075Sobrien	tsleep(&dummy, 0, "acpislp", timo);
231169689Skan    else
232169689Skan	DELAY(Milliseconds * 1000);
233169689Skan
234169689Skan    return_VOID;
235169689Skan}
236169689Skan
237169689Skanvoid
238169689SkanAcpiOsStall(UINT32 Microseconds)
239169689Skan{
240169689Skan    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
241
242    DELAY(Microseconds);
243    return_VOID;
244}
245
246UINT32
247AcpiOsGetThreadId(void)
248{
249    struct proc *p;
250
251    /* XXX do not add ACPI_FUNCTION_TRACE here, results in recursive call. */
252
253    p = curproc;
254    KASSERT(p != NULL, ("%s: curproc is NULL!", __func__));
255
256    /* Returning 0 is not allowed. */
257    return (p->p_pid + 1);
258}
259