[PATCH v1 2/3] drm: Add API for capturing frame CRCs

Tomeu Vizoso tomeu.vizoso at collabora.com
Wed Jun 22 08:26:36 UTC 2016


On 21 June 2016 at 17:07, Thierry Reding <thierry.reding at gmail.com> wrote:
> On Tue, Jun 21, 2016 at 01:06:41PM +0200, Tomeu Vizoso wrote:
> [...]
>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> [...]
>
>> +
>> +static int crc_control_show(struct seq_file *m, void *data)
>> +{
>> +     struct drm_device *dev = m->private;
>> +     struct drm_crtc *crtc;
>> +
>> +     drm_for_each_crtc(crtc, dev)
>> +             seq_printf(m, "crtc %d %s\n", crtc->index,
>> +                        crtc->crc.source ? crtc->crc.source : "none");
>> +
>> +     return 0;
>> +}
>
> Why are these control files not per-CRTC? I'd imagine you could do
> something like control the CRC generation on writes and provide the
> sampled CRCs on reads.

We just thought there wasn't a strong point for breaking the existing
API in a fundamental way. The current proposal allows us to reuse more
code between the new and legacy CRC implementations in i915 and in
IGT.

>> +             source = NULL;
>> +
>> +     if (!crc->source && !source)
>> +             return 0;
>> +
>> +     if (crc->source && source && !strcmp(crc->source, source))
>> +             return 0;
>> +
>> +     /* Forbid changing the source without going back to "none". */
>> +     if (crc->source && source)
>> +             return -EINVAL;
>
> Why? It seems to me that if a driver doesn't support switching from one
> source to another directly, then it should internally handle that. After
> all the source parameter is already driver-specific, so it seems odd to
> impose this kind of policy on it at this level.

Hmm, I don't see when that would make sense for userspace. If
userspace has a source configured and changes directly to another, how
does it know what's the last CRC for the old source? I think that if
userspace does that it's shooting in its foot and it's good to give an
error.

>> +
>> +     drm_for_each_crtc(crtc, dev)
>> +             if (i++ == index)
>> +                     return crtc;
>> +
>> +     return NULL;
>> +}
>
> This looks like a candidate for the core. I know that at least Tegra
> implements a variant of this, and I think i915 does, too.

And a few others. I would go this way but when I pinged danvet on irc
he didn't reply so I just went with the safe option.

