Index: sys/compat/linuxkpi/common/include/acpi/acpi.h =================================================================== --- /dev/null +++ sys/compat/linuxkpi/common/include/acpi/acpi.h @@ -0,0 +1,99 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017 Mark Johnston + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _ACPI_ACPI_H_ +#define _ACPI_ACPI_H_ + +/* + * FreeBSD import of ACPICA has a typedef for BOOLEAN which conflicts with + * amdgpu driver. Workaround it on preprocessor level. + */ +#define ACPI_USE_SYSTEM_INTTYPES +#define BOOLEAN unsigned char +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef short INT16; +typedef unsigned int UINT32; +typedef int INT32; +typedef uint64_t UINT64; +typedef int64_t INT64; +#include +#undef BOOLEAN + +typedef ACPI_HANDLE acpi_handle; +typedef ACPI_OBJECT acpi_object; +typedef ACPI_OBJECT_HANDLER acpi_object_handler; +typedef ACPI_OBJECT_TYPE acpi_object_type; +typedef ACPI_STATUS acpi_status; +typedef ACPI_STRING acpi_string; +typedef ACPI_SIZE acpi_size; +typedef ACPI_WALK_CALLBACK acpi_walk_callback; + +static inline ACPI_STATUS +acpi_evaluate_object(ACPI_HANDLE Object, ACPI_STRING Pathname, + ACPI_OBJECT_LIST *ParameterObjects, ACPI_BUFFER *ReturnObjectBuffer) +{ + return (AcpiEvaluateObject( + Object, Pathname, ParameterObjects, ReturnObjectBuffer)); +} + +static inline const char * +acpi_format_exception(ACPI_STATUS Exception) +{ + return (AcpiFormatException(Exception)); +} + +static inline ACPI_STATUS +acpi_get_handle(ACPI_HANDLE Parent, ACPI_STRING Pathname, + ACPI_HANDLE *RetHandle) +{ + return (AcpiGetHandle(Parent, Pathname, RetHandle)); +} + +static inline ACPI_STATUS +acpi_get_data(ACPI_HANDLE ObjHandle, ACPI_OBJECT_HANDLER Handler, void **Data) +{ + return (AcpiGetData(ObjHandle, Handler, Data)); +} + +static inline ACPI_STATUS +acpi_get_name(ACPI_HANDLE Object, uint32_t NameType, ACPI_BUFFER *Buffer) +{ + return (AcpiGetName(Object, NameType, Buffer)); +} + +static inline ACPI_STATUS +acpi_get_table(ACPI_STRING Signature, uint32_t Instance, + ACPI_TABLE_HEADER **OutTable) +{ + return (AcpiGetTable(Signature, Instance, OutTable)); +} + +#endif /* _ACPI_ACPI_H_ */ Index: sys/compat/linuxkpi/common/include/acpi/acpi_bus.h =================================================================== --- /dev/null +++ sys/compat/linuxkpi/common/include/acpi/acpi_bus.h @@ -0,0 +1,52 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Vladimir Kondratyev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _ACPI_ACPI_BUS_H_ +#define _ACPI_ACPI_BUS_H_ + +typedef char acpi_device_class[20]; + +struct acpi_bus_event { + acpi_device_class device_class; + uint32_t type; + uint32_t data; +}; + +ACPI_HANDLE bsd_acpi_get_handle(device_t bsddev); +bool acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, + uint64_t funcs); +ACPI_OBJECT * acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid, + int rev, int func, ACPI_OBJECT *argv4, + ACPI_OBJECT_TYPE type); +int register_acpi_notifier(struct notifier_block *nb); +int unregister_acpi_notifier(struct notifier_block *nb); +uint32_t acpi_target_system_state(void); + +#endif /* !_ACPI_ACPI_BUS_H_ */ Index: sys/compat/linuxkpi/common/include/acpi/video.h =================================================================== --- /dev/null +++ sys/compat/linuxkpi/common/include/acpi/video.h @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Vladimir Kondratyev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _ACPI_VIDEO_H_ +#define _ACPI_VIDEO_H_ + +#define ACPI_VIDEO_CLASS "video" + +#define ACPI_VIDEO_NOTIFY_PROBE 0x81 + +#endif /* !_ACPI_VIDEO_H_ */ Index: sys/compat/linuxkpi/common/include/linux/acpi.h =================================================================== --- /dev/null +++ sys/compat/linuxkpi/common/include/linux/acpi.h @@ -0,0 +1,42 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Vladimir Kondratyev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _LINUX_ACPI_H_ +#define _LINUX_ACPI_H_ + +#include + +#include +#include + +#define ACPI_HANDLE(dev) \ + ((dev)->bsddev != NULL ? bsd_acpi_get_handle((dev)->bsddev) : NULL) + +#endif /* _LINUX_ACPI_H_ */ Index: sys/compat/linuxkpi/common/src/linux_acpi.c =================================================================== --- /dev/null +++ sys/compat/linuxkpi/common/src/linux_acpi.c @@ -0,0 +1,243 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Johannes Lundberg + * Copyright (c) 2020 Vladimir Kondratyev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_acpi.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define ACPI_AC_CLASS "ac_adapter" + +ACPI_MODULE_NAME("linux_acpi") + +enum { + LINUX_ACPI_ACAD, + LINUX_ACPI_VIDEO, + LINUX_ACPI_TAGS /* must be last */ +}; +_Static_assert(LINUX_ACPI_TAGS <= LINUX_NOTIFY_TAGS, + "Not enough space for tags in notifier_block structure"); + +#ifdef DEV_ACPI + +static uint32_t linux_acpi_target_sleep_state = ACPI_STATE_S0; + +static eventhandler_tag resume_tag; +static eventhandler_tag suspend_tag; + +ACPI_HANDLE +bsd_acpi_get_handle(device_t bsddev) +{ + return (acpi_get_handle(bsddev)); +} + +bool +acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, uint64_t funcs) +{ + + if (funcs == 0) + return (false); + + /* + * From ACPI 6.3 spec 9.1.1: + * Bit 0 indicates whether there is support for any functions other + * than function 0 for the specified UUID and Revision ID. If set to + * zero, no functions are supported (other than function zero) for the + * specified UUID and Revision ID. + */ + funcs |= 1 << 0; + + return ((acpi_DSMQuery(handle, uuid, rev) & funcs) == funcs); +} + +ACPI_OBJECT * +acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid, int rev, + int func, ACPI_OBJECT *argv4, ACPI_OBJECT_TYPE type) +{ + ACPI_BUFFER buf; + + return (ACPI_SUCCESS(acpi_EvaluateDSMTyped(handle, uuid, rev, func, + argv4, &buf, type)) ? (ACPI_OBJECT *)buf.Pointer : NULL); +} + +static void +linux_handle_power_suspend_event(void *arg __unused) +{ + /* + * Only support S3 for now. + * acpi_sleep_event isn't always called so we use power_suspend_early + * instead which means we don't know what state we're switching to. + * TODO: Make acpi_sleep_event consistent + */ + linux_acpi_target_sleep_state = ACPI_STATE_S3; +} + +static void +linux_handle_power_resume_event(void *arg __unused) +{ + linux_acpi_target_sleep_state = ACPI_STATE_S0; +} + +static void +linux_handle_acpi_acad_event(void *arg, int data) +{ + struct notifier_block *nb = arg; + /* + * Event type information is lost ATM in FreeBSD ACPI event handler. + * Fortunately, drm-kmod do not distinct AC event types too, so we can + * use any type e.g. ACPI_NOTIFY_BUS_CHECK that suits notifier handler. + */ + struct acpi_bus_event abe = { + .device_class = ACPI_AC_CLASS, + .type = ACPI_NOTIFY_BUS_CHECK, + .data = data, + }; + + nb->notifier_call(nb, 0, &abe); +} + +static void +linux_handle_acpi_video_event(void *arg, int type) +{ + struct notifier_block *nb = arg; + struct acpi_bus_event abe = { + .device_class = ACPI_VIDEO_CLASS, + .type = type, + .data = 0, + }; + + nb->notifier_call(nb, 0, &abe); +} + +int +register_acpi_notifier(struct notifier_block *nb) +{ + nb->tags[LINUX_ACPI_ACAD] = EVENTHANDLER_REGISTER(acpi_acad_event, + linux_handle_acpi_acad_event, nb, EVENTHANDLER_PRI_FIRST); + nb->tags[LINUX_ACPI_VIDEO] = EVENTHANDLER_REGISTER(acpi_video_event, + linux_handle_acpi_video_event, nb, EVENTHANDLER_PRI_FIRST); + + return (0); +} + +int +unregister_acpi_notifier(struct notifier_block *nb) +{ + EVENTHANDLER_DEREGISTER(acpi_acad_event, nb->tags[LINUX_ACPI_ACAD]); + EVENTHANDLER_DEREGISTER(acpi_video_event, nb->tags[LINUX_ACPI_VIDEO]); + + return (0); +} + +uint32_t +acpi_target_system_state(void) +{ + return (linux_acpi_target_sleep_state); +} + +static void +linux_register_acpi_event_handlers(void *arg __unused) +{ + /* + * XXX johalun: acpi_{sleep,wakeup}_event can't be trusted, use + * power_{suspend_early,resume} 'acpiconf -s 3' or 'zzz' will not + * generate acpi_sleep_event... Lid open or wake on button generates + * acpi_wakeup_event on one of my Dell laptops but not the other + * (but it does power on)... is this a general thing? + */ + resume_tag = EVENTHANDLER_REGISTER(power_resume, + linux_handle_power_resume_event, NULL, EVENTHANDLER_PRI_FIRST); + suspend_tag = EVENTHANDLER_REGISTER(power_suspend_early, + linux_handle_power_suspend_event, NULL, EVENTHANDLER_PRI_FIRST); +} + +static void +linux_deregister_acpi_event_handlers(void *arg __unused) +{ + EVENTHANDLER_DEREGISTER(power_resume, resume_tag); + EVENTHANDLER_DEREGISTER(power_suspend_early, suspend_tag); +} + +SYSINIT(linux_acpi_events, SI_SUB_DRIVERS, SI_ORDER_ANY, + linux_register_acpi_event_handlers, NULL); +SYSUNINIT(linux_acpi_events, SI_SUB_DRIVERS, SI_ORDER_ANY, + linux_deregister_acpi_event_handlers, NULL); + +#else /* !DEV_ACPI */ + +ACPI_HANDLE +bsd_acpi_get_handle(device_t bsddev) +{ + return (NULL); +} + +bool +acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev, uint64_t funcs) +{ + return (false); +} + +ACPI_OBJECT * +acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid, int rev, + int func, ACPI_OBJECT *argv4, ACPI_OBJECT_TYPE type) +{ + return (NULL); +} + +int +register_acpi_notifier(struct notifier_block *nb) +{ + return (0); +} + +int +unregister_acpi_notifier(struct notifier_block *nb) +{ + return (0); +} + +uint32_t +acpi_target_system_state(void) +{ + return (ACPI_STATE_S0); +} + +#endif /* !DEV_ACPI */ Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -4508,6 +4508,8 @@ # Linux Kernel Programming Interface compat/linuxkpi/common/src/linux_kmod.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" +compat/linuxkpi/common/src/linux_acpi.c optional compat_linuxkpi \ + compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_compat.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_current.c optional compat_linuxkpi \ Index: sys/conf/kmod.mk =================================================================== --- sys/conf/kmod.mk +++ sys/conf/kmod.mk @@ -98,6 +98,7 @@ pci_iov_if.h \ vnode_if.h \ usb_if.h \ + opt_acpi.h \ opt_usb.h \ opt_stack.h Index: sys/dev/acpica/acpi_acad.c =================================================================== --- sys/dev/acpica/acpi_acad.c +++ sys/dev/acpica/acpi_acad.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -115,6 +116,7 @@ ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), "%s Line\n", newstatus ? "On" : "Off"); acpi_UserNotify("ACAD", h, newstatus); + EVENTHANDLER_INVOKE(acpi_acad_event, newstatus); } else ACPI_SERIAL_END(acad); } Index: sys/dev/acpica/acpi_video.c =================================================================== --- sys/dev/acpica/acpi_video.c +++ sys/dev/acpica/acpi_video.c @@ -350,6 +350,12 @@ return (0); } +static void +acpi_video_invoke_event_handler(void *context) +{ + EVENTHANDLER_INVOKE(acpi_video_event, (int)(intptr_t)context); +} + static void acpi_video_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context) { @@ -402,6 +408,8 @@ device_printf(sc->device, "unknown notify event 0x%x\n", notify); } + AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_video_invoke_event_handler, + (void *)(uintptr_t)notify); } static void Index: sys/dev/acpica/acpivar.h =================================================================== --- sys/dev/acpica/acpivar.h +++ sys/dev/acpica/acpivar.h @@ -433,6 +433,8 @@ EVENTHANDLER_DECLARE(acpi_sleep_event, acpi_event_handler_t); EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t); +EVENTHANDLER_DECLARE(acpi_acad_event, acpi_event_handler_t); +EVENTHANDLER_DECLARE(acpi_video_event, acpi_event_handler_t); /* Device power control. */ ACPI_STATUS acpi_pwr_wake_enable(ACPI_HANDLE consumer, int enable); Index: sys/modules/linuxkpi/Makefile =================================================================== --- sys/modules/linuxkpi/Makefile +++ sys/modules/linuxkpi/Makefile @@ -2,7 +2,8 @@ .PATH: ${SRCTOP}/sys/compat/linuxkpi/common/src KMOD= linuxkpi -SRCS= linux_compat.c \ +SRCS= linux_acpi.c \ + linux_compat.c \ linux_current.c \ linux_hrtimer.c \ linux_idr.c \