From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755374AbcGZLBm (ORCPT ); Tue, 26 Jul 2016 07:01:42 -0400 Received: from mga03.intel.com ([134.134.136.65]:52514 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754629AbcGZLBj (ORCPT ); Tue, 26 Jul 2016 07:01:39 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.28,424,1464678000"; d="scan'208";a="1014019670" From: Lv Zheng To: "Rafael J. Wysocki" , "Rafael J. Wysocki" , Len Brown Cc: Lv Zheng , Lv Zheng , , linux-acpi@vger.kernel.org, linux-api@vger.kernel.org Subject: [PATCH v4 1/3] ACPI / debugger: Add kernel flushing support Date: Tue, 26 Jul 2016 19:01:33 +0800 Message-Id: X-Mailer: git-send-email 1.7.10 In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds debugger output 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. This mechanism is useful for the batch mode. Scripts can integrate a batch mode acpidbg instance to perform AML debugger functionalities. As the batch mode always starts from a new command write, it thus requires the kernel debugger driver to drop the old input/output first. The old input is automatically dropped by acpi_os_get_line() via an error returning value, but the output are remained in acpi_dbg output buffers and should be dropped prior than reading the new command, otherwise, the old output can be read out by the batch mode instance and the result of the batch mode command will be messed up. Signed-off-by: Lv Zheng Cc: linux-api@vger.kernel.org --- 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 #include #include +#include #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 + * + * 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 + +#define ACPI_IOCTL_IDENT 'a' + +#define ACPI_IOCTL_DEBUGGER_FLUSH _IO(ACPI_IOCTL_IDENT, 0x80) + +#endif /* _UAPI_LINUX_ACPI_IOCTLS_H */ -- 1.7.10