>> +/*
>> + * Parse CRC command strings:
>> + *   command: wsp* object wsp+ (crtc | pipe) wsp+ source wsp*
>
> Should the "(crtc | pipe)" in the above be "object"?

In one case they are literals and in the other symbols.

>> + *   object: ('crtc' | 'pipe')
>
> Because you define that here?
>
>> + *   crtc: (0 | 1 | 2 | ...)
>> + *   pipe: (A | B | C)
>> + *   source: (none | plane1 | plane2 | ...)
>
> I wouldn't provide "plane1 | plane2 |" here, since the parameter is
> passed as-is to drivers, which may or may not support plane1 or plane2.

Agreed, feels more confusing than clarifying.

>> + *   wsp: (#0x20 | #0x9 | #0xA)+
>> + *
>> + * eg.:
>> + *  "crtc 0 plane1"  ->  Start CRC computations on plane1 of first CRTC
>> + *  "crtc 0 none"    ->  Stop CRC
>
> I've said this above, but again, it seems odd to me that you'd have to
> configure the CRC per-CRTC in one per-device file and read out the CRC
> from per-CRTC files.

Not sure, I like that the per-crtc files just provide CRC data, and
that there's a separate control file that can be queried for the
current state.

>
>> +                                    entry->frame, entry->crc[0],
>> +                                    entry->crc[1], entry->crc[2],
>> +                                    entry->crc[3], entry->crc[4]);
>
> What about drivers that only support one uint32_t for the CRC? Do they
> also need to output all unused uint32_t:s?

Yeah, do you think that could be a problem?

>> +
>> +             ret = copy_to_user(user_buf, buf, CRC_LINE_LEN);
>> +             if (ret == CRC_LINE_LEN)
>> +                     return -EFAULT;
>>
>> +             user_buf += CRC_LINE_LEN;
>> +             n_entries--;
>> +
>> +             spin_lock_irq(&crc->lock);
>> +     }
>> +
>> +     spin_unlock_irq(&crc->lock);
>> +
>> +     return bytes_read;
>> +}
>> +
>> +const struct file_operations drm_crtc_crc_fops = {
>> +     .owner = THIS_MODULE,
>> +     .open = crtc_crc_open,
>> +     .read = crtc_crc_read,
>> +     .release = crtc_crc_release,
>> +};
>
> Do we want to support poll?

Don't see the point of it, TBH.

>> +
>> +static int drm_debugfs_crtc_add_for_minor(struct drm_crtc *crtc,
>> +                                       struct drm_minor *minor)
>> +{
>> +     struct dentry *ent;
>> +     char *name;
>> +
>> +     if (!minor->debugfs_root)
>> +             return -1;
>
> Can this ever happen? Perhaps turn this into a symbolic name if you
> really need it.

Sorry, can you explain what you mean by that?

>> +
>> +     name = kasprintf(GFP_KERNEL, "drm_crtc_%d_crc", crtc->index);
>> +     if (!name)
>> +             return -ENOMEM;
>
> I think it might be preferable to move this all into per-CRTC debugfs
> directories, perhaps even collapse the "crc" and "control" files. But in
> any case I think the drm_ prefix is redundant here and should be
> dropped.

Yeah, I kind of like the redundancy as in the client code you will
only sometimes find the file name next to the directory name, but I
don't particularly care myself.

>> +int drm_debugfs_crtc_add(struct drm_crtc *crtc)
>> +{
>> +     int ret;
>> +
>> +     ret = drm_debugfs_crtc_add_for_minor(crtc, crtc->dev->control);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = drm_debugfs_crtc_add_for_minor(crtc, crtc->dev->primary);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = drm_debugfs_crtc_add_for_minor(crtc, crtc->dev->render);
>> +     if (ret)
>> +             return ret;
>> +
>> +     return 0;
>> +}
>
> Do we really want these for all minors? Is ->primary not enough? It
> certainly seems completely misplaced in ->render, and I don't think
> anything really uses ->control anymore.

Agreed.

>> +void drm_crtc_add_crc_entry(struct drm_crtc *crtc, uint32_t frame,
>> +                         uint32_t crc0, uint32_t crc1, uint32_t crc2,
>> +                         uint32_t crc3, uint32_t crc4)
>
> Perhaps allow passing the CRC as an array with a count parameter? I can
> imagine that a lot of hardware will only give you a single uint32_t for
> the CRC, in which case you could do:
>
>         drm_crtc_add_crc_entry(crtc, frame, &crc, 1);
>
> instead of:
>
>         drm_crtc_add_crc_entry(crtc, frame, crc, 0, 0, 0, 0);
>
> It would probably save poor users of the interface, such as myself, a
> lot of headaches because they can't remember how many uint32_t:s the
> function needs.

Sounds good to me, I don't really know how common multiple sources of
complex CRC data will be in the future.

>> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
>> index 38401d406532..e5b124d937f5 100644
>> --- a/drivers/gpu/drm/drm_internal.h
>> +++ b/drivers/gpu/drm/drm_internal.h
>> @@ -100,6 +100,8 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
>>  int drm_debugfs_cleanup(struct drm_minor *minor);
>>  int drm_debugfs_connector_add(struct drm_connector *connector);
>>  void drm_debugfs_connector_remove(struct drm_connector *connector);
>> +int drm_debugfs_crtc_add(struct drm_crtc *crtc);
>> +void drm_debugfs_crtc_remove(struct drm_crtc *crtc);
>
> Oh... this isn't something that drivers are supposed to call?

Right, it's analogous to drm_debugfs_connector_add.

>> +      *
>> +      * When CRC generation is enabled, the driver should call
>> +      * drm_crtc_add_crc_entry() at each frame, providing any information
>> +      * that characterizes the frame contents in the crcN arguments, as
>> +      * provided from the configured source. Drivers should accept a "auto"
>> +      * source name that will select a default source for this CRTC.
>
> Would it be useful to provide some more aliases? "enable" and "on" for
> "auto", "disable" and "off" for "none"?

Not sure, TBH, i like to keep my interfaces simple. Do you think this
could be helpful?

Thanks for the great review!

Tomeu


More information about the dri-devel mailing list