Re: [PATCH 2/2] iommu/tegra: smmu: Use __debugfs_create_dir

From: Felipe Balbi
Date: Wed Aug 08 2012 - 11:34:42 EST


Hi,

On Wed, Aug 08, 2012 at 06:11:29PM +0300, Felipe Balbi wrote:
> Hi,
>
> On Wed, Aug 08, 2012 at 09:24:33AM +0300, Hiroshi Doyu wrote:
> > The commit c3b1a35 "debugfs: make sure that debugfs_create_file() gets
> > used only for regulars" doesn't allow to use debugfs_create_file() for
> > dir. Use the version with "data", __debugfs_create_dir().
> >
> > Signed-off-by: Hiroshi Doyu <hdoyu@xxxxxxxxxx>
> > Reported-by: Laxman Dewangan <ldewangan@xxxxxxxxxx>
> > ---
> > drivers/iommu/tegra-smmu.c | 4 +---
> > 1 files changed, 1 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
> > index 5e51fb7..41aff7a 100644
> > --- a/drivers/iommu/tegra-smmu.c
> > +++ b/drivers/iommu/tegra-smmu.c
> > @@ -1035,9 +1035,7 @@ static void smmu_debugfs_create(struct smmu_device *smmu)
> > int i;
> > struct dentry *root;
> >
> > - root = debugfs_create_file(dev_name(smmu->dev),
> > - S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
> > - NULL, smmu, NULL);
> > + root = __debugfs_create_dir(dev_name(smmu->dev), NULL, smmu);
>
> why would the directory need extra data ? Looking in mainline,
> tegra-smmu.c doesn't have any debugfs support, where can I see the
> patches adding debugfs to tegra-smmu ? It doesn't look correct that the
> directory will have a data field.

Looking at linux-next I found the commit which added it:

