Received: by 2002:ac0:a581:0:0:0:0:0 with SMTP id m1-v6csp1154962imm; Tue, 3 Jul 2018 06:31:03 -0700 (PDT) X-Google-Smtp-Source: ADUXVKIlhlaGz9U040MaHAJcXFa4v8BXpiCFkuid2/vM63MbeRPvUH5pk0F3G9E4gjRYGlGviQqh X-Received: by 2002:a63:107:: with SMTP id 7-v6mr25131688pgb.289.1530624663219; Tue, 03 Jul 2018 06:31:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530624663; cv=none; d=google.com; s=arc-20160816; b=vBfQNKFkcyBfHe8LjZH0bfNcLw3OjPB+KGSL3edAKtREJY1xH474GrqwgeHRVsUwIs j3uyEptuRN1A/sCR90lar0JA92jANYyShXXmrv1dc5gy5pRDsa/cVsugGXL4V++v6q5G ZS61halCCUmBW5qhC1a+m7sKCPTFLAGIRlNqj8jQSntwx46a4LX5+lGhSumSv6FC4UR3 PyCpZ1nHCAIp47gLP/P5/ycE5a+LsLqRRkTClwFf1vGBBox2HQR5Or5i6KEx5NpYIPKd S0cYCN7cYbnqR2wA1UISUz3tcPeCIncW0rWtMfTfyy2aK3f0+yCUWPcYyKCyKrYi8a/e 1rYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=8aXPRb4GJ/Pu7ba6++wF7HGTnCYlJXAHtESVz/13WWY=; b=ZFsFA30BBw56yBL6BEJPzfjZOpEqmJ50LKZlO/Hh+JTLljQvier353E1dZM1gE+Mm1 mKNuoIjZaBvmljM2gjiYiTGMNstJpJWK4gvCUiQ629YHXlLWMl0mEKRuoxEjOVfRmo6R BJsauuUtEs0mBEhQ0pXw+rjNBylUhoBUOjyiUuBFiwqJeDIp7Q+P3mqDKpRVRM9w5y2K c1pwhSb3Kdq71uDCq3R2vdqVXZXhGkmrda+JdJzcq8zRXulCubRmFmtk4i7r6IrlpYYF k1tMtf2XuKCLZs9DpcwCFll20l16I4rTPIWLi46DTv7sjcz0p/KDaO06nwFgOr6QF8Q2 X8JQ== 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=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c192-v6si1184288pfg.347.2018.07.03.06.30.48; Tue, 03 Jul 2018 06:31:03 -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=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753473AbeGCN3k (ORCPT + 99 others); Tue, 3 Jul 2018 09:29:40 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:60454 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753307AbeGCN3j (ORCPT ); Tue, 3 Jul 2018 09:29:39 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id B5EC4263B91 From: Enric Balletbo i Serra To: linux-kernel@vger.kernel.org Cc: kernel@collabora.com, Chanwoo Choi , Kyungmin Park , MyungJoo Ham , linux-pm@vger.kernel.org Subject: [PATCH v4] PM / devfreq: Fix devfreq_add_device() when drivers are built as modules. Date: Tue, 3 Jul 2018 15:29:31 +0200 Message-Id: <20180703132931.14389-1-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.18.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When the devfreq driver and the governor driver are built as modules, the call to devfreq_add_device() or governor_store() fails because the governor driver is not loaded at the time the devfreq driver loads. The devfreq driver has a build dependency on the governor but also should have a runtime dependency. We need to make sure that the governor driver is loaded before the devfreq driver. This patch fixes this bug by adding a try_then_request_governor() function. First tries to find the governor, and then, if it is not found, it requests the module and tries again. Fixes: 1b5c1be2c88e (PM / devfreq: map devfreq drivers to governor using name) Signed-off-by: Enric Balletbo i Serra --- Changes in v4: - Kept "locked" devfreq_list from the return of find_devfreq_governor() to the unlock of governor_store(). Requested by MyungJoo Ham. Changes in v3: - Remove unneded change in dev_err message. - Fix err returned value in case to not find the governor. Changes in v2: - Add a new function to request the module and call that function from devfreq_add_device and governor_store. drivers/devfreq/devfreq.c | 53 ++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 0b5b3abe054e..4ea6b19879a1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -221,6 +222,46 @@ static struct devfreq_governor *find_devfreq_governor(const char *name) return ERR_PTR(-ENODEV); } +/** + * try_then_request_governor() - Try to find the governor and request the + * module if is not found. + * @name: name of the governor + * + * Search the list of devfreq governors and request the module and try again + * if is not found. This can happen when both drivers (the governor driver + * and the driver that call devfreq_add_device) are built as modules. + * devfreq_list_lock should be held by the caller. + * + * Return: The matched governor's pointer. + */ +static struct devfreq_governor *try_then_request_governor(const char *name) +{ + struct devfreq_governor *governor; + int err = 0; + + WARN(!mutex_is_locked(&devfreq_list_lock), + "devfreq_list_lock must be locked."); + + governor = find_devfreq_governor(name); + if (IS_ERR(governor)) { + mutex_unlock(&devfreq_list_lock); + + if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND, + DEVFREQ_NAME_LEN)) + err = request_module("governor_%s", "simpleondemand"); + else + err = request_module("governor_%s", name); + if (err) + return NULL; + + mutex_lock(&devfreq_list_lock); + + governor = find_devfreq_governor(name); + } + + return governor; +} + static int devfreq_notify_transition(struct devfreq *devfreq, struct devfreq_freqs *freqs, unsigned int state) { @@ -643,11 +684,9 @@ struct devfreq *devfreq_add_device(struct device *dev, srcu_init_notifier_head(&devfreq->transition_notifier_list); mutex_unlock(&devfreq->lock); - mutex_lock(&devfreq_list_lock); - list_add(&devfreq->node, &devfreq_list); - governor = find_devfreq_governor(devfreq->governor_name); + governor = try_then_request_governor(devfreq->governor_name); if (IS_ERR(governor)) { dev_err(dev, "%s: Unable to find governor for the device\n", __func__); @@ -663,14 +702,15 @@ struct devfreq *devfreq_add_device(struct device *dev, __func__); goto err_init; } + + list_add(&devfreq->node, &devfreq_list); + mutex_unlock(&devfreq_list_lock); return devfreq; err_init: - list_del(&devfreq->node); mutex_unlock(&devfreq_list_lock); - device_unregister(&devfreq->dev); err_dev: if (devfreq) @@ -989,7 +1029,8 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&devfreq_list_lock); - governor = find_devfreq_governor(str_governor); + + governor = try_then_request_governor(str_governor); if (IS_ERR(governor)) { ret = PTR_ERR(governor); goto out; -- 2.18.0