From patchwork Wed Aug 27 20:14:39 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lina Iyer X-Patchwork-Id: 4790781 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 8D3BB9F2A9 for ; Wed, 27 Aug 2014 20:18:44 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 87D6420142 for ; Wed, 27 Aug 2014 20:18:43 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7FE792012E for ; Wed, 27 Aug 2014 20:18:42 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XMje6-0005mX-5C; Wed, 27 Aug 2014 20:16:42 +0000 Received: from mail-pa0-f49.google.com ([209.85.220.49]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XMjdY-00053c-26 for linux-arm-kernel@lists.infradead.org; Wed, 27 Aug 2014 20:16:08 +0000 Received: by mail-pa0-f49.google.com with SMTP id hz1so1189233pad.22 for ; Wed, 27 Aug 2014 13:15:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=kMKYTvv86pDnqHUkT0OYume1QMBdL75VTYNnR/ylv/0=; b=EfhjtKLxgyKwoOAz4H2fwrXqsvR2Zv9npG533/J6EfboRHp36g/zEh+Q2fdVfRFiP7 rCrVKapM0fKLfbxF3GZkb7rimODIRtbCFZiofztw2FEBlFvvfk1VWZTi5VvJVP38PC8h DHW4fYlGnBviyo/vqB80ANDcDV5lXYQ5D5vUihrOQavTf1LsOrjONd62PPXhu4ow9WzO qNwJewuoTgSge/8arn3uiwfF+83j89u0namlFIFXPjzN0PCT5+9/IjiXf/Y/+dgRdHhx L874CAM1oHgdzrfPsS5gieh9G9WDUhG3KbLV+58KMf2xTHp6Imi/XV/x4XGGRONa9Hkl CRZw== X-Gm-Message-State: ALoCoQlsqn9DdTSGxE+fidLNwxQF0ej1Zjv51VpsKo6yPqiIvZN1tGi/Lx/MvTFqZCSO7KL7LS17 X-Received: by 10.70.10.100 with SMTP id h4mr25409722pdb.162.1409170546792; Wed, 27 Aug 2014 13:15:46 -0700 (PDT) Received: from ubuntu.localdomain (70-59-28-129.hlrn.qwest.net. [70.59.28.129]) by mx.google.com with ESMTPSA id ol8sm1868447pdb.82.2014.08.27.13.15.44 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 27 Aug 2014 13:15:46 -0700 (PDT) From: Lina Iyer To: khilman@linaro.org, ulf.hansson@linaro.org, linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, tglx@linutronix.de, rjw@rjwysocki.net Subject: [PATCH v3 4/4] QoS: Enable PM QoS requests to apply only on smp_affinity of an IRQ Date: Wed, 27 Aug 2014 14:14:39 -0600 Message-Id: <1409170479-29955-5-git-send-email-lina.iyer@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1409170479-29955-1-git-send-email-lina.iyer@linaro.org> References: <1409170479-29955-1-git-send-email-lina.iyer@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140827_131608_166171_415FA017 X-CRM114-Status: GOOD ( 16.81 ) X-Spam-Score: -0.7 (/) Cc: Praveen Chidambaram , daniel.lezcano@linaro.org, Lina Iyer X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Based on original work by pchidamb@codeaurora.org. QoS requests that need to track an IRQ can be set to apply only on the cpus to which the IRQ's smp_affinity attribute is set to. The PM QoS framework will automatically track IRQ migration between the cores. The QoS is updated to be applied only to the core(s) that the IRQ has been migrated to. The userspace sysfs interface does not support IRQ affinity. Signed-off-by: Praveen Chidambaram Signed-off-by: Lina Iyer [lina.iyer: Split the change from a previous change, add commit text] diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt index c129517..32b864d 100644 --- a/Documentation/power/pm_qos_interface.txt +++ b/Documentation/power/pm_qos_interface.txt @@ -47,8 +47,10 @@ applies to all cores. However, the driver can also specify a request type to be either of PM_QOS_REQ_ALL_CORES, PM_QOS_REQ_AFFINE_CORES, + PM_QOS_REQ_AFFINE_IRQ, -Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES. +Specify the cpumask when type is set to PM_QOS_REQ_AFFINE_CORES and specify +the IRQ number with PM_QOS_REQ_AFFINE_IRQ. void pm_qos_update_request(handle, new_target_value): Will update the list element pointed to by the handle with the new target value diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index a3aa5b5..68b16b8 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -11,6 +11,7 @@ #include #include #include +#include enum { PM_QOS_RESERVED = 0, @@ -45,12 +46,16 @@ enum pm_qos_flags_status { enum pm_qos_req_type { PM_QOS_REQ_ALL_CORES = 0, PM_QOS_REQ_AFFINE_CORES, + PM_QOS_REQ_AFFINE_IRQ, }; struct pm_qos_request { enum pm_qos_req_type type; struct cpumask cpus_affine; + uint32_t irq; /* Internal structure members */ + struct irq_affinity_notify irq_notify; + struct completion irq_released; struct plist_node node; int pm_qos_class; struct delayed_work work; /* for pm_qos_update_request_timeout */ diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 27f84a2..c10e8bc 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -41,6 +41,9 @@ #include #include #include +#include +#include +#include #include #include @@ -412,6 +415,37 @@ static void pm_qos_work_fn(struct work_struct *work) __pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE); } +static void pm_qos_irq_release(struct kref *ref) +{ + unsigned long flags; + struct irq_affinity_notify *notify = container_of(ref, + struct irq_affinity_notify, kref); + struct pm_qos_request *req = container_of(notify, + struct pm_qos_request, irq_notify); + + spin_lock_irqsave(&pm_qos_lock, flags); + cpumask_clear(&req->cpus_affine); + spin_unlock_irqrestore(&pm_qos_lock, flags); + + complete(&req->irq_released); +} + +static void pm_qos_irq_notify(struct irq_affinity_notify *notify, + const cpumask_t *mask) +{ + unsigned long flags; + struct pm_qos_request *req = container_of(notify, + struct pm_qos_request, irq_notify); + struct pm_qos_constraints *c = + pm_qos_array[req->pm_qos_class]->constraints; + + spin_lock_irqsave(&pm_qos_lock, flags); + cpumask_copy(&req->cpus_affine, mask); + spin_unlock_irqrestore(&pm_qos_lock, flags); + + pm_qos_update_target(c, req, PM_QOS_UPDATE_REQ, req->node.prio); +} + /** * pm_qos_add_request - inserts new qos request into the list * @req: pointer to a preallocated handle @@ -445,6 +479,34 @@ void pm_qos_add_request(struct pm_qos_request *req, } break; + case PM_QOS_REQ_AFFINE_IRQ: + if (irq_can_set_affinity(req->irq)) { + int ret = 0; + struct irq_desc *desc = irq_to_desc(req->irq); + struct cpumask *mask = desc->irq_data.affinity; + + /* Get the current affinity */ + cpumask_copy(&req->cpus_affine, mask); + req->irq_notify.irq = req->irq; + req->irq_notify.notify = pm_qos_irq_notify; + req->irq_notify.release = pm_qos_irq_release; + + ret = irq_set_affinity_notifier(req->irq, + &req->irq_notify); + if (ret) { + WARN(1, KERN_ERR "IRQ affinity notify set failed\n"); + req->type = PM_QOS_REQ_ALL_CORES; + cpumask_setall(&req->cpus_affine); + } + } else { + req->type = PM_QOS_REQ_ALL_CORES; + cpumask_setall(&req->cpus_affine); + WARN(1, KERN_ERR "IRQ-%d not set for request with affinity flag\n", + req->irq); + } + init_completion(&req->irq_released); + break; + default: WARN(1, KERN_ERR "Unknown request type %d\n", req->type); /* fall through */ @@ -526,11 +588,14 @@ void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value, */ void pm_qos_remove_request(struct pm_qos_request *req) { - if (!req) /*guard against callers passing in null */ return; /* silent return to keep pcm code cleaner */ + /* Remove ourselves from the irq notification */ + if (req->type == PM_QOS_REQ_AFFINE_IRQ) + irq_release_affinity_notifier(&req->irq_notify); + if (!pm_qos_request_active(req)) { WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n"); return; @@ -543,6 +608,16 @@ void pm_qos_remove_request(struct pm_qos_request *req) req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); + /** + * The 'release' callback of the notifier would not be called unless + * there are no active users of the irq_notify object, i.e, kref count + * is non-zero. This could happen if there is an active 'notify' + * callback happening while the pm_qos_remove request is called. Wait + * until the release callback clears the cpus_affine mask. + */ + if (req->type == PM_QOS_REQ_AFFINE_IRQ) + wait_for_completion(&req->irq_released); + memset(req, 0, sizeof(*req)); } EXPORT_SYMBOL_GPL(pm_qos_remove_request);