> @@ -892,6 +909,164 @@ static struct iommu_ops smmu_iommu_ops = {
> .pgsize_bitmap = SMMU_IOMMU_PGSIZES,
> };
>
> +/* Should be in the order of enum */
> +static const char * const smmu_debugfs_mc[] = { "mc", };
> +static const char * const smmu_debugfs_cache[] = { "tlb", "ptc", };
> +
> +static ssize_t smmu_debugfs_stats_write(struct file *file,
> + const char __user *buffer,
> + size_t count, loff_t *pos)
> +{
> + struct smmu_device *smmu;
> + struct dentry *dent;
> + int i, cache, mc;
> + enum {
> + _OFF = 0,
> + _ON,
> + _RESET,
> + };
> + const char * const command[] = {
> + [_OFF] = "off",
> + [_ON] = "on",
> + [_RESET] = "reset",
> + };
> + char str[] = "reset";
> + u32 val;
> + size_t offs;
> +
> + count = min_t(size_t, count, sizeof(str));
> + if (copy_from_user(str, buffer, count))
> + return -EINVAL;
> +
> + for (i = 0; i < ARRAY_SIZE(command); i++)
> + if (strncmp(str, command[i],
> + strlen(command[i])) == 0)
> + break;
> +
> + if (i == ARRAY_SIZE(command))
> + return -EINVAL;
> +
> + dent = file->f_dentry;
> + cache = (int)dent->d_inode->i_private;

cache you can figure out by the filename. In fact, it would be much
better to have tlc and ptc directories with a "status" filename which
you write ON/OFF/RESET or enable/disable/reset to trigger what you need.

For that to work, you should probably hold tlb and ptc on an array of
some sort, and pass those as data to their respective "status" files as
the data field. If tlb and ptc are properly defined structures which can
point back to smmu, then you have everything you need.

I mean something like:

struct smmu;

struct mc {
const char *name;
void __iomem *regs;

struct smmu *smmu;
};

struct smmu {
struct mc mc[2]; /*what does mc stand for ? memory controller ? */

...
};

debugfs_create_dir(smmu);
debugfs_create_dir(mc);
debugfs_create_dir(smmu->mc[1].name);
debugfs_create_dir(smmu->mc[2].name);
debugfs_create_file(&smmu->mc[1], status);
debugfs_create_file(&smmu->mc[2], status);

or something similar. You will avoid all the trickery you did here to
achieve what you need.

> + mc = (int)dent->d_parent->d_inode->i_private;
> + smmu = dent->d_parent->d_parent->d_inode->i_private;
> +
> + offs = SMMU_CACHE_CONFIG(cache);
> + val = smmu_read(smmu, offs);
> + switch (i) {
> + case _OFF:
> + val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE;
> + val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
> + smmu_write(smmu, val, offs);
> + break;
> + case _ON:
> + val |= SMMU_CACHE_CONFIG_STATS_ENABLE;
> + val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
> + smmu_write(smmu, val, offs);
> + break;
> + case _RESET:
> + val |= SMMU_CACHE_CONFIG_STATS_TEST;
> + smmu_write(smmu, val, offs);
> + val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
> + smmu_write(smmu, val, offs);
> + break;
> + default:
> + BUG();
> + break;
> + }
> +
> + dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__,
> + val, smmu_read(smmu, offs), offs);
> +
> + return count;
> +}
> +
> +static int smmu_debugfs_stats_show(struct seq_file *s, void *v)
> +{
> + struct smmu_device *smmu;
> + struct dentry *dent;
> + int i, cache, mc;
> + const char * const stats[] = { "hit", "miss", };
> +
> + dent = d_find_alias(s->private);
> + cache = (int)dent->d_inode->i_private;
> + mc = (int)dent->d_parent->d_inode->i_private;
> + smmu = dent->d_parent->d_parent->d_inode->i_private;
> +
> + for (i = 0; i < ARRAY_SIZE(stats); i++) {
> + u32 val;
> + size_t offs;
> +
> + offs = SMMU_STATS_CACHE_COUNT(mc, cache, i);
> + val = smmu_read(smmu, offs);
> + seq_printf(s, "%s:%08x ", stats[i], val);
> +
> + dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__,
> + stats[i], val, offs);
> + }
> + seq_printf(s, "\n");
> +
> + return 0;
> +}
> +
> +static int smmu_debugfs_stats_open(struct inode *inode, struct file *file)
> +{
> + return single_open(file, smmu_debugfs_stats_show, inode);
> +}
> +
> +static const struct file_operations smmu_debugfs_stats_fops = {
> + .open = smmu_debugfs_stats_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = single_release,
> + .write = smmu_debugfs_stats_write,
> +};
> +
> +static void smmu_debugfs_delete(struct smmu_device *smmu)
> +{
> + debugfs_remove_recursive(smmu->debugfs_root);
> +}
> +
> +static void smmu_debugfs_create(struct smmu_device *smmu)
> +{
> + int i;
> + struct dentry *root;
> +
> + root = debugfs_create_file(dev_name(smmu->dev),
> + S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
> + NULL, smmu, NULL);

directories don't need data. You don't even have a file_operations
structure so when exactly are you going to access the data ? What you
did above is actually wrong. You need to either patch this ASAP or drop
the patch you wrote and rewrite the whole debugfs support.

> + if (!root)
> + goto err_out;
> + smmu->debugfs_root = root;
> +
> + for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) {
> + int j;
> + struct dentry *mc;
> +
> + mc = debugfs_create_file(smmu_debugfs_mc[i],
> + S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
> + root, (void *)i, NULL);

likewise here. What would you use that index for ? Even if you were to
access it, how would you use it ? Not to mention that you never, ever
access the private_data of the directory :-)

Just convert these two to the proper debugfs_create_dir()

> + if (!mc)
> + goto err_out;
> +
> + for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) {
> + struct dentry *cache;
> +
> + cache = debugfs_create_file(smmu_debugfs_cache[j],
> + S_IWUGO | S_IRUGO, mc,
> + (void *)j,
> + &smmu_debugfs_stats_fops);

it would be far better to pass a structure which you actually need. In
this case 'smmu'. That will be a lot more useful for your code.

--
balbi

Attachment: signature.asc
Description: Digital signature