LCOV - code coverage report
Current view: top level - drivers/opp - debugfs.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 52 78 66.7 %
Date: 2020-09-30 20:25:40 Functions: 7 10 70.0 %
Branches: 6 18 33.3 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Generic OPP debugfs interface
       4                 :            :  *
       5                 :            :  * Copyright (C) 2015-2016 Viresh Kumar <viresh.kumar@linaro.org>
       6                 :            :  */
       7                 :            : 
       8                 :            : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
       9                 :            : 
      10                 :            : #include <linux/debugfs.h>
      11                 :            : #include <linux/device.h>
      12                 :            : #include <linux/err.h>
      13                 :            : #include <linux/init.h>
      14                 :            : #include <linux/limits.h>
      15                 :            : #include <linux/slab.h>
      16                 :            : 
      17                 :            : #include "opp.h"
      18                 :            : 
      19                 :            : static struct dentry *rootdir;
      20                 :            : 
      21                 :        828 : static void opp_set_dev_name(const struct device *dev, char *name)
      22                 :            : {
      23         [ -  + ]:        828 :         if (dev->parent)
      24                 :          0 :                 snprintf(name, NAME_MAX, "%s-%s", dev_name(dev->parent),
      25                 :            :                          dev_name(dev));
      26                 :            :         else
      27                 :        828 :                 snprintf(name, NAME_MAX, "%s", dev_name(dev));
      28                 :        828 : }
      29                 :            : 
      30                 :          0 : void opp_debug_remove_one(struct dev_pm_opp *opp)
      31                 :            : {
      32                 :          0 :         debugfs_remove_recursive(opp->dentry);
      33                 :          0 : }
      34                 :            : 
      35                 :        828 : static void opp_debug_create_supplies(struct dev_pm_opp *opp,
      36                 :            :                                       struct opp_table *opp_table,
      37                 :            :                                       struct dentry *pdentry)
      38                 :            : {
      39                 :            :         struct dentry *d;
      40                 :            :         int i;
      41                 :            : 
      42         [ +  + ]:       1656 :         for (i = 0; i < opp_table->regulator_count; i++) {
      43                 :            :                 char name[15];
      44                 :            : 
      45                 :        828 :                 snprintf(name, sizeof(name), "supply-%d", i);
      46                 :            : 
      47                 :            :                 /* Create per-opp directory */
      48                 :        828 :                 d = debugfs_create_dir(name, pdentry);
      49                 :            : 
      50                 :        828 :                 debugfs_create_ulong("u_volt_target", S_IRUGO, d,
      51                 :        828 :                                      &opp->supplies[i].u_volt);
      52                 :            : 
      53                 :        828 :                 debugfs_create_ulong("u_volt_min", S_IRUGO, d,
      54                 :        828 :                                      &opp->supplies[i].u_volt_min);
      55                 :            : 
      56                 :        828 :                 debugfs_create_ulong("u_volt_max", S_IRUGO, d,
      57                 :        828 :                                      &opp->supplies[i].u_volt_max);
      58                 :            : 
      59                 :        828 :                 debugfs_create_ulong("u_amp", S_IRUGO, d,
      60                 :        828 :                                      &opp->supplies[i].u_amp);
      61                 :            :         }
      62                 :        828 : }
      63                 :            : 
      64                 :        828 : void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
      65                 :            : {
      66                 :        828 :         struct dentry *pdentry = opp_table->dentry;
      67                 :            :         struct dentry *d;
      68                 :            :         unsigned long id;
      69                 :            :         char name[25];  /* 20 chars for 64 bit value + 5 (opp:\0) */
      70                 :            : 
      71                 :            :         /*
      72                 :            :          * Get directory name for OPP.
      73                 :            :          *
      74                 :            :          * - Normally rate is unique to each OPP, use it to get unique opp-name.
      75                 :            :          * - For some devices rate isn't available, use index instead.
      76                 :            :          */
      77         [ -  + ]:        828 :         if (likely(opp->rate))
      78                 :            :                 id = opp->rate;
      79                 :            :         else
      80                 :          0 :                 id = _get_opp_count(opp_table);
      81                 :            : 
      82                 :        828 :         snprintf(name, sizeof(name), "opp:%lu", id);
      83                 :            : 
      84                 :            :         /* Create per-opp directory */
      85                 :        828 :         d = debugfs_create_dir(name, pdentry);
      86                 :            : 
      87                 :        828 :         debugfs_create_bool("available", S_IRUGO, d, &opp->available);
      88                 :        828 :         debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic);
      89                 :        828 :         debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo);
      90                 :        828 :         debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend);
      91                 :        828 :         debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate);
      92                 :        828 :         debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate);
      93                 :        828 :         debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
      94                 :            :                              &opp->clock_latency_ns);
      95                 :            : 
      96                 :        828 :         opp_debug_create_supplies(opp, opp_table, d);
      97                 :            : 
      98                 :        828 :         opp->dentry = d;
      99                 :        828 : }
     100                 :            : 
     101                 :        207 : static void opp_list_debug_create_dir(struct opp_device *opp_dev,
     102                 :            :                                       struct opp_table *opp_table)
     103                 :            : {
     104                 :        207 :         const struct device *dev = opp_dev->dev;
     105                 :            :         struct dentry *d;
     106                 :            : 
     107                 :        207 :         opp_set_dev_name(dev, opp_table->dentry_name);
     108                 :            : 
     109                 :            :         /* Create device specific directory */
     110                 :        207 :         d = debugfs_create_dir(opp_table->dentry_name, rootdir);
     111                 :            : 
     112                 :        207 :         opp_dev->dentry = d;
     113                 :        207 :         opp_table->dentry = d;
     114                 :        207 : }
     115                 :            : 
     116                 :        621 : static void opp_list_debug_create_link(struct opp_device *opp_dev,
     117                 :            :                                        struct opp_table *opp_table)
     118                 :            : {
     119                 :            :         char name[NAME_MAX];
     120                 :            : 
     121                 :        621 :         opp_set_dev_name(opp_dev->dev, name);
     122                 :            : 
     123                 :            :         /* Create device specific directory link */
     124                 :       1242 :         opp_dev->dentry = debugfs_create_symlink(name, rootdir,
     125                 :        621 :                                                  opp_table->dentry_name);
     126                 :        621 : }
     127                 :            : 
     128                 :            : /**
     129                 :            :  * opp_debug_register - add a device opp node to the debugfs 'opp' directory
     130                 :            :  * @opp_dev: opp-dev pointer for device
     131                 :            :  * @opp_table: the device-opp being added
     132                 :            :  *
     133                 :            :  * Dynamically adds device specific directory in debugfs 'opp' directory. If the
     134                 :            :  * device-opp is shared with other devices, then links will be created for all
     135                 :            :  * devices except the first.
     136                 :            :  */
     137                 :        828 : void opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table)
     138                 :            : {
     139         [ +  + ]:        828 :         if (opp_table->dentry)
     140                 :        621 :                 opp_list_debug_create_link(opp_dev, opp_table);
     141                 :            :         else
     142                 :        207 :                 opp_list_debug_create_dir(opp_dev, opp_table);
     143                 :        828 : }
     144                 :            : 
     145                 :          0 : static void opp_migrate_dentry(struct opp_device *opp_dev,
     146                 :            :                                struct opp_table *opp_table)
     147                 :            : {
     148                 :            :         struct opp_device *new_dev;
     149                 :            :         const struct device *dev;
     150                 :            :         struct dentry *dentry;
     151                 :            : 
     152                 :            :         /* Look for next opp-dev */
     153         [ #  # ]:          0 :         list_for_each_entry(new_dev, &opp_table->dev_list, node)
     154         [ #  # ]:          0 :                 if (new_dev != opp_dev)
     155                 :            :                         break;
     156                 :            : 
     157                 :            :         /* new_dev is guaranteed to be valid here */
     158                 :          0 :         dev = new_dev->dev;
     159                 :          0 :         debugfs_remove_recursive(new_dev->dentry);
     160                 :            : 
     161                 :          0 :         opp_set_dev_name(dev, opp_table->dentry_name);
     162                 :            : 
     163                 :          0 :         dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir,
     164                 :            :                                 opp_table->dentry_name);
     165         [ #  # ]:          0 :         if (!dentry) {
     166                 :          0 :                 dev_err(dev, "%s: Failed to rename link from: %s to %s\n",
     167                 :            :                         __func__, dev_name(opp_dev->dev), dev_name(dev));
     168                 :          0 :                 return;
     169                 :            :         }
     170                 :            : 
     171                 :          0 :         new_dev->dentry = dentry;
     172                 :          0 :         opp_table->dentry = dentry;
     173                 :            : }
     174                 :            : 
     175                 :            : /**
     176                 :            :  * opp_debug_unregister - remove a device opp node from debugfs opp directory
     177                 :            :  * @opp_dev: opp-dev pointer for device
     178                 :            :  * @opp_table: the device-opp being removed
     179                 :            :  *
     180                 :            :  * Dynamically removes device specific directory from debugfs 'opp' directory.
     181                 :            :  */
     182                 :          0 : void opp_debug_unregister(struct opp_device *opp_dev,
     183                 :            :                           struct opp_table *opp_table)
     184                 :            : {
     185         [ #  # ]:          0 :         if (opp_dev->dentry == opp_table->dentry) {
     186                 :            :                 /* Move the real dentry object under another device */
     187         [ #  # ]:          0 :                 if (!list_is_singular(&opp_table->dev_list)) {
     188                 :          0 :                         opp_migrate_dentry(opp_dev, opp_table);
     189                 :          0 :                         goto out;
     190                 :            :                 }
     191                 :          0 :                 opp_table->dentry = NULL;
     192                 :            :         }
     193                 :            : 
     194                 :          0 :         debugfs_remove_recursive(opp_dev->dentry);
     195                 :            : 
     196                 :            : out:
     197                 :          0 :         opp_dev->dentry = NULL;
     198                 :          0 : }
     199                 :            : 
     200                 :        207 : static int __init opp_debug_init(void)
     201                 :            : {
     202                 :            :         /* Create /sys/kernel/debug/opp directory */
     203                 :        207 :         rootdir = debugfs_create_dir("opp", NULL);
     204                 :            : 
     205                 :        207 :         return 0;
     206                 :            : }
     207                 :            : core_initcall(opp_debug_init);

Generated by: LCOV version 1.14