Commit 25474279 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'acpi-bus', 'acpi-pci', 'acpica' and 'acpi-doc'

* acpi-bus:
  ACPI / bus: Support for platform initiated graceful shutdown
  ACPI / bus: Correct the comments about acpi_subsystem_init()
  ACPI / bus: Use acpi_handle_debug() in acpi_print_osc_error()

* acpi-pci:
  ACPI / PCI: make pci_slot explicitly non-modular
  ACPI / PCI: pci_slot: Use generic pr_debug utility
  ACPI / PCI: pci_slot: Use more common logging style

* acpica:
  ACPICA: Linux: Enable ACPI_MUTEX_DEBUG for Linux kernel

* acpi-doc:
  ACPI / debugger: Add AML debugger documentation
  ACPI: Add documentation describing ACPICA release automation
The AML Debugger
Copyright (C) 2016, Intel Corporation
Author: Lv Zheng <lv.zheng@intel.com>
This document describes the usage of the AML debugger embedded in the Linux
kernel.
1. Build the debugger
The following kernel configuration items are required to enable the AML
debugger interface from the Linux kernel:
CONFIG_ACPI_DEBUGGER=y
CONFIG_ACPI_DEBUGGER_USER=m
The userspace utlities can be built from the kernel source tree using
the following commands:
$ cd tools
$ make acpi
The resultant userspace tool binary is then located at:
tools/acpi/power/acpi/acpidbg/acpidbg
It can be installed to system directories by running "make install" (as a
sufficiently privileged user).
2. Start the userspace debugger interface
After booting the kernel with the debugger built-in, the debugger can be
started by using the following commands:
# mount -t debugfs none /sys/kernel/debug
# modprobe acpi_dbg
# tools/acpi/power/acpi/acpidbg/acpidbg
That spawns the interactive AML debugger environment where you can execute
debugger commands.
The commands are documented in the "ACPICA Overview and Programmer Reference"
that can be downloaded from
https://acpica.org/documentation
The detailed debugger commands reference is located in Chapter 12 "ACPICA
Debugger Reference". The "help" command can be used for a quick reference.
3. Stop the userspace debugger interface
The interactive debugger interface can be closed by pressing Ctrl+C or using
the "quit" or "exit" commands. When finished, unload the module with:
# rmmod acpi_dbg
The module unloading may fail if there is an acpidbg instance running.
4. Run the debugger in a script
It may be useful to run the AML debugger in a test script. "acpidbg" supports
this in a special "batch" mode. For example, the following command outputs
the entire ACPI namespace:
# acpidbg -b "namespace"
This diff is collapsed.
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/workqueue.h>
#include <linux/reboot.h>
#include <linux/delay.h>
#ifdef CONFIG_X86 #ifdef CONFIG_X86
#include <asm/mpspec.h> #include <asm/mpspec.h>
#endif #endif
...@@ -176,20 +179,15 @@ EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data); ...@@ -176,20 +179,15 @@ EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data);
static void acpi_print_osc_error(acpi_handle handle, static void acpi_print_osc_error(acpi_handle handle,
struct acpi_osc_context *context, char *error) struct acpi_osc_context *context, char *error)
{ {
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
int i; int i;
if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) acpi_handle_debug(handle, "(%s): %s\n", context->uuid_str, error);
printk(KERN_DEBUG "%s: %s\n", context->uuid_str, error);
else { pr_debug("_OSC request data:");
printk(KERN_DEBUG "%s (%s): %s\n",
(char *)buffer.pointer, context->uuid_str, error);
kfree(buffer.pointer);
}
printk(KERN_DEBUG "_OSC request data:");
for (i = 0; i < context->cap.length; i += sizeof(u32)) for (i = 0; i < context->cap.length; i += sizeof(u32))
printk(" %x", *((u32 *)(context->cap.pointer + i))); pr_debug(" %x", *((u32 *)(context->cap.pointer + i)));
printk("\n");
pr_debug("\n");
} }
acpi_status acpi_str_to_uuid(char *str, u8 *uuid) acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
...@@ -475,6 +473,56 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) ...@@ -475,6 +473,56 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
acpi_device_notify); acpi_device_notify);
} }
/* Handle events targeting \_SB device (at present only graceful shutdown) */
#define ACPI_SB_NOTIFY_SHUTDOWN_REQUEST 0x81
#define ACPI_SB_INDICATE_INTERVAL 10000
static void sb_notify_work(struct work_struct *dummy)
{
acpi_handle sb_handle;
orderly_poweroff(true);
/*
* After initiating graceful shutdown, the ACPI spec requires OSPM
* to evaluate _OST method once every 10seconds to indicate that
* the shutdown is in progress
*/
acpi_get_handle(NULL, "\\_SB", &sb_handle);
while (1) {
pr_info("Graceful shutdown in progress.\n");
acpi_evaluate_ost(sb_handle, ACPI_OST_EC_OSPM_SHUTDOWN,
ACPI_OST_SC_OS_SHUTDOWN_IN_PROGRESS, NULL);
msleep(ACPI_SB_INDICATE_INTERVAL);
}
}
static void acpi_sb_notify(acpi_handle handle, u32 event, void *data)
{
static DECLARE_WORK(acpi_sb_work, sb_notify_work);
if (event == ACPI_SB_NOTIFY_SHUTDOWN_REQUEST) {
if (!work_busy(&acpi_sb_work))
schedule_work(&acpi_sb_work);
} else
pr_warn("event %x is not supported by \\_SB device\n", event);
}
static int __init acpi_setup_sb_notify_handler(void)
{
acpi_handle sb_handle;
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &sb_handle)))
return -ENXIO;
if (ACPI_FAILURE(acpi_install_notify_handler(sb_handle, ACPI_DEVICE_NOTIFY,
acpi_sb_notify, NULL)))
return -EINVAL;
return 0;
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Device Matching Device Matching
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
...@@ -961,8 +1009,7 @@ void __init acpi_early_init(void) ...@@ -961,8 +1009,7 @@ void __init acpi_early_init(void)
/** /**
* acpi_subsystem_init - Finalize the early initialization of ACPI. * acpi_subsystem_init - Finalize the early initialization of ACPI.
* *
* Switch over the platform to the ACPI mode (if possible), initialize the * Switch over the platform to the ACPI mode (if possible).
* handling of ACPI events, install the interrupt and global lock handlers.
* *
* Doing this too early is generally unsafe, but at the same time it needs to be * Doing this too early is generally unsafe, but at the same time it needs to be
* done before all things that really depend on ACPI. The right spot appears to * done before all things that really depend on ACPI. The right spot appears to
...@@ -1133,6 +1180,7 @@ static int __init acpi_init(void) ...@@ -1133,6 +1180,7 @@ static int __init acpi_init(void)
acpi_sleep_proc_init(); acpi_sleep_proc_init();
acpi_wakeup_device_init(); acpi_wakeup_device_init();
acpi_debugger_init(); acpi_debugger_init();
acpi_setup_sb_notify_handler();
return 0; return 0;
} }
......
...@@ -22,8 +22,9 @@ ...@@ -22,8 +22,9 @@
* General Public License for more details. * General Public License for more details.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -33,30 +34,11 @@ ...@@ -33,30 +34,11 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/pci-acpi.h> #include <linux/pci-acpi.h>
static bool debug;
static int check_sta_before_sun; static int check_sta_before_sun;
#define DRIVER_VERSION "0.1"
#define DRIVER_AUTHOR "Alex Chiang <achiang@hp.com>"
#define DRIVER_DESC "ACPI PCI Slot Detection Driver"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
module_param(debug, bool, 0644);
#define _COMPONENT ACPI_PCI_COMPONENT #define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_slot"); ACPI_MODULE_NAME("pci_slot");
#define MY_NAME "pci_slot"
#define err(format, arg...) pr_err("%s: " format , MY_NAME , ## arg)
#define info(format, arg...) pr_info("%s: " format , MY_NAME , ## arg)
#define dbg(format, arg...) \
do { \
if (debug) \
pr_debug("%s: " format, MY_NAME , ## arg); \
} while (0)
#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */ #define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
struct acpi_pci_slot { struct acpi_pci_slot {
...@@ -76,7 +58,7 @@ check_slot(acpi_handle handle, unsigned long long *sun) ...@@ -76,7 +58,7 @@ check_slot(acpi_handle handle, unsigned long long *sun)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
dbg("Checking slot on path: %s\n", (char *)buffer.pointer); pr_debug("Checking slot on path: %s\n", (char *)buffer.pointer);
if (check_sta_before_sun) { if (check_sta_before_sun) {
/* If SxFy doesn't have _STA, we just assume it's there */ /* If SxFy doesn't have _STA, we just assume it's there */
...@@ -87,14 +69,16 @@ check_slot(acpi_handle handle, unsigned long long *sun) ...@@ -87,14 +69,16 @@ check_slot(acpi_handle handle, unsigned long long *sun)
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer); pr_debug("_ADR returned %d on %s\n",
status, (char *)buffer.pointer);
goto out; goto out;
} }
/* No _SUN == not a slot == bail */ /* No _SUN == not a slot == bail */
status = acpi_evaluate_integer(handle, "_SUN", NULL, sun); status = acpi_evaluate_integer(handle, "_SUN", NULL, sun);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer); pr_debug("_SUN returned %d on %s\n",
status, (char *)buffer.pointer);
goto out; goto out;
} }
...@@ -132,15 +116,13 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -132,15 +116,13 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
} }
slot = kmalloc(sizeof(*slot), GFP_KERNEL); slot = kmalloc(sizeof(*slot), GFP_KERNEL);
if (!slot) { if (!slot)
err("%s: cannot allocate memory\n", __func__);
return AE_OK; return AE_OK;
}
snprintf(name, sizeof(name), "%llu", sun); snprintf(name, sizeof(name), "%llu", sun);
pci_slot = pci_create_slot(pci_bus, device, name, NULL); pci_slot = pci_create_slot(pci_bus, device, name, NULL);
if (IS_ERR(pci_slot)) { if (IS_ERR(pci_slot)) {
err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot)); pr_err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
kfree(slot); kfree(slot);
return AE_OK; return AE_OK;
} }
...@@ -150,7 +132,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -150,7 +132,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
get_device(&pci_bus->dev); get_device(&pci_bus->dev);
dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n", pr_debug("%p, pci_bus: %x, device: %d, name: %s\n",
pci_slot, pci_bus->number, device, name); pci_slot, pci_bus->number, device, name);
return AE_OK; return AE_OK;
...@@ -186,7 +168,8 @@ void acpi_pci_slot_remove(struct pci_bus *bus) ...@@ -186,7 +168,8 @@ void acpi_pci_slot_remove(struct pci_bus *bus)
static int do_sta_before_sun(const struct dmi_system_id *d) static int do_sta_before_sun(const struct dmi_system_id *d)
{ {
info("%s detected: will evaluate _STA before calling _SUN\n", d->ident); pr_info("%s detected: will evaluate _STA before calling _SUN\n",
d->ident);
check_sta_before_sun = 1; check_sta_before_sun = 1;
return 0; return 0;
} }
......
...@@ -73,6 +73,10 @@ ...@@ -73,6 +73,10 @@
#define ACPI_DEBUGGER #define ACPI_DEBUGGER
#endif #endif
#ifdef CONFIG_ACPI_DEBUG
#define ACPI_MUTEX_DEBUG
#endif
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ctype.h> #include <linux/ctype.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment