[PATCH v3 0/3]Re:Re:Re:[PATCH v2] Added perf functionality to mmdc driver

STALE3693d

4 messages, 1 author, 2016-08-19 · open the first message on its own page

[PATCH v3 0/3]Re:Re:Re:[PATCH v2] Added perf functionality to mmdc driver

From: Nitin Chaudhary <hidden>
Date: 2016-08-19 01:17:36

The following series of patch resolve the kernel compilation errors with the
proposed perf functionality integration into MMDC driver by Zhengyu Shen and
hence provide the working code which can be enhanced upon as per the reviews
from Mark Rutland and Peter Zilstra. The code still retains the original working
as was proposed by Zhengyu except a few minor changes to resolve probe failure
in the latest version of kernel. These patchsets are second version of patches
incorporating the inputs from Zhengyu. The below is description:
 v2 - Migrated driver to use state machine based CPU notifier
 v3 - Fixed the code for probe failure while polling on MMDC MAPSR bit 4

Any review & comments are welcomed!

Nitin Chaudhary (3):
  Error: Fix mmdc compilation errors due to cpu notifier
  [i.MX6Q] Code cleanup & verification after fixing compilation error
  [i.MX6Q]Removed MMDC Auto Power saving timeout error

 arch/arm/mach-imx/mmdc.c   | 122 +++++++++++++++++++++++++--------------------
 include/linux/cpuhotplug.h |   1 +
 2 files changed, 69 insertions(+), 54 deletions(-)

--
2.7.4


________________________________


This email and any files transmitted with it are confidential & proprietary to Zodiac Inflight Innovations. This information is intended solely for the use of the individual or entity to which it is addressed. Access or transmittal of the information contained in this e-mail, in full or in part, to any other organization or persons is not authorized.

[PATCH 1/3] Error: Fix mmdc compilation errors due to cpu notifier

From: Nitin Chaudhary <hidden>
Date: 2016-08-19 01:17:37

---
 arch/arm/mach-imx/mmdc.c   | 89 ++++++++++++++++++++++------------------------
 include/linux/cpuhotplug.h |  1 +
 2 files changed, 44 insertions(+), 46 deletions(-)
diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index 372b59c..95c222d 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -77,13 +77,14 @@ struct mmdc_pmu
        struct pmu pmu;
        void __iomem *mmdc_base;
        cpumask_t cpu;
-       struct notifier_block cpu_nb;
        struct hrtimer hrtimer;
        unsigned int irq;
        struct device *dev;
        struct perf_event *mmdc_events[MMDC_NUM_COUNTERS];
 };

+static struct mmdc_pmu *pmu_mmdc;
+
 static unsigned int mmdc_poll_period_us = 1000000;
 module_param_named(pmu_poll_period_us, mmdc_poll_period_us, uint,
                        S_IRUGO | S_IWUSR);
@@ -96,7 +97,6 @@ static ktime_t mmdc_timer_period(void)
 static ssize_t mmdc_cpumask_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct mmdc_pmu *pmu_mmdc = dev_get_drvdata(dev);
        return cpumap_print_to_pagebuf(true, buf, &pmu_mmdc->cpu);
 }
@@ -149,7 +149,7 @@ static const struct attribute_group * attr_groups[] = {
        NULL,
 };

