[PATCH v3 1/3] ACPI / debugger: Add kernel flushing support
From: Lv Zheng
Date: Fri Jul 22 2016 - 00:17:20 EST
This patch adds debugger log flushing support in kernel via .ioctl()
callback. The in-kernel flushing is more efficient, because it reduces
useless log IOs by bypassing log user_read/kern_write during the flush
period.
Signed-off-by: Lv Zheng <lv.zheng@xxxxxxxxx>
Cc: linux-api@xxxxxxxxxxxxxxx
---
drivers/acpi/acpi_dbg.c | 85 ++++++++++++++++++++++++++++++++++++--
include/linux/acpi.h | 1 +
include/uapi/linux/acpi-ioctls.h | 21 ++++++++++
3 files changed, 103 insertions(+), 4 deletions(-)
create mode 100644 include/uapi/linux/acpi-ioctls.h
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c
index dee8692..a5f4457 100644
--- a/drivers/acpi/acpi_dbg.c
+++ b/drivers/acpi/acpi_dbg.c
@@ -46,6 +46,8 @@
#define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN)
#define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN)
#define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED)
+#define ACPI_AML_FLUSHING_LOG 0x0040 /* flushing log output */
+#define ACPI_AML_WAITING_CMD 0x0080 /* waiting for cmd input */
struct acpi_aml_io {
wait_queue_head_t wait;
@@ -120,6 +122,16 @@ static inline bool __acpi_aml_busy(void)
return false;
}
+static inline bool __acpi_aml_waiting_cmd(void)
+{
+ return !!(acpi_aml_io.flags & ACPI_AML_WAITING_CMD);
+}
+
+static inline bool __acpi_aml_flushing_log(void)
+{
+ return !!(acpi_aml_io.flags & ACPI_AML_FLUSHING_LOG);
+}
+
static inline bool __acpi_aml_opened(void)
{
if (acpi_aml_io.flags & ACPI_AML_OPEN)
@@ -152,6 +164,26 @@ static bool acpi_aml_busy(void)
return ret;
}
+static inline bool acpi_aml_waiting_cmd(void)
+{
+ bool ret;
+
+ mutex_lock(&acpi_aml_io.lock);
+ ret = __acpi_aml_waiting_cmd();
+ mutex_unlock(&acpi_aml_io.lock);
+ return ret;
+}
+
+static inline bool acpi_aml_flushing_log(void)
+{
+ bool ret;
+
+ mutex_lock(&acpi_aml_io.lock);
+ ret = __acpi_aml_flushing_log();
+ mutex_unlock(&acpi_aml_io.lock);
+ return ret;
+}
+
static bool acpi_aml_used(void)
{
bool ret;
@@ -183,7 +215,8 @@ static bool acpi_aml_kern_writable(void)
mutex_lock(&acpi_aml_io.lock);
ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) ||
- __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN);
+ __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN) ||
+ __acpi_aml_flushing_log();
mutex_unlock(&acpi_aml_io.lock);
return ret;
}
@@ -264,6 +297,9 @@ static int acpi_aml_write_kern(const char *buf, int len)
int n;
char *p;
+ if (acpi_aml_flushing_log())
+ return len;
+
ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN);
if (ret < 0)
return ret;
@@ -458,9 +494,18 @@ static int acpi_aml_wait_command_ready(bool single_step,
else
acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
+ mutex_lock(&acpi_aml_io.lock);
+ acpi_aml_io.flags |= ACPI_AML_WAITING_CMD;
+ wake_up_interruptible(&acpi_aml_io.wait);
+ mutex_unlock(&acpi_aml_io.lock);
+
status = acpi_os_get_line(buffer, length, NULL);
if (ACPI_FAILURE(status))
return -EINVAL;
+
+ mutex_lock(&acpi_aml_io.lock);
+ acpi_aml_io.flags &= ~ACPI_AML_WAITING_CMD;
+ mutex_unlock(&acpi_aml_io.lock);
return 0;
}
@@ -593,9 +638,11 @@ static int acpi_aml_read_user(char __user *buf, int len)
smp_rmb();
p = &crc->buf[crc->tail];
n = min(len, circ_count_to_end(crc));
- if (copy_to_user(buf, p, n)) {
- ret = -EFAULT;
- goto out;
+ if (!acpi_aml_flushing_log()) {
+ if (copy_to_user(buf, p, n)) {
+ ret = -EFAULT;
+ goto out;
+ }
}
/* sync tail after removing logs */
smp_mb();
@@ -731,10 +778,40 @@ static unsigned int acpi_aml_poll(struct file *file, poll_table *wait)
return masks;
}
+static int acpi_aml_flush(void)
+{
+ int ret;
+
+ /*
+ * Discard output buffer and put the driver into a state waiting
+ * for the new user input.
+ */
+ mutex_lock(&acpi_aml_io.lock);
+ acpi_aml_io.flags |= ACPI_AML_FLUSHING_LOG;
+ mutex_unlock(&acpi_aml_io.lock);
+
+ ret = wait_event_interruptible(acpi_aml_io.wait,
+ acpi_aml_waiting_cmd());
+ (void)acpi_aml_read_user(NULL, ACPI_AML_BUF_SIZE);
+
+ mutex_lock(&acpi_aml_io.lock);
+ acpi_aml_io.flags &= ~ACPI_AML_FLUSHING_LOG;
+ mutex_unlock(&acpi_aml_io.lock);
+ return ret;
+}
+
+static long acpi_aml_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return cmd == ACPI_IOCTL_DEBUGGER_FLUSH ?
+ acpi_aml_flush() : -EINVAL;
+}
+
static const struct file_operations acpi_aml_operations = {
.read = acpi_aml_read,
.write = acpi_aml_write,
.poll = acpi_aml_poll,
+ .unlocked_ioctl = acpi_aml_ioctl,
.open = acpi_aml_open,
.release = acpi_aml_release,
.llseek = generic_file_llseek,
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 08235a6..9354fb8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -26,6 +26,7 @@
#include <linux/resource_ext.h>
#include <linux/device.h>
#include <linux/property.h>
+#include <uapi/linux/acpi-ioctls.h>
#ifndef _LINUX
#define _LINUX
diff --git a/include/uapi/linux/acpi-ioctls.h b/include/uapi/linux/acpi-ioctls.h
new file mode 100644
index 0000000..71b891a
--- /dev/null
+++ b/include/uapi/linux/acpi-ioctls.h
@@ -0,0 +1,21 @@
+/*
+ * ACPI IOCTL collections
+ *
+ * Copyright (C) 2016, Intel Corporation
+ * Authors: Lv Zheng <lv.zheng@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _UAPI_LINUX_ACPI_IOCTLS_H
+#define _UAPI_LINUX_ACPI_IOCTLS_H
+
+#include <linux/ioctl.h>
+
+#define ACPI_IOCTL_IDENT 'a'
+
+#define ACPI_IOCTL_DEBUGGER_FLUSH _IO(ACPI_IOCTL_IDENT, 0x80)
+
+#endif /* _UAPI_LINUX_ACPI_IOCTLS_H */
--
1.7.10