Received: by 2002:a25:683:0:0:0:0:0 with SMTP id 125csp1271276ybg; Thu, 4 Jun 2020 05:42:42 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw2Yig8wJXekIZEmnNr+VJRdV/VRQq1RUBXK0OfURNqUPefbliPZ7xUwPMf8Q998OyBLwpK X-Received: by 2002:a05:6402:1bde:: with SMTP id ch30mr4181501edb.163.1591274562198; Thu, 04 Jun 2020 05:42:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1591274562; cv=none; d=google.com; s=arc-20160816; b=DwiSU3TcUfuazYQBRb5COZEPetDTkHZzsD0sWrwiL6R9N4eIoikb8ZXR4PGB3dZek8 Fage62ACsxepH2vmPONWInyw3ocZuIDjL6Xxp3SwnelBaTg+Bj4HOavT3vZEBBzHQuu+ iE+DzpOM+LFZxGlkJvUy5OylRIvMHQdXBKgSGh+HjCZA1WBFdELuPKnyhErKnMNdvclS rW+sHx/gMe/t06lhzhegFNSWDHOpNTeyJNUsI64aEiRjW6aGeXNYcOPpc1KC7rmdZPPF Q7gFPss1XMz6zEcYV1jOOX7KmXvHfXkD2VGPHy0/hnHpRh2ei6IUfSvVmfs8zZHwhYPa zI4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=nOT8wpxhzrsWe8nqVqTn3LV4HPvG+lPubQlfdIwx+yM=; b=tLrN7yUM7O8r+Zzm5R3txl4pNxGhNWUNwoPQH8jnFLEdHI1bsDaaaJHOGlQXOShXgg dhehX9jfgZG0RvtMQUzuZo1CoRZh7zaMIT2zHWZTVCWHtpOMXG4mHrgfbhWn/dOfc1Xg YbXifsWTAUUlVZsw4vDeIfW70E1p/I5rdPWuYlZWcge2+oKgRuSWtTmG1shfDAj1fdeh OFnWW0m/pcCUS+DBRz17NhpATV93qNH7jE+1wwT6/rRO5Rzl3j3AMB/M6/u87pxdxCOs t5UzYdUgGDjCWe8rXZ4cNJws9Dv31d88r3T83Fl1Vmu1TlARXe8WrPDKCIMCVTwmsEjy 397A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@st.com header.s=STMicroelectronics header.b=n43BdgBI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=st.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id rp11si1420085ejb.744.2020.06.04.05.42.19; Thu, 04 Jun 2020 05:42:42 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@st.com header.s=STMicroelectronics header.b=n43BdgBI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=st.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727806AbgFDMk1 (ORCPT + 99 others); Thu, 4 Jun 2020 08:40:27 -0400 Received: from mx07-00178001.pphosted.com ([62.209.51.94]:19638 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726221AbgFDMkU (ORCPT ); Thu, 4 Jun 2020 08:40:20 -0400 Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 054CWQbL014360; Thu, 4 Jun 2020 14:40:05 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=STMicroelectronics; bh=nOT8wpxhzrsWe8nqVqTn3LV4HPvG+lPubQlfdIwx+yM=; b=n43BdgBIcJQdgKwBKWge8kwF3Sko3mEozI+LjJq2rFMzB7X+d/u97bqHsSnhEevUh3+w 7kXNykjdzrzKLiEPHkG828fysN81KMQ7uLq8//YDP/7d7cZcJnd4OcNcBkBHlIvg0/b7 UjjRhSJZ301E8pebHWgdDwBt0NQPbq8+b90iFA7P3JS2wwq2zyeHTjWvGtLmi3MKrP33 47Oxl6j6EqlekwIfqF7vqhjeRbFnUXWhraloN3vjA32tg1/k97hw7/E1wAgnhGKBNMkB KYqFlBrJ/bhK5n5W6pEOmAPe7kjFJbfvJJ2a99CzjZqKXgn/OhlwklYtAWVnrd2ZDTbN xA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 31bcy0t9gm-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 04 Jun 2020 14:40:05 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 78C27100034; Thu, 4 Jun 2020 14:40:04 +0200 (CEST) Received: from Webmail-eu.st.com (sfhdag3node3.st.com [10.75.127.9]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 4EF462BE256; Thu, 4 Jun 2020 14:40:04 +0200 (CEST) Received: from localhost (10.75.127.48) by SFHDAG3NODE3.st.com (10.75.127.9) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Thu, 4 Jun 2020 14:39:36 +0200 From: Benjamin Gaignard To: , , , CC: , , , , , , , Benjamin Gaignard Subject: [PATCH v3 2/3] media: stm32-dcmi: Set minimum cpufreq requirement Date: Thu, 4 Jun 2020 14:39:31 +0200 Message-ID: <20200604123932.20512-3-benjamin.gaignard@st.com> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20200604123932.20512-1-benjamin.gaignard@st.com> References: <20200604123932.20512-1-benjamin.gaignard@st.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.75.127.48] X-ClientProxiedBy: SFHDAG2NODE1.st.com (10.75.127.4) To SFHDAG3NODE3.st.com (10.75.127.9) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.216,18.0.687 definitions=2020-06-04_10:2020-06-02,2020-06-04 signatures=0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Before start streaming set cpufreq minimum frequency requirement. The cpufreq governor will adapt the frequencies and we will have no latency for handling interrupts. The frequency requirement is retrieved from the device-tree node. While streaming be notified if the IRQ affinity change thanks to irq_affinity_notify callback. Signed-off-by: Benjamin Gaignard --- version 3: - add a cpumask field to track boosted CPUs - add irq_affinity_notify callback - protect cpumask field with a mutex drivers/media/platform/stm32/stm32-dcmi.c | 187 ++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index b8931490b83b..fb6ab09eaff0 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -13,10 +13,13 @@ #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -99,6 +102,8 @@ enum state { #define OVERRUN_ERROR_THRESHOLD 3 +static DEFINE_PER_CPU(struct freq_qos_request, qos_req); + struct dcmi_graph_entity { struct v4l2_async_subdev asd; @@ -133,6 +138,7 @@ struct stm32_dcmi { struct resource *res; struct reset_control *rstc; int sequence; + int irq; struct list_head buffers; struct dcmi_buf *active; @@ -173,6 +179,11 @@ struct stm32_dcmi { struct media_device mdev; struct media_pad vid_cap_pad; struct media_pipeline pipeline; + + u32 min_frequency; + cpumask_var_t boosted; + struct irq_affinity_notify notify; + struct mutex freq_lock; }; static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) @@ -722,6 +733,156 @@ static void dcmi_pipeline_stop(struct stm32_dcmi *dcmi) dcmi_pipeline_s_stream(dcmi, 0); } +static void dcmi_get_min_frequency(struct stm32_dcmi *dcmi) +{ + struct device_node *np = dcmi->mdev.dev->of_node; + + dcmi->min_frequency = FREQ_QOS_MIN_DEFAULT_VALUE; + + of_property_read_u32(np, "st,stm32-dcmi-min-frequency", + &dcmi->min_frequency); +} + +static void dcmi_irq_notifier_notify(struct irq_affinity_notify *notify, + const cpumask_t *mask) +{ + struct stm32_dcmi *dcmi = container_of(notify, + struct stm32_dcmi, + notify); + struct cpufreq_policy *p; + int cpu; + + mutex_lock(&dcmi->freq_lock); + /* + * For all boosted CPUs check if it is still the case + * if not remove the request + */ + for_each_cpu(cpu, dcmi->boosted) { + if (cpumask_test_cpu(cpu, mask)) + continue; + + p = cpufreq_cpu_get(cpu); + if (!p) + continue; + + freq_qos_remove_request(&per_cpu(qos_req, cpu)); + cpumask_andnot(dcmi->boosted, dcmi->boosted, p->cpus); + + cpufreq_cpu_put(p); + } + + /* + * For CPUs in the mask check if they are boosted if not add + * a request + */ + for_each_cpu(cpu, mask) { + if (cpumask_test_cpu(cpu, dcmi->boosted)) + continue; + + p = cpufreq_cpu_get(cpu); + if (!p) + continue; + + freq_qos_add_request(&p->constraints, &per_cpu(qos_req, cpu), + FREQ_QOS_MIN, dcmi->min_frequency); + cpumask_or(dcmi->boosted, dcmi->boosted, p->cpus); + cpufreq_cpu_put(p); + } + + mutex_unlock(&dcmi->freq_lock); +} + +static void dcmi_irq_notifier_release(struct kref *ref) +{ + /* + * This is required by affinity notifier. We don't have anything to + * free here. + */ +} + +static void dcmi_get_cpu_policy(struct stm32_dcmi *dcmi) +{ + struct cpufreq_policy *p; + int cpu; + + if (!alloc_cpumask_var(&dcmi->boosted, GFP_KERNEL)) + return; + + mutex_lock(&dcmi->freq_lock); + + for_each_cpu(cpu, irq_get_affinity_mask(dcmi->irq)) { + if (cpumask_test_cpu(cpu, dcmi->boosted)) + continue; + + p = cpufreq_cpu_get(cpu); + if (!p) + continue; + + freq_qos_add_request(&p->constraints, &per_cpu(qos_req, cpu), + FREQ_QOS_MIN, FREQ_QOS_MIN_DEFAULT_VALUE); + + cpumask_or(dcmi->boosted, dcmi->boosted, p->cpus); + + cpufreq_cpu_put(p); + } + + mutex_unlock(&dcmi->freq_lock); +} + +static void dcmi_put_cpu_policy(struct stm32_dcmi *dcmi) +{ + struct cpufreq_policy *p; + int cpu; + + mutex_lock(&dcmi->freq_lock); + + for_each_cpu(cpu, irq_get_affinity_mask(dcmi->irq)) { + if (!cpumask_test_cpu(cpu, dcmi->boosted)) + continue; + + p = cpufreq_cpu_get(cpu); + if (!p) + continue; + + freq_qos_remove_request(&per_cpu(qos_req, cpu)); + cpumask_andnot(dcmi->boosted, dcmi->boosted, p->cpus); + + cpufreq_cpu_put(p); + } + + free_cpumask_var(dcmi->boosted); + + mutex_unlock(&dcmi->freq_lock); +} + +static void dcmi_set_min_frequency(struct stm32_dcmi *dcmi, s32 freq) +{ + struct irq_affinity_notify *notify = &dcmi->notify; + int cpu; + + mutex_lock(&dcmi->freq_lock); + + for_each_cpu(cpu, irq_get_affinity_mask(dcmi->irq)) { + if (!cpumask_test_cpu(cpu, dcmi->boosted)) + continue; + + if (!freq_qos_request_active(&per_cpu(qos_req, cpu))) + continue; + + freq_qos_update_request(&per_cpu(qos_req, cpu), freq); + } + + mutex_unlock(&dcmi->freq_lock); + + if (freq != FREQ_QOS_MIN_DEFAULT_VALUE) { + notify->notify = dcmi_irq_notifier_notify; + notify->release = dcmi_irq_notifier_release; + irq_set_affinity_notifier(dcmi->irq, notify); + } else { + irq_set_affinity_notifier(dcmi->irq, NULL); + } +} + static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) { struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); @@ -736,11 +897,13 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_release_buffers; } + dcmi_set_min_frequency(dcmi, dcmi->min_frequency); + ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); if (ret < 0) { dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", __func__, ret); - goto err_pm_put; + goto err_drop_qos; } ret = dcmi_pipeline_start(dcmi); @@ -835,7 +998,8 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) err_media_pipeline_stop: media_pipeline_stop(&dcmi->vdev->entity); -err_pm_put: +err_drop_qos: + dcmi_set_min_frequency(dcmi, FREQ_QOS_MIN_DEFAULT_VALUE); pm_runtime_put(dcmi->dev); err_release_buffers: @@ -863,6 +1027,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) media_pipeline_stop(&dcmi->vdev->entity); + dcmi_set_min_frequency(dcmi, FREQ_QOS_MIN_DEFAULT_VALUE); + spin_lock_irq(&dcmi->irqlock); /* Disable interruptions */ @@ -1838,7 +2004,6 @@ static int dcmi_probe(struct platform_device *pdev) struct vb2_queue *q; struct dma_chan *chan; struct clk *mclk; - int irq; int ret = 0; match = of_match_device(of_match_ptr(stm32_dcmi_of_match), &pdev->dev); @@ -1879,9 +2044,9 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->bus.bus_width = ep.bus.parallel.bus_width; dcmi->bus.data_shift = ep.bus.parallel.data_shift; - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return irq ? irq : -ENXIO; + dcmi->irq = platform_get_irq(pdev, 0); + if (dcmi->irq <= 0) + return dcmi->irq ? dcmi->irq : -ENXIO; dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!dcmi->res) { @@ -1895,11 +2060,12 @@ static int dcmi_probe(struct platform_device *pdev) return PTR_ERR(dcmi->regs); } - ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback, + ret = devm_request_threaded_irq(&pdev->dev, dcmi->irq, + dcmi_irq_callback, dcmi_irq_thread, IRQF_ONESHOT, dev_name(&pdev->dev), dcmi); if (ret) { - dev_err(&pdev->dev, "Unable to request irq %d\n", irq); + dev_err(&pdev->dev, "Unable to request irq %d\n", dcmi->irq); return ret; } @@ -2022,6 +2188,9 @@ static int dcmi_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Probe done\n"); + dcmi_get_min_frequency(dcmi); + dcmi_get_cpu_policy(dcmi); + platform_set_drvdata(pdev, dcmi); pm_runtime_enable(&pdev->dev); @@ -2049,6 +2218,8 @@ static int dcmi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); + dcmi_put_cpu_policy(dcmi); + v4l2_async_notifier_unregister(&dcmi->notifier); v4l2_async_notifier_cleanup(&dcmi->notifier); media_entity_cleanup(&dcmi->vdev->entity); -- 2.15.0