-static u32 mmdc_read_counter(struct mmdc_pmu *pmu_mmdc, int cfg, u64 prev_val)
+static u32 mmdc_read_counter(int cfg, u64 prev_val)
 {
        u32 val;
        void __iomem *mmdc_base, *reg;
@@ -184,7 +184,6 @@ static u32 mmdc_read_counter(struct mmdc_pmu *pmu_mmdc, int cfg, u64 prev_val)

 static void mmdc_enable_profiling(struct perf_event *event)
 {
-       struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
        void __iomem *mmdc_base, *reg;

        mmdc_base = pmu_mmdc->mmdc_base;
@@ -193,32 +192,27 @@ static void mmdc_enable_profiling(struct perf_event *event)
        writel_relaxed(DBG_EN, reg);
 }

-static int mmdc_cpu_notifier(struct notifier_block *nb,
-        unsigned long action, void *hcpu)
+static int mmdc_cpu_offline(unsigned int cpu)
 {
-       struct mmdc_pmu *pmu_mmdc = container_of(nb, struct mmdc_pmu, cpu_nb);
-       unsigned int cpu = (long)hcpu; /* for (long) see kernel/cpu.c */
        unsigned int target;
-
-       switch (action & ~CPU_TASKS_FROZEN) {
-               case CPU_DOWN_PREPARE:
-                       if (!cpumask_test_and_clear_cpu(cpu, &pmu_mmdc->cpu))
-                               break;
-                       target = cpumask_any_but(cpu_online_mask, cpu);
-                       if (target >= nr_cpu_ids)
-                               break;
-                       perf_pmu_migrate_context(&pmu_mmdc->pmu, cpu, target);
-                       cpumask_set_cpu(target, &pmu_mmdc->cpu);
-               default:
-                       break;
-    }
-
-       return NOTIFY_OK;
+       struct mmdc_pmu *pmu_ptr = pmu_mmdc;
+       if (!cpumask_test_and_clear_cpu(cpu, &pmu_ptr->cpu))
+               return 0;
+       target = cpumask_any_but(cpu_online_mask, cpu);
+       if (target >= nr_cpu_ids)
+               return 0;
+
+       perf_pmu_migrate_context(&pmu_ptr->pmu, cpu, target);
+       cpumask_set_cpu(target, &pmu_ptr->cpu);
+       /*
+       if(pmu_ptr->irq)
+               WARN_ON(irq_set_affinity_hint(pmu_ptr->irq, &pmu_ptr->cpu) != 0);
+       */
+       return 0;
 }

 static int mmdc_event_init(struct perf_event *event)
 {
-       struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
        if (event->attr.type != event->pmu->type)
                return -ENOENT;
@@ -243,17 +237,15 @@ static int mmdc_event_init(struct perf_event *event)

 static void mmdc_event_update(struct perf_event * event)
 {
-       struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
        u32 val;
        u64 prev_val;
        prev_val = local64_read(&event->count);
-       val = mmdc_read_counter(pmu_mmdc, (int) event->attr.config, prev_val);
+       val = mmdc_read_counter((int)event->attr.config, prev_val);
        local64_add(val - (u32)(prev_val&0xFFFFFFFF) , &event->count);
 }

 static void mmdc_event_start(struct perf_event *event, int flags)
 {
-       struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
        void __iomem *mmdc_base, *reg;

        local64_set(&event->count, 0);
@@ -268,7 +260,6 @@ static void mmdc_event_start(struct perf_event *event, int flags)

 static int mmdc_event_add(struct perf_event *event, int flags)
 {
-       struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
        int cfg = (int)event->attr.config;
        if (cfg >= 1 && cfg <= MMDC_NUM_COUNTERS)
                pmu_mmdc->mmdc_events[cfg - 1] = event;
@@ -279,7 +270,6 @@ static int mmdc_event_add(struct perf_event *event, int flags)

 static void mmdc_event_stop(struct perf_event *event, int flags)
 {
-       struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
        void __iomem *mmdc_base, *reg;
        int cfg = (int)event->attr.config;
@@ -300,7 +290,7 @@ static void mmdc_event_del(struct perf_event *event, int flags)
        mmdc_event_stop(event, PERF_EF_UPDATE);
 }

-static void mmdc_overflow_handler(struct mmdc_pmu *pmu_mmdc)
+static void mmdc_overflow_handler(void)
 {
        int i;
        u32 val;
@@ -312,7 +302,7 @@ static void mmdc_overflow_handler(struct mmdc_pmu *pmu_mmdc)
                if (event)
                {
                        prev_val = local64_read(&event->count);
-                       val = mmdc_read_counter(pmu_mmdc, i + 1, prev_val);
+                       val = mmdc_read_counter(i + 1, prev_val);
                        local64_add(val - (u32)(prev_val&0xFFFFFFFF) , &event->count);
                }
        }
@@ -320,16 +310,13 @@ static void mmdc_overflow_handler(struct mmdc_pmu *pmu_mmdc)

 static enum hrtimer_restart mmdc_timer_handler(struct hrtimer *hrtimer)
 {
-       struct mmdc_pmu *pmu_mmdc = container_of(hrtimer, struct mmdc_pmu,
-                       hrtimer);
-
-       mmdc_overflow_handler(pmu_mmdc);
+       mmdc_overflow_handler();

        hrtimer_forward_now(hrtimer, mmdc_timer_period());
        return HRTIMER_RESTART;
 }

-static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc, void __iomem *mmdc_base, struct device *dev)
+static int mmdc_pmu_init(void __iomem *mmdc_base, struct device *dev)
 {
        int mmdc_num;
        *pmu_mmdc = (struct mmdc_pmu) {
@@ -347,12 +334,9 @@ static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc, void __iomem *mmdc_base, str
        };

        mmdc_num = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL);
-
+
        cpumask_set_cpu(smp_processor_id(), &pmu_mmdc->cpu);

-       pmu_mmdc->cpu_nb.notifier_call = mmdc_cpu_notifier;
-       pmu_mmdc->cpu_nb.priority = CPU_PRI_PERF + 1;
-
        pmu_mmdc->dev = dev;
        return mmdc_num;
 }
@@ -361,11 +345,11 @@ static int imx_mmdc_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        void __iomem *mmdc_base, *reg;
-       struct mmdc_pmu *pmu_mmdc;
        char * name;
        u32 val;
-       int timeout = 0x400;
+       int timeout = 0x800;
        int mmdc_num;
+       int err;

        mmdc_base = of_iomap(np, 0);
        WARN_ON(!mmdc_base);
@@ -390,7 +374,7 @@ static int imx_mmdc_probe(struct platform_device *pdev)
        if (unlikely(!timeout)) {
                pr_warn("%s: failed to enable automatic power saving\n",
                        __func__);
-               return -EBUSY;
+               //return -EBUSY;
        }
        pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL);
@@ -398,12 +382,18 @@ static int imx_mmdc_probe(struct platform_device *pdev)
                pr_err("failed to allocate PMU device!\n");
                return -ENOMEM;
        }
