From patchwork Fri Sep 2 07:46:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lv Zheng X-Patchwork-Id: 9310505 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CB9BB607D2 for ; Fri, 2 Sep 2016 07:46:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BF8DE29683 for ; Fri, 2 Sep 2016 07:46:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B4657296D4; Fri, 2 Sep 2016 07:46:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A7ED929683 for ; Fri, 2 Sep 2016 07:46:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751913AbcIBHqj (ORCPT ); Fri, 2 Sep 2016 03:46:39 -0400 Received: from mga09.intel.com ([134.134.136.24]:50035 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751660AbcIBHqi (ORCPT ); Fri, 2 Sep 2016 03:46:38 -0400 Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga102.jf.intel.com with ESMTP; 02 Sep 2016 00:46:37 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.30,270,1470726000"; d="scan'208";a="3790426" Received: from lvzheng-z530.sh.intel.com ([10.239.159.35]) by fmsmga005.fm.intel.com with ESMTP; 02 Sep 2016 00:46:34 -0700 From: Lv Zheng To: "Rafael J. Wysocki" , "Rafael J. Wysocki" , Len Brown Cc: Lv Zheng , Lv Zheng , linux-acpi@vger.kernel.org, Peter Wu , Luya Tshimbalanga Subject: [PATCH 1/4] ACPI / EC: Cleanup first_ec/boot_ec code Date: Fri, 2 Sep 2016 15:46:31 +0800 Message-Id: <329458b814b546daf26e058d303729fdc936730f.1472802172.git.lv.zheng@intel.com> X-Mailer: git-send-email 1.7.10 In-Reply-To: References: Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In order to support full ECDT (driving the ECDT EC after probing the namespace EC), we need to change our EC device alloc/free algorithm, ensure not to free old boot EC before qualifying new boot EC. This patch achieves this by cleaning up first_ec/boot_ec logic: 1. first_ec: used to perform transactions, so it is assigned in new acpi_ec_setup() function. 2. boot_ec: used to track early EC device, so it is assigned in new acpi_config_boot_ec() function which explictly tells the driver to save the EC device as early EC device. Link: https://bugzilla.kernel.org/show_bug.cgi?id=115021 Reported-and-tested-by: Luya Tshimbalanga Suggested-by: Peter Wu Cc: Peter Wu Cc: Luya Tshimbalanga Signed-off-by: Lv Zheng --- drivers/acpi/ec.c | 96 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 33 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e7bd57c..4a5f3ab 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -179,6 +179,7 @@ static void acpi_ec_event_processor(struct work_struct *work); struct acpi_ec *boot_ec, *first_ec; EXPORT_SYMBOL(first_ec); +static bool boot_ec_is_ecdt = false; static struct workqueue_struct *ec_query_wq; static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ @@ -1228,7 +1229,16 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, static acpi_status ec_parse_io_ports(struct acpi_resource *resource, void *context); -static struct acpi_ec *make_acpi_ec(void) +static void acpi_ec_free(struct acpi_ec *ec) +{ + if (first_ec == ec) + first_ec = NULL; + if (boot_ec == ec) + boot_ec = NULL; + kfree(ec); +} + +static struct acpi_ec *acpi_ec_alloc(void) { struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); @@ -1290,6 +1300,11 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) return AE_CTRL_TERMINATE; } +/* + * Note: This function returns an error code only when the address space + * handler is not installed, which means "not able to handle + * transactions". + */ static int ec_install_handlers(struct acpi_ec *ec) { acpi_status status; @@ -1365,21 +1380,49 @@ static void ec_remove_handlers(struct acpi_ec *ec) } } -static struct acpi_ec *acpi_ec_alloc(void) +static int acpi_ec_setup(struct acpi_ec *ec) { - struct acpi_ec *ec; + int ret; - /* Check for boot EC */ - if (boot_ec) { - ec = boot_ec; - boot_ec = NULL; - ec_remove_handlers(ec); - if (first_ec == ec) - first_ec = NULL; - } else { - ec = make_acpi_ec(); + ret = ec_install_handlers(ec); + if (ret) + return ret; + + /* First EC capable of handling transactions */ + if (!first_ec) { + first_ec = ec; + acpi_handle_info(first_ec->handle, "Used as first EC\n"); } - return ec; + + acpi_handle_info(ec->handle, + "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", + ec->gpe, ec->command_addr, ec->data_addr); + return ret; +} + +static int acpi_config_boot_ec(struct acpi_ec *ec, bool is_ecdt) +{ + int ret; + + if (boot_ec) + ec_remove_handlers(boot_ec); + + /* Unset old boot EC */ + if (boot_ec != ec) + acpi_ec_free(boot_ec); + + ret = acpi_ec_setup(ec); + if (ret) + return ret; + + /* Set new boot EC */ + if (!boot_ec) { + boot_ec = ec; + boot_ec_is_ecdt = is_ecdt; + acpi_handle_info(boot_ec->handle, "Used as boot %s EC\n", + is_ecdt ? "ECDT" : "DSDT"); + } + return ret; } static int acpi_ec_add(struct acpi_device *device) @@ -1395,7 +1438,7 @@ static int acpi_ec_add(struct acpi_device *device) return -ENOMEM; if (ec_parse_device(device->handle, 0, ec, NULL) != AE_CTRL_TERMINATE) { - kfree(ec); + acpi_ec_free(ec); return -EINVAL; } @@ -1403,8 +1446,6 @@ static int acpi_ec_add(struct acpi_device *device) acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, acpi_ec_register_query_methods, NULL, ec, NULL); - if (!first_ec) - first_ec = ec; device->driver_data = ec; ret = !!request_region(ec->data_addr, 1, "EC data"); @@ -1412,10 +1453,7 @@ static int acpi_ec_add(struct acpi_device *device) ret = !!request_region(ec->command_addr, 1, "EC cmd"); WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); - pr_info("GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", - ec->gpe, ec->command_addr, ec->data_addr); - - ret = ec_install_handlers(ec); + ret = acpi_config_boot_ec(ec, false); /* Reprobe devices depending on the EC */ acpi_walk_dep_device_list(ec->handle); @@ -1442,9 +1480,7 @@ static int acpi_ec_remove(struct acpi_device *device) release_region(ec->data_addr, 1); release_region(ec->command_addr, 1); device->driver_data = NULL; - if (ec == first_ec) - first_ec = NULL; - kfree(ec); + acpi_ec_free(ec); return 0; } @@ -1496,13 +1532,10 @@ int __init acpi_ec_dsdt_probe(void) ret = -ENODEV; goto error; } - ret = ec_install_handlers(ec); - + ret = acpi_config_boot_ec(ec, false); error: if (ret) - kfree(ec); - else - first_ec = boot_ec = ec; + acpi_ec_free(ec); return ret; } @@ -1600,7 +1633,6 @@ int __init acpi_ec_ecdt_probe(void) goto error; } - pr_info("EC description table is found, configuring boot EC\n"); if (EC_FLAGS_CORRECT_ECDT) { ec->command_addr = ecdt_ptr->data.address; ec->data_addr = ecdt_ptr->control.address; @@ -1610,12 +1642,10 @@ int __init acpi_ec_ecdt_probe(void) } ec->gpe = ecdt_ptr->gpe; ec->handle = ACPI_ROOT_OBJECT; - ret = ec_install_handlers(ec); + ret = acpi_config_boot_ec(ec, true); error: if (ret) - kfree(ec); - else - first_ec = boot_ec = ec; + acpi_ec_free(ec); return ret; }