From patchwork Mon Sep 23 23:17:46 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 20540 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qa0-f70.google.com (mail-qa0-f70.google.com [209.85.216.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 91DB2246ED for ; Mon, 23 Sep 2013 23:18:05 +0000 (UTC) Received: by mail-qa0-f70.google.com with SMTP id i13sf3078015qae.5 for ; Mon, 23 Sep 2013 16:18:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe :content-transfer-encoding; bh=n611+Qe4/7AYX0ukmZUxzLSev6eaKXw3wXDXDUZlNR0=; b=FHceWTO/0Tc5Gwg/QLRobtkSfStb4Xt8lhuqmNHAOLxiR3Xl7COdUIfm9JL5dxZZNX ZVcWxOjKIV8hdmvYYbfZ5+4Pj53P/zWdEeQVfFACOWpTHtK9PQBF8oQnTuGK4LaxmPRV YXFPnnLyFUhmLFwT28LSAPfQGYL0gu6HNfGl3ie22yuDscKhxYGCtFgjQjAdSRargQ5d M9Ehuvqps/neocuqXNb9wREdTW/xokWHwdLu1oZ0bXZTvpuh9i5SKoG32FTg0XbSmBH9 6CCIAuT1p9PO0WoaP8w4ZCgo2GD+G6xvjNGtaEaxtiT2iquHF025Ia5CXrknlq2m22Rf 0JuQ== X-Gm-Message-State: ALoCoQmKy9EmlKbgSIRZ9YhWGA9z1KDFmTvL4zDdOX6MKma8eLXoIwHYkbyAjFzW+2geDEIr5Z8p X-Received: by 10.236.45.102 with SMTP id o66mr7533300yhb.47.1379978285450; Mon, 23 Sep 2013 16:18:05 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.99.72 with SMTP id eo8ls1436954qeb.41.gmail; Mon, 23 Sep 2013 16:18:05 -0700 (PDT) X-Received: by 10.220.186.202 with SMTP id ct10mr24906564vcb.14.1379978285309; Mon, 23 Sep 2013 16:18:05 -0700 (PDT) Received: from mail-ve0-f178.google.com (mail-ve0-f178.google.com [209.85.128.178]) by mx.google.com with ESMTPS id t10si3206942vcr.35.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 23 Sep 2013 16:18:05 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.178 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.178; Received: by mail-ve0-f178.google.com with SMTP id jw12so2899992veb.37 for ; Mon, 23 Sep 2013 16:18:05 -0700 (PDT) X-Received: by 10.58.118.130 with SMTP id km2mr24225586veb.0.1379978285199; Mon, 23 Sep 2013 16:18:05 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp208741vcz; Mon, 23 Sep 2013 16:18:04 -0700 (PDT) X-Received: by 10.224.22.75 with SMTP id m11mr26442630qab.27.1379978282662; Mon, 23 Sep 2013 16:18:02 -0700 (PDT) Received: from relais.videotron.ca (relais.videotron.ca. [24.201.245.36]) by mx.google.com with ESMTP id k4si13385945qas.62.1969.12.31.16.00.00; Mon, 23 Sep 2013 16:18:02 -0700 (PDT) Received-SPF: neutral (google.com: 24.201.245.36 is neither permitted nor denied by best guess record for domain of nicolas.pitre@linaro.org) client-ip=24.201.245.36; Received: from yoda.home ([70.83.209.44]) by VL-VM-MR005.ip.videotron.ca (Oracle Communications Messaging Exchange Server 7u4-22.01 64bit (built Apr 21 2011)) with ESMTP id <0MTL003B5Q21N190@VL-VM-MR005.ip.videotron.ca> for patches@linaro.org; Mon, 23 Sep 2013 19:18:01 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 39D652DA0668; Mon, 23 Sep 2013 19:18:01 -0400 (EDT) From: Nicolas Pitre To: linux-arm-kernel@lists.infradead.org Cc: dave.martin@arm.com, linaro-kernel@lists.linaro.org, patches@linaro.org Subject: [PATCH 03/13] ARM: bL_switcher: Add switch completion callback for bL_switch_request() Date: Mon, 23 Sep 2013 19:17:46 -0400 Message-id: <1379978276-31241-4-git-send-email-nicolas.pitre@linaro.org> X-Mailer: git-send-email 1.8.4.98.gb022869 In-reply-to: <1379978276-31241-1-git-send-email-nicolas.pitre@linaro.org> References: <1379978276-31241-1-git-send-email-nicolas.pitre@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: nicolas.pitre@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.178 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Content-transfer-encoding: 7BIT From: Dave Martin There is no explicit way to know when a switch started via bL_switch_request() is complete. This can lead to unpredictable behaviour when the switcher is controlled by a subsystem which makes dynamic decisions (such as cpufreq). The CPU PM notifier is not really suitable for signalling completion, because the CPU could get suspended and resumed for other, independent reasons while a switch request is in flight. Adding a whole new notifier for this seems excessive, and may tempt people to put heavyweight code on this path. This patch implements a new bL_switch_request_cb() function that allows for a per-request lightweight callback, private between the switcher and the caller of bL_switch_request_cb(). Overlapping switches on a single CPU are considered incorrect if they are requested via bL_switch_request_cb() with a callback (they will lead to an unpredictable final state without explicit external synchronisation to force the requests into a particular order). Queuing requests robustly would be overkill because only one subsystem should be attempting to control the switcher at any time. Overlapping requests of this kind will be failed with -EBUSY to indicate that the second request won't take effect and the completer will never be called for it. bL_switch_request() is retained as a wrapper round the new function, with the old, fire-and-forget semantics. In this case the last request will always win. The request may still be denied if a previous request with a completer is still pending. Signed-off-by: Dave Martin Signed-off-by: Nicolas Pitre --- arch/arm/common/bL_switcher.c | 53 ++++++++++++++++++++++++++++++++++---- arch/arm/include/asm/bL_switcher.h | 10 ++++++- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/arch/arm/common/bL_switcher.c b/arch/arm/common/bL_switcher.c index 016488730c..34316be404 100644 --- a/arch/arm/common/bL_switcher.c +++ b/arch/arm/common/bL_switcher.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -224,10 +226,13 @@ static int bL_switch_to(unsigned int new_cluster_id) } struct bL_thread { + spinlock_t lock; struct task_struct *task; wait_queue_head_t wq; int wanted_cluster; struct completion started; + bL_switch_completion_handler completer; + void *completer_cookie; }; static struct bL_thread bL_threads[NR_CPUS]; @@ -237,6 +242,8 @@ static int bL_switcher_thread(void *arg) struct bL_thread *t = arg; struct sched_param param = { .sched_priority = 1 }; int cluster; + bL_switch_completion_handler completer; + void *completer_cookie; sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); complete(&t->started); @@ -247,9 +254,21 @@ static int bL_switcher_thread(void *arg) wait_event_interruptible(t->wq, t->wanted_cluster != -1 || kthread_should_stop()); - cluster = xchg(&t->wanted_cluster, -1); - if (cluster != -1) + + spin_lock(&t->lock); + cluster = t->wanted_cluster; + completer = t->completer; + completer_cookie = t->completer_cookie; + t->wanted_cluster = -1; + t->completer = NULL; + spin_unlock(&t->lock); + + if (cluster != -1) { bL_switch_to(cluster); + + if (completer) + completer(completer_cookie); + } } while (!kthread_should_stop()); return 0; @@ -270,16 +289,30 @@ static struct task_struct *bL_switcher_thread_create(int cpu, void *arg) } /* - * bL_switch_request - Switch to a specific cluster for the given CPU + * bL_switch_request_cb - Switch to a specific cluster for the given CPU, + * with completion notification via a callback * * @cpu: the CPU to switch * @new_cluster_id: the ID of the cluster to switch to. + * @completer: switch completion callback. if non-NULL, + * @completer(@completer_cookie) will be called on completion of + * the switch, in non-atomic context. + * @completer_cookie: opaque context argument for @completer. * * This function causes a cluster switch on the given CPU by waking up * the appropriate switcher thread. This function may or may not return * before the switch has occurred. + * + * If a @completer callback function is supplied, it will be called when + * the switch is complete. This can be used to determine asynchronously + * when the switch is complete, regardless of when bL_switch_request() + * returns. When @completer is supplied, no new switch request is permitted + * for the affected CPU until after the switch is complete, and @completer + * has returned. */ -int bL_switch_request(unsigned int cpu, unsigned int new_cluster_id) +int bL_switch_request_cb(unsigned int cpu, unsigned int new_cluster_id, + bL_switch_completion_handler completer, + void *completer_cookie) { struct bL_thread *t; @@ -289,16 +322,25 @@ int bL_switch_request(unsigned int cpu, unsigned int new_cluster_id) } t = &bL_threads[cpu]; + if (IS_ERR(t->task)) return PTR_ERR(t->task); if (!t->task) return -ESRCH; + spin_lock(&t->lock); + if (t->completer) { + spin_unlock(&t->lock); + return -EBUSY; + } + t->completer = completer; + t->completer_cookie = completer_cookie; t->wanted_cluster = new_cluster_id; + spin_unlock(&t->lock); wake_up(&t->wq); return 0; } -EXPORT_SYMBOL_GPL(bL_switch_request); +EXPORT_SYMBOL_GPL(bL_switch_request_cb); /* * Activation and configuration code. @@ -460,6 +502,7 @@ static int bL_switcher_enable(void) for_each_online_cpu(cpu) { struct bL_thread *t = &bL_threads[cpu]; + spin_lock_init(&t->lock); init_waitqueue_head(&t->wq); init_completion(&t->started); t->wanted_cluster = -1; diff --git a/arch/arm/include/asm/bL_switcher.h b/arch/arm/include/asm/bL_switcher.h index b243ca93e8..7d1cce8b8a 100644 --- a/arch/arm/include/asm/bL_switcher.h +++ b/arch/arm/include/asm/bL_switcher.h @@ -15,7 +15,15 @@ #include #include -int bL_switch_request(unsigned int cpu, unsigned int new_cluster_id); +typedef void (*bL_switch_completion_handler)(void *cookie); + +int bL_switch_request_cb(unsigned int cpu, unsigned int new_cluster_id, + bL_switch_completion_handler completer, + void *completer_cookie); +static inline int bL_switch_request(unsigned int cpu, unsigned int new_cluster_id) +{ + return bL_switch_request_cb(cpu, new_cluster_id, NULL, NULL); +} /* * Register here to be notified about runtime enabling/disabling of