-       mmdc_num = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev);
+       mmdc_num = mmdc_pmu_init(mmdc_base, &pdev->dev);
        dev_info(pmu_mmdc->dev, "No access to interrupts, using timer.\n");
        hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC,
                        HRTIMER_MODE_REL);
        pmu_mmdc->hrtimer.function = mmdc_timer_handler;
-       register_cpu_notifier(&pmu_mmdc->cpu_nb);
+
+       err = cpuhp_setup_state(CPUHP_AP_PERF_ARM_MMDC_ONLINE,
+                               "AP_PERF_ARM_MMDC_ONLINE", NULL,
+                               mmdc_cpu_offline);
+       if(err)
+               goto error_cpu_notifier;
+
        if (mmdc_num == 0) {
                name = "mmdc";
        } else {
@@ -413,12 +403,19 @@ static int imx_mmdc_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, pmu_mmdc);
        perf_pmu_register(&(pmu_mmdc->pmu), name, -1);
+
+       dev_info(pmu_mmdc->dev, "%s success\n",__func__);
+
        return 0;
+
+error_cpu_notifier:
+       cpuhp_remove_state_nocalls(CPUHP_AP_PERF_ARM_MMDC_ONLINE);
+       kfree(pmu_mmdc);
+       return err;
 }

 static int imx_mmdc_remove(struct platform_device *pdev)
 {
-       struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev);
        perf_pmu_unregister(&pmu_mmdc->pmu);
        kfree(pmu_mmdc);
        return 0;
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 242bf53..c059342 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -86,6 +86,7 @@ enum cpuhp_state {
        CPUHP_AP_PERF_S390_SF_ONLINE,
        CPUHP_AP_PERF_ARM_CCI_ONLINE,
        CPUHP_AP_PERF_ARM_CCN_ONLINE,
+       CPUHP_AP_PERF_ARM_MMDC_ONLINE,
        CPUHP_AP_WORKQUEUE_ONLINE,
        CPUHP_AP_RCUTREE_ONLINE,
        CPUHP_AP_NOTIFY_ONLINE,
--
2.7.4


________________________________


This email and any files transmitted with it are confidential & proprietary to Zodiac Inflight Innovations. This information is intended solely for the use of the individual or entity to which it is addressed. Access or transmittal of the information contained in this e-mail, in full or in part, to any other organization or persons is not authorized.

[PATCH 2/3] [i.MX6Q] Code cleanup & verification after fixing compilation error

From: Nitin Chaudhary <hidden>
Date: 2016-08-19 01:17:38

Cleanup the code after fixing build error in Zhengyu Shen's perf mmdc
integrated driver. The error occured due to migration of CPU Hotplug
notifiers to a state machine based mechanism. Made the necessary cha-
nges into the code and tested the same on an i.MX6QP FSL Board. The
changes allow clean compilation and work fine as well. The results
are as follows:

root at RDU2:~ perf stat -a -e mmdc/busy-cycles/,mmdc/read-accesses/,mmdc/read-byte
s/,mmdc/total-cycles/,mmdc/write-accesses/,mmdc/write-bytes/ dd if=/dev/zero of=
/dev/null bs=1M count=5000
5000+0 records in
5000+0 records out
5242880000 bytes (5.2 GB) copied, 5.4982 s, 954 MB/s

 Performance counter stats for 'system wide':

        1597891298      mmdc/busy-cycles/
          28531959      mmdc/read-accesses/
            910.77 MB   mmdc/read-bytes/
        2917082184      mmdc/total-cycles/
          27965222      mmdc/write-accesses/
            894.91 MB   mmdc/write-bytes/

       5.527407668 seconds time elapsed

But still need to check why the automatic power saving mode is not getting
enabled in my board. Any help/guidance on the same will be appreciated.

Signed-off-by: Nitin Chaudhary <redacted>
---
 arch/arm/mach-imx/mmdc.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index 95c222d..45790f5 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -204,9 +204,10 @@ static int mmdc_cpu_offline(unsigned int cpu)

        perf_pmu_migrate_context(&pmu_ptr->pmu, cpu, target);
        cpumask_set_cpu(target, &pmu_ptr->cpu);
-       /*
-       if(pmu_ptr->irq)
-               WARN_ON(irq_set_affinity_hint(pmu_ptr->irq, &pmu_ptr->cpu) != 0);
+       /*
+        * TODO: Need to check if we need it or not
+        * if(pmu_ptr->irq)
+        *       WARN_ON(irq_set_affinity_hint(pmu_ptr->irq, &pmu_ptr->cpu) != 0);
        */
        return 0;
 }
