Received: by 2002:a05:6358:489b:b0:bb:da1:e618 with SMTP id x27csp229719rwn; Wed, 7 Sep 2022 15:41:25 -0700 (PDT) X-Google-Smtp-Source: AA6agR4rjvNpNt5Pbr+hFXz6rjXtyvKT+K+wkfMoYNICXe13xt+CbsaL/bwsj9uoDkPhy/zICyXu X-Received: by 2002:a05:6402:4312:b0:448:6db8:9d8f with SMTP id m18-20020a056402431200b004486db89d8fmr4599678edc.272.1662590485612; Wed, 07 Sep 2022 15:41:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1662590485; cv=none; d=google.com; s=arc-20160816; b=WQagG5nunmRTEfTfoWDSZSg0+X2bNyb4i2tw2A7odSAL9tzTO7Rp48dV2PFO1TNrA9 +7lwV7j7GGwRl1rrEWn2LeU/Bx51RnCf/D1bJTRkeRa06d8ibL0hxPM/zK6ljWKFSV5C 5eynwm5a7VFcwaGV7PIkaNVSf6BZhM/iRL+qzqYvgEeyDaSpcJLb5IBxmq46t48xw3zU Xk4XvE7pQ57iMLllD7g32DWjrhWOgPJdbh84mb44bb1klAErJt0Ju0GR8oZoMPBel33G ZiwnnSHsEWZfmIILH/n8ckVeKACJpCp1w1f8f548g04vEi8OHNWaKCqywte3jYZPdWhJ NSBA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=bvSC3/Vli6WdvkgSlY+Xks/AtEikIzuD8y+i7AbUTdE=; b=eikQa0x1PR6sI4Iu274FLX/KwgqysAfvIWAznu/WCmuLEUaRkGMsuk6bSo6m0w1csp kzxP9J9YKiNCRpyJVmh4z+gA5O/l/pOh9Qck1MgyenqlmuFP/7lXmcu6wfue/Qwv2ZEV hPuDem1lf8BgrrOmDJiXMRxSTwQEhw2qSvJrZdDpE5faGBk0n6vll/TDRVd4uSS+Dy7y ZCHmI1mYI7APi2MKLjjLb08oJOUbqjbJ4V5WkWyTFQyJlcBK1pqZir+IVTmfNbF/JTV5 WAJ29QqpEqxR6D405cMq5jgL5mwLRhyXhLKWSOCQmEtZNbD798si9BHGFtXkIo1vcsi0 Huiw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=PntKpQDo; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id sa39-20020a1709076d2700b00741827c60c4si532054ejc.900.2022.09.07.15.41.01; Wed, 07 Sep 2022 15:41:25 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=PntKpQDo; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230408AbiIGVwI (ORCPT + 99 others); Wed, 7 Sep 2022 17:52:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230370AbiIGVv7 (ORCPT ); Wed, 7 Sep 2022 17:51:59 -0400 Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D18042C64B for ; Wed, 7 Sep 2022 14:51:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1662587517; x=1694123517; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=E4BDJWRngPMS6N93vl9Ek5HBey+FwHqzMSQ0kh5WK+c=; b=PntKpQDojN/qpWHqh+dGidgkdFlM5l1N8U+CK10cweAXUDtl8u25UWVy 8SG5SLCc5znDsUp1Yx5vxI021SHFZf27LEtxX5zcGqvF5NsUGfzZ6FAqP VFjCARgIrWeOtgNeIRQMT7iR96CR9P5ODlHp6tLqdU+vy19AElKm7oMQS lyWNCIKMFChbiYWw+K6N1ME2/PXMlXRwcmibZN1lJMo85JYPQeyYBHpRx 3fc2QWDTYxYw9XlUGIeYk2mAHw7lv//ualN1Dzxeu3h+2MsulwQ5UavHe hh6u6+Kq3tqP9BxSVudkx86T+wrl2opDrwSPjQnuFE+1Xc+m+/aRREhg3 g==; X-IronPort-AV: E=McAfee;i="6500,9779,10463"; a="295740300" X-IronPort-AV: E=Sophos;i="5.93,298,1654585200"; d="scan'208";a="295740300" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2022 14:51:54 -0700 X-IronPort-AV: E=Sophos;i="5.93,298,1654585200"; d="scan'208";a="790207898" Received: from twinkler-lnx.jer.intel.com ([10.12.87.143]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2022 14:51:50 -0700 From: Tomas Winkler To: Greg Kroah-Hartman , David Airlie , Daniel Vetter Cc: Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , Tvrtko Ursulin , intel-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org, Tomas Winkler , Alexander Usyskin , Vitaly Lubart , James Ausmus , Daniele Ceraolo Spurio Subject: [PATCH v9 06/16] mei: gsc: use polling instead of interrupts Date: Thu, 8 Sep 2022 00:51:03 +0300 Message-Id: <20220907215113.1596567-7-tomas.winkler@intel.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20220907215113.1596567-1-tomas.winkler@intel.com> References: <20220907215113.1596567-1-tomas.winkler@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org A work-around for a HW issue in XEHPSDV that manifests itself when SW reads a gsc register when gsc is sending an interrupt. The work-around is to disable interrupts and to use polling instead. Cc: James Ausmus Signed-off-by: Vitaly Lubart Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Reviewed-by: Daniele Ceraolo Spurio --- V8: Add kdoc and comments to mei_me_polling_thread() V9: Rebase drivers/misc/mei/gsc-me.c | 48 ++++++++++++++++++----- drivers/misc/mei/hw-me.c | 80 ++++++++++++++++++++++++++++++++++++--- drivers/misc/mei/hw-me.h | 15 +++++++- 3 files changed, 128 insertions(+), 15 deletions(-) diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c index c8145e9b62b6..2caba3a9ac35 100644 --- a/drivers/misc/mei/gsc-me.c +++ b/drivers/misc/mei/gsc-me.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "mei_dev.h" #include "hw-me.h" @@ -66,13 +67,28 @@ static int mei_gsc_probe(struct auxiliary_device *aux_dev, dev_set_drvdata(device, dev); - ret = devm_request_threaded_irq(device, hw->irq, - mei_me_irq_quick_handler, - mei_me_irq_thread_handler, - IRQF_ONESHOT, KBUILD_MODNAME, dev); - if (ret) { - dev_err(device, "irq register failed %d\n", ret); - goto err; + /* use polling */ + if (mei_me_hw_use_polling(hw)) { + mei_disable_interrupts(dev); + mei_clear_interrupts(dev); + init_waitqueue_head(&hw->wait_active); + hw->is_active = true; /* start in active mode for initialization */ + hw->polling_thread = kthread_run(mei_me_polling_thread, dev, + "kmegscirqd/%s", dev_name(device)); + if (IS_ERR(hw->polling_thread)) { + ret = PTR_ERR(hw->polling_thread); + dev_err(device, "unable to create kernel thread: %d\n", ret); + goto err; + } + } else { + ret = devm_request_threaded_irq(device, hw->irq, + mei_me_irq_quick_handler, + mei_me_irq_thread_handler, + IRQF_ONESHOT, KBUILD_MODNAME, dev); + if (ret) { + dev_err(device, "irq register failed %d\n", ret); + goto err; + } } pm_runtime_get_noresume(device); @@ -98,7 +114,8 @@ static int mei_gsc_probe(struct auxiliary_device *aux_dev, register_err: mei_stop(dev); - devm_free_irq(device, hw->irq, dev); + if (!mei_me_hw_use_polling(hw)) + devm_free_irq(device, hw->irq, dev); err: dev_err(device, "probe failed: %d\n", ret); @@ -119,12 +136,17 @@ static void mei_gsc_remove(struct auxiliary_device *aux_dev) mei_stop(dev); + hw = to_me_hw(dev); + if (mei_me_hw_use_polling(hw)) + kthread_stop(hw->polling_thread); + mei_deregister(dev); pm_runtime_disable(&aux_dev->dev); mei_disable_interrupts(dev); - devm_free_irq(&aux_dev->dev, hw->irq, dev); + if (!mei_me_hw_use_polling(hw)) + devm_free_irq(&aux_dev->dev, hw->irq, dev); } static int __maybe_unused mei_gsc_pm_suspend(struct device *device) @@ -185,6 +207,9 @@ static int __maybe_unused mei_gsc_pm_runtime_suspend(struct device *device) if (mei_write_is_idle(dev)) { hw = to_me_hw(dev); hw->pg_state = MEI_PG_ON; + + if (mei_me_hw_use_polling(hw)) + hw->is_active = false; ret = 0; } else { ret = -EAGAIN; @@ -209,6 +234,11 @@ static int __maybe_unused mei_gsc_pm_runtime_resume(struct device *device) hw = to_me_hw(dev); hw->pg_state = MEI_PG_OFF; + if (mei_me_hw_use_polling(hw)) { + hw->is_active = true; + wake_up(&hw->wait_active); + } + mutex_unlock(&dev->device_lock); irq_ret = mei_me_irq_thread_handler(1, dev); diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 3a95fe7d4e33..23ad53efbcb7 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2003-2020, Intel Corporation. All rights reserved. + * Copyright (c) 2003-2022, Intel Corporation. All rights reserved. * Intel Management Engine Interface (Intel MEI) Linux driver */ @@ -10,6 +10,7 @@ #include #include #include +#include #include "mei_dev.h" #include "hbm.h" @@ -327,9 +328,12 @@ static void mei_me_intr_clear(struct mei_device *dev) */ static void mei_me_intr_enable(struct mei_device *dev) { - u32 hcsr = mei_hcsr_read(dev); + u32 hcsr; + + if (mei_me_hw_use_polling(to_me_hw(dev))) + return; - hcsr |= H_CSR_IE_MASK; + hcsr = mei_hcsr_read(dev) | H_CSR_IE_MASK; mei_hcsr_set(dev, hcsr); } @@ -354,6 +358,9 @@ static void mei_me_synchronize_irq(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); + if (mei_me_hw_use_polling(hw)) + return; + synchronize_irq(hw->irq); } @@ -380,7 +387,10 @@ static void mei_me_host_set_ready(struct mei_device *dev) { u32 hcsr = mei_hcsr_read(dev); - hcsr |= H_CSR_IE_MASK | H_IG | H_RDY; + if (!mei_me_hw_use_polling(to_me_hw(dev))) + hcsr |= H_CSR_IE_MASK; + + hcsr |= H_IG | H_RDY; mei_hcsr_set(dev, hcsr); } @@ -1176,7 +1186,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) hcsr |= H_RST | H_IG | H_CSR_IS_MASK; - if (!intr_enable) + if (!intr_enable || mei_me_hw_use_polling(to_me_hw(dev))) hcsr &= ~H_CSR_IE_MASK; dev->recvd_hw_ready = false; @@ -1331,6 +1341,66 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) } EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler); +#define MEI_POLLING_TIMEOUT_ACTIVE 100 +#define MEI_POLLING_TIMEOUT_IDLE 500 + +/** + * mei_me_polling_thread - interrupt register polling thread + * + * The thread monitors the interrupt source register and calls + * mei_me_irq_thread_handler() to handle the firmware + * input. + * + * The function polls in MEI_POLLING_TIMEOUT_ACTIVE timeout + * in case there was an event, in idle case the polling + * time increases yet again by MEI_POLLING_TIMEOUT_ACTIVE + * up to MEI_POLLING_TIMEOUT_IDLE. + * + * @_dev: mei device + * + * Return: always 0 + */ +int mei_me_polling_thread(void *_dev) +{ + struct mei_device *dev = _dev; + irqreturn_t irq_ret; + long polling_timeout = MEI_POLLING_TIMEOUT_ACTIVE; + + dev_dbg(dev->dev, "kernel thread is running\n"); + while (!kthread_should_stop()) { + struct mei_me_hw *hw = to_me_hw(dev); + u32 hcsr; + + wait_event_timeout(hw->wait_active, + hw->is_active || kthread_should_stop(), + msecs_to_jiffies(MEI_POLLING_TIMEOUT_IDLE)); + + if (kthread_should_stop()) + break; + + hcsr = mei_hcsr_read(dev); + if (me_intr_src(hcsr)) { + polling_timeout = MEI_POLLING_TIMEOUT_ACTIVE; + irq_ret = mei_me_irq_thread_handler(1, dev); + if (irq_ret != IRQ_HANDLED) + dev_err(dev->dev, "irq_ret %d\n", irq_ret); + } else { + /* + * Increase timeout by MEI_POLLING_TIMEOUT_ACTIVE + * up to MEI_POLLING_TIMEOUT_IDLE + */ + polling_timeout = clamp_val(polling_timeout + MEI_POLLING_TIMEOUT_ACTIVE, + MEI_POLLING_TIMEOUT_ACTIVE, + MEI_POLLING_TIMEOUT_IDLE); + } + + schedule_timeout_interruptible(msecs_to_jiffies(polling_timeout)); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mei_me_polling_thread); + static const struct mei_hw_ops mei_me_hw_ops = { .trc_status = mei_me_trc_status, diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index a071c645e905..6256b36bdafd 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2012-2020, Intel Corporation. All rights reserved. + * Copyright (c) 2012-2022, Intel Corporation. All rights reserved. * Intel Management Engine Interface (Intel MEI) Linux driver */ @@ -51,6 +51,9 @@ struct mei_cfg { * @d0i3_supported: di03 support * @hbuf_depth: depth of hardware host/write buffer in slots * @read_fws: read FW status register handler + * @polling_thread: interrupt polling thread + * @wait_active: the polling thread activity wait queue + * @is_active: the device is active */ struct mei_me_hw { const struct mei_cfg *cfg; @@ -60,10 +63,19 @@ struct mei_me_hw { bool d0i3_supported; u8 hbuf_depth; int (*read_fws)(const struct mei_device *dev, int where, u32 *val); + /* polling */ + struct task_struct *polling_thread; + wait_queue_head_t wait_active; + bool is_active; }; #define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) +static inline bool mei_me_hw_use_polling(const struct mei_me_hw *hw) +{ + return hw->irq < 0; +} + /** * enum mei_cfg_idx - indices to platform specific configurations. * @@ -127,5 +139,6 @@ int mei_me_pg_exit_sync(struct mei_device *dev); irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id); irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id); +int mei_me_polling_thread(void *_dev); #endif /* _MEI_INTERFACE_H_ */ -- 2.37.2