Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp1339042imm; Thu, 23 Aug 2018 01:06:00 -0700 (PDT) X-Google-Smtp-Source: AA+uWPwoGScN9kmEtxE2YEUpEjjvh5ITeEbvVHj6D5Rc1+qmeST1g7AeIu9b1MZi2+29Uh4UbUHL X-Received: by 2002:a17:902:864b:: with SMTP id y11-v6mr58203396plt.335.1535011560508; Thu, 23 Aug 2018 01:06:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535011560; cv=none; d=google.com; s=arc-20160816; b=v3mzAkzfg6yNweYq04c/c2GAL13h73JqxUuvzgPU11ObPuUaG4i7X8H669uCmvANo2 Cm9dYl3efMsUAlQbX8ThkSI0xX5QMFkRkqeisHJMJ9b7Gjt4ikm2lP7q3WEjO87FH2k+ KHEGJxqDmp9kZ/VAXsQPma6k6d0BvCX/tK2YNDUfNVTYF1WFxxdWJsv84oGN6u74iqQk A37z1Y6KxUlyWYOeZG+Is/JOYhZJyIFofHo9Tqz6zynZx62Z1OghMVp2GtoGQr22Uuqi QKTxPr5rkiNhprW+V9mFN6uAd0MJkAI7EijwIfytl35w7ySsT9Pe3zv+cJsr/c1bIZ95 4CwQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:to:references:message-id :content-transfer-encoding:cc:date:in-reply-to:from:subject :mime-version:arc-authentication-results; bh=tcxSPAewSyIVr+RqyXbDOL+ezmDz3zyIb9nsWOEYMWY=; b=CHgY9sXCHujptHa5eWhfsl4mZTZTuBZnmePKX5OxyT+suCdtHmrhqDyN/7bi11ihDI ZZntheSZNHeFVc/7gtcoUBXAmPVDXJLbIL0NuxvEd5pkDWLLIWjkpRFBxy66rAYEaUeg WKw5JHj1pfdUFYwSVTGqCuLFnul7kh04WOD2ypp10A5KvTcYBs5mpyYALPSYIAjM7kcP T3Dks4Oc+d4Qnpzw891tMQ/fkn5DlyrB6BGVzNx2sUilkCL92RI0JmmD/EHOKMjOkWFm 2wAjQN3G2KRkTB9lrcS9i6PSon+JTVDqMOHt+XM9e0ibKvjLhE+Hr+EpnykdnLoOAIIF 8gaw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=canonical.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o12-v6si3398125pls.94.2018.08.23.01.05.45; Thu, 23 Aug 2018 01:06:00 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=canonical.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728276AbeHWLcZ (ORCPT + 99 others); Thu, 23 Aug 2018 07:32:25 -0400 Received: from youngberry.canonical.com ([91.189.89.112]:53455 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725960AbeHWLcZ (ORCPT ); Thu, 23 Aug 2018 07:32:25 -0400 Received: from mail-pl0-f71.google.com ([209.85.160.71]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fskb0-0002Zb-JN for linux-kernel@vger.kernel.org; Thu, 23 Aug 2018 08:03:58 +0000 Received: by mail-pl0-f71.google.com with SMTP id h4-v6so2179379pls.16 for ; Thu, 23 Aug 2018 01:03:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=tcxSPAewSyIVr+RqyXbDOL+ezmDz3zyIb9nsWOEYMWY=; b=iUNluY2njlIj6p+q0zU1iitLXKe+aNB1d80VXAKuTu15H73hehTHiZRLcbPvWCzzEG u2gMn+9duSgZGpnvweGLgPn/abTwNLneNArMBCEexW5SPS8yoRWDCFvFtaLuJxNyg+qC GKdd/VY1nnCS9MtF48zBYQPM/k4U/OSxluRuWn+pQ888qOyZMbkIZ4hyv3GQTNax3RLJ Pou53eM9+kwjf+lSj7JgPp0R2qSaoxKzlTw+UrrxQwz0kCsROagNgzgd2esKW73k38Cu Bii9MUEQmn3Ww3q1Shq6M0AtKGe72r3qSImF/KADX++bgFlslZCYCL0Z9xBiMGk4R4ml teUg== X-Gm-Message-State: APzg51CLvINkEjMbs73KETcUy4wGvIB/ma8o7kK4dqvtZDIcgui96h8W 6nIZXhCLiDadtchvlO/5Y9rOd3QuR6DFIMcTa/hWfej+OKQE1EIJl2VfoC3cVYL7NuQMx3LUo1R w3e5gE66kTKpH8UCnIR2cffqJVRAdjshkZUy02t8Jbw== X-Received: by 2002:a63:c807:: with SMTP id z7-v6mr3334284pgg.77.1535011437165; Thu, 23 Aug 2018 01:03:57 -0700 (PDT) X-Received: by 2002:a63:c807:: with SMTP id z7-v6mr3334262pgg.77.1535011436852; Thu, 23 Aug 2018 01:03:56 -0700 (PDT) Received: from [192.168.1.206] (220-133-187-190.HINET-IP.hinet.net. [220.133.187.190]) by smtp.gmail.com with ESMTPSA id s85-v6sm5129081pfa.116.2018.08.23.01.03.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 23 Aug 2018 01:03:56 -0700 (PDT) Content-Type: text/plain; charset=us-ascii; delsp=yes; format=flowed Mime-Version: 1.0 (Mac OS X Mail 11.5 \(3445.9.1\)) Subject: Re: [PATCH 4/5] memstick: rtsx_usb_ms: Support runtime power management From: Kai-Heng Feng In-Reply-To: Date: Thu, 23 Aug 2018 16:03:51 +0800 Cc: Arnd Bergmann , Greg Kroah-Hartman , Alan Stern , "Bauer.Chen" , ricky_wu@realtek.com, Linux Kernel Mailing List , Linux USB List Content-Transfer-Encoding: 7bit Message-Id: References: <20180731061721.15831-1-kai.heng.feng@canonical.com> <20180731061721.15831-5-kai.heng.feng@canonical.com> To: Ulf Hansson X-Mailer: Apple Mail (2.3445.9.1) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Ulf, Sorry for the late reply. at 21:14, Ulf Hansson wrote: > On 31 July 2018 at 08:17, Kai-Heng Feng > wrote: >> In order to let host's parent device, rtsx_usb, to use USB remote wake >> up signaling to do card detection, it needs to be suspended. Hence it's >> necessary to add runtime PM support for the memstick host. >> >> To keep memstick host stays suspended when it's not in use, convert the >> card detection function from kthread to delayed_work, which can be >> scheduled when the host is resumed and can be canceled when the host is >> suspended. >> >> Use an idle function check if there's no card and the power mode is >> MEMSTICK_POWER_OFF. If both criteria are met, put the device to suspend. >> >> Signed-off-by: Kai-Heng Feng >> --- >> drivers/memstick/host/rtsx_usb_ms.c | 138 ++++++++++++++-------------- >> 1 file changed, 71 insertions(+), 67 deletions(-) >> >> diff --git a/drivers/memstick/host/rtsx_usb_ms.c >> b/drivers/memstick/host/rtsx_usb_ms.c >> index cd12f3d1c088..126eb310980a 100644 >> --- a/drivers/memstick/host/rtsx_usb_ms.c >> +++ b/drivers/memstick/host/rtsx_usb_ms.c >> @@ -40,15 +40,14 @@ struct rtsx_usb_ms { >> >> struct mutex host_mutex; >> struct work_struct handle_req; >> - >> - struct task_struct *detect_ms; >> - struct completion detect_ms_exit; >> + struct delayed_work poll_card; >> >> u8 ssc_depth; >> unsigned int clock; >> int power_mode; >> unsigned char ifmode; >> bool eject; >> + bool suspend; >> }; >> >> static inline struct device *ms_dev(struct rtsx_usb_ms *host) >> @@ -524,7 +523,7 @@ static void rtsx_usb_ms_handle_req(struct >> work_struct *work) >> int rc; >> >> if (!host->req) { >> - pm_runtime_get_sync(ms_dev(host)); >> + pm_runtime_get_noresume(ms_dev(host)); > > I don't think this is safe. > > The memstick core doesn't manage runtime PM, hence there are no > guarantee that the device is runtime resumed at this point, or is > there? No guarantees there. Right now this only gets call when the host is powered on. > >> do { >> rc = memstick_next_req(msh, &host->req); >> dev_dbg(ms_dev(host), "next req %d\n", rc); >> @@ -545,7 +544,7 @@ static void rtsx_usb_ms_handle_req(struct >> work_struct *work) >> host->req->error); >> } >> } while (!rc); >> - pm_runtime_put(ms_dev(host)); >> + pm_runtime_put_noidle(ms_dev(host)); > > According to the above, I think this should stay as is. Or perhaps you > want to use pm_runtime_put_sync() instead, as to avoid the device from > being unnecessary resumed and hence also its parent. The tricky part is that pm_runtime_put_sync() calls rtsx_usb_ms_set_param() which calls pm_runtime_* helpers again So maybe add runtime PM support to memstick core is the only way to support it properly? > >> } >> >> } >> @@ -572,7 +571,7 @@ static int rtsx_usb_ms_set_param(struct >> memstick_host *msh, >> dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n", >> __func__, param, value); >> >> - pm_runtime_get_sync(ms_dev(host)); >> + pm_runtime_get_noresume(ms_dev(host)); > > Ditto. > >> mutex_lock(&ucr->dev_mutex); >> >> err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD); >> @@ -585,14 +584,14 @@ static int rtsx_usb_ms_set_param(struct >> memstick_host *msh, >> break; >> >> if (value == MEMSTICK_POWER_ON) { >> - pm_runtime_get_sync(ms_dev(host)); >> + pm_runtime_get_noresume(ms_dev(host)); > > Ditto. > >> err = ms_power_on(host); >> + if (err) >> + pm_runtime_put_noidle(ms_dev(host)); >> } else if (value == MEMSTICK_POWER_OFF) { >> err = ms_power_off(host); >> - if (host->msh->card) >> + if (!err) >> pm_runtime_put_noidle(ms_dev(host)); >> - else >> - pm_runtime_put(ms_dev(host)); > > Ditto. > >> } else >> err = -EINVAL; >> if (!err) >> @@ -638,7 +637,7 @@ static int rtsx_usb_ms_set_param(struct >> memstick_host *msh, >> } >> out: >> mutex_unlock(&ucr->dev_mutex); >> - pm_runtime_put(ms_dev(host)); >> + pm_runtime_put_noidle(ms_dev(host)); > > Ditto. > >> /* power-on delay */ >> if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON) >> @@ -648,75 +647,86 @@ static int rtsx_usb_ms_set_param(struct >> memstick_host *msh, >> return err; >> } >> >> -#ifdef CONFIG_PM_SLEEP >> -static int rtsx_usb_ms_suspend(struct device *dev) >> +#ifdef CONFIG_PM >> +static int rtsx_usb_ms_runtime_suspend(struct device *dev) >> { >> struct rtsx_usb_ms *host = dev_get_drvdata(dev); >> struct memstick_host *msh = host->msh; >> >> - dev_dbg(ms_dev(host), "--> %s\n", __func__); >> - >> + host->suspend = true; >> memstick_suspend_host(msh); >> + >> return 0; >> } >> >> -static int rtsx_usb_ms_resume(struct device *dev) >> +static int rtsx_usb_ms_runtime_resume(struct device *dev) >> { >> struct rtsx_usb_ms *host = dev_get_drvdata(dev); >> struct memstick_host *msh = host->msh; >> >> - dev_dbg(ms_dev(host), "--> %s\n", __func__); >> - >> memstick_resume_host(msh); >> + host->suspend = false; >> + schedule_delayed_work(&host->poll_card, 100); >> + >> return 0; >> } >> -#endif /* CONFIG_PM_SLEEP */ >> >> -/* >> - * Thread function of ms card slot detection. The thread starts right >> after >> - * successful host addition. It stops while the driver removal function >> sets >> - * host->eject true. >> - */ >> -static int rtsx_usb_detect_ms_card(void *__host) >> +static int rtsx_usb_ms_runtime_idle(struct device *dev) >> +{ >> + struct rtsx_usb_ms *host = dev_get_drvdata(dev); >> + >> + if (!host->msh->card && host->power_mode == MEMSTICK_POWER_OFF) { >> + pm_schedule_suspend(dev, 0); >> + return 0; >> + } >> + >> + return -EAGAIN; >> +} >> + >> +static UNIVERSAL_DEV_PM_OPS(rtsx_usb_ms_pm_ops, >> + rtsx_usb_ms_runtime_suspend, rtsx_usb_ms_runtime_resume, >> + rtsx_usb_ms_runtime_idle); >> +#endif /* CONFIG_PM */ >> + >> +static void rtsx_usb_ms_poll_card(struct work_struct *work) >> { >> - struct rtsx_usb_ms *host = (struct rtsx_usb_ms *)__host; >> + struct rtsx_usb_ms *host = container_of(work, struct rtsx_usb_ms, >> + poll_card.work); >> struct rtsx_ucr *ucr = host->ucr; >> - u8 val = 0; >> int err; >> + u8 val; >> >> - for (;;) { >> - pm_runtime_get_sync(ms_dev(host)); >> - mutex_lock(&ucr->dev_mutex); >> + if (host->eject || host->suspend) > > The runtime PM state of the device could potentially be changed by > user space, via sysfs, as well. > > It seems like what you really should be checking is whether > host->power_mode is MEMSTICK_POWER_OFF and then act accordingly. Makes sense. > > I also think you be able to implement this without a ->runtime_idle() > callback, as it just makes this a bit unnecessary complicated. You are right. Will update it with runtime_suspend() version. > >> + return; >> >> - /* Check pending MS card changes */ >> - err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val); >> - if (err) { >> - mutex_unlock(&ucr->dev_mutex); >> - goto poll_again; >> - } >> - >> - /* Clear the pending */ >> - rtsx_usb_write_register(ucr, CARD_INT_PEND, >> - XD_INT | MS_INT | SD_INT, >> - XD_INT | MS_INT | SD_INT); >> + pm_runtime_get_noresume(ms_dev(host)); >> + mutex_lock(&ucr->dev_mutex); >> >> + /* Check pending MS card changes */ >> + err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val); >> + if (err) { >> mutex_unlock(&ucr->dev_mutex); >> + goto poll_again; >> + } >> >> - if (val & MS_INT) { >> - dev_dbg(ms_dev(host), "MS slot change >> detected\n"); >> - memstick_detect_change(host->msh); >> - } >> + /* Clear the pending */ >> + rtsx_usb_write_register(ucr, CARD_INT_PEND, >> + XD_INT | MS_INT | SD_INT, >> + XD_INT | MS_INT | SD_INT); >> >> -poll_again: >> - pm_runtime_put(ms_dev(host)); >> - if (host->eject) >> - break; >> + mutex_unlock(&ucr->dev_mutex); >> + pm_runtime_put_noidle(ms_dev(host)); >> >> - schedule_timeout_idle(HZ); >> + if (val & MS_INT) { >> + dev_dbg(ms_dev(host), "MS slot change detected\n"); >> + memstick_detect_change(host->msh); >> } >> >> - complete(&host->detect_ms_exit); >> - return 0; >> + pm_runtime_idle(ms_dev(host)); >> + >> +poll_again: >> + if (!host->eject && !host->suspend) >> + schedule_delayed_work(&host->poll_card, 100); >> } >> >> static int rtsx_usb_ms_drv_probe(struct platform_device *pdev) >> @@ -747,26 +757,21 @@ static int rtsx_usb_ms_drv_probe(struct >> platform_device *pdev) >> mutex_init(&host->host_mutex); >> INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req); >> >> - init_completion(&host->detect_ms_exit); >> - host->detect_ms = kthread_create(rtsx_usb_detect_ms_card, host, >> - "rtsx_usb_ms_%d", pdev->id); >> - if (IS_ERR(host->detect_ms)) { >> - dev_dbg(&(pdev->dev), >> - "Unable to create polling thread.\n"); >> - err = PTR_ERR(host->detect_ms); >> - goto err_out; >> - } >> + INIT_DELAYED_WORK(&host->poll_card, rtsx_usb_ms_poll_card); >> >> msh->request = rtsx_usb_ms_request; >> msh->set_param = rtsx_usb_ms_set_param; >> msh->caps = MEMSTICK_CAP_PAR4; >> >> - pm_runtime_enable(&pdev->dev); >> + pm_runtime_set_active(ms_dev(host)); >> + pm_runtime_enable(ms_dev(host)); >> + >> err = memstick_add_host(msh); >> if (err) >> goto err_out; >> >> - wake_up_process(host->detect_ms); >> + schedule_delayed_work(&host->poll_card, 100); >> + >> return 0; >> err_out: >> memstick_free_host(msh); >> @@ -782,6 +787,7 @@ static int rtsx_usb_ms_drv_remove(struct >> platform_device *pdev) >> msh = host->msh; >> host->eject = true; >> cancel_work_sync(&host->handle_req); >> + cancel_delayed_work_sync(&host->poll_card); >> >> mutex_lock(&host->host_mutex); >> if (host->req) { >> @@ -797,7 +803,6 @@ static int rtsx_usb_ms_drv_remove(struct >> platform_device *pdev) >> } >> mutex_unlock(&host->host_mutex); >> >> - wait_for_completion(&host->detect_ms_exit); >> memstick_remove_host(msh); >> memstick_free_host(msh); >> >> @@ -816,9 +821,6 @@ static int rtsx_usb_ms_drv_remove(struct >> platform_device *pdev) >> return 0; >> } >> >> -static SIMPLE_DEV_PM_OPS(rtsx_usb_ms_pm_ops, >> - rtsx_usb_ms_suspend, rtsx_usb_ms_resume); >> - >> static struct platform_device_id rtsx_usb_ms_ids[] = { >> { >> .name = "rtsx_usb_ms", >> @@ -834,7 +836,9 @@ static struct platform_driver rtsx_usb_ms_driver = { >> .id_table = rtsx_usb_ms_ids, >> .driver = { >> .name = "rtsx_usb_ms", >> +#ifdef CONFIG_PM >> .pm = &rtsx_usb_ms_pm_ops, >> +#endif >> }, >> }; >> module_platform_driver(rtsx_usb_ms_driver); >> -- >> 2.17.1 > > Kind regards > Uffe