@@ -374,7 +375,12 @@ static int imx_mmdc_probe(struct platform_device *pdev)
        if (unlikely(!timeout)) {
                pr_warn("%s: failed to enable automatic power saving\n",
                        __func__);
-               //return -EBUSY;
+
+               /*
+                * TODO: Need to check why Automatic Power saving is not
+                * getting enabled successfully.
+                * return -EBUSY;
+                */
        }
        pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL);

--
2.7.4


________________________________


This email and any files transmitted with it are confidential & proprietary to Zodiac Inflight Innovations. This information is intended solely for the use of the individual or entity to which it is addressed. Access or transmittal of the information contained in this e-mail, in full or in part, to any other organization or persons is not authorized.

[PATCH 3/3] [PATCH][i.MX6Q]Removed MMDC Auto Power saving timeout error

From: Nitin Chaudhary <hidden>
Date: 2016-08-19 01:17:39

Moved the busy loop to check MMDC0_MAPSR bit[4] for MMDC Automatic
power saving mode enable to a deferred kernel workqueue ~5s after
probe. Now the check passes successfully and no failure logs are
seen. The power numbers are also lower on the board. The below are
relevant dmesg outputs:

root at RDU2:~ dmesg | grep -i mmdc
[    0.132669] imx-mmdc 21b0000.mmdc: No access to interrupts, using timer.
[    0.132775] imx-mmdc 21b0000.mmdc: imx_mmdc_probe success
[    5.210514] is_mmdc_auto_powersave: MMDC auto power saving enabled MAPSR: 0x00001076

Signed-off-by: Nitin Chaudhary <redacted>
---
 arch/arm/mach-imx/mmdc.c | 43 +++++++++++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index 45790f5..9f27814 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -80,6 +80,7 @@ struct mmdc_pmu
        struct hrtimer hrtimer;
        unsigned int irq;
        struct device *dev;
+       struct delayed_work init_work;
        struct perf_event *mmdc_events[MMDC_NUM_COUNTERS];
 };
@@ -149,6 +150,27 @@ static const struct attribute_group * attr_groups[] = {
        NULL,
 };

+static void is_mmdc_auto_powersave(struct work_struct *work)
+{
+
+       void __iomem *mmdc_base, *reg;
+       int timeout = 0x400;
+       mmdc_base = pmu_mmdc->mmdc_base;
+       reg = mmdc_base + MMDC_MAPSR;
+
+       /* Ensure Automatic Power saving mode is successfully enabled */
+       while (!(readl_relaxed(reg) & 1 << BP_MMDC_MAPSR_PSS) && --timeout)
+               cpu_relax();
+
+       if (unlikely(!timeout)) {
+               pr_warn("%s: failed to enable automatic power saving, recheck\n",
+                       __func__);
+       } else {
+               pr_info("%s: MMDC auto power saving enabled MAPSR: 0x%08x\n",
+                       __func__);
+       }
+}
+
 static u32 mmdc_read_counter(int cfg, u64 prev_val)
 {
        u32 val;
@@ -348,7 +370,6 @@ static int imx_mmdc_probe(struct platform_device *pdev)
        void __iomem *mmdc_base, *reg;
        char * name;
        u32 val;
-       int timeout = 0x800;
        int mmdc_num;
        int err;
@@ -368,20 +389,6 @@ static int imx_mmdc_probe(struct platform_device *pdev)
        val &= ~(1 << BP_MMDC_MAPSR_PSD);
        writel_relaxed(val, reg);

-       /* Ensure it's successfully enabled */
-       while (!(readl_relaxed(reg) & 1 << BP_MMDC_MAPSR_PSS) && --timeout)
-               cpu_relax();
-
-       if (unlikely(!timeout)) {
-               pr_warn("%s: failed to enable automatic power saving\n",
-                       __func__);
-
-               /*
-                * TODO: Need to check why Automatic Power saving is not
-                * getting enabled successfully.
-                * return -EBUSY;
-                */
-       }
        pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL);

        if (!pmu_mmdc) {
@@ -409,7 +416,11 @@ static int imx_mmdc_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, pmu_mmdc);
        perf_pmu_register(&(pmu_mmdc->pmu), name, -1);
-
+
+       /* Check if automatic Power saving mode was enabled */
+       INIT_DELAYED_WORK(&pmu_mmdc->init_work, is_mmdc_auto_powersave);
+       schedule_delayed_work(&pmu_mmdc->init_work, msecs_to_jiffies(5000));
+
        dev_info(pmu_mmdc->dev, "%s success\n",__func__);

        return 0;
--
2.7.4


________________________________


This email and any files transmitted with it are confidential & proprietary to Zodiac Inflight Innovations. This information is intended solely for the use of the individual or entity to which it is addressed. Access or transmittal of the information contained in this e-mail, in full or in part, to any other organization or persons is not authorized.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help