Re: [igt-dev] [PATCH i-g-t] tools/dpcd_reg: Add dump all functionality

Tarun Vyas
2018-10-23T16:42:46Z

On Tue, Oct 23, 2018 at 11:50:47AM +0300, Jani Nikula wrote:
> On Mon, 22 Oct 2018, Tarun Vyas <tarun.vyas@intel.com> wrote:
> > From: Rodrigo Vivi <rodrigo.vivi@intel.com>
> >
> > And make it the default when no operation or device is given.
> >
> > So, this will replace i915_dpcd for now but can be expanded
> > later.
> >
> > Current debugfs:
> >
> > $ sudo cat /sys/kernel/debug/dri/0/DP-1/i915_dpcd
> > 0000: 12 14 c4 01 01 00 01 00 02 02 06 00 00 00 02
> > 0070: 00 00
> > 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> > 0100: 14 84 00 06 06 06 06 00 01 04 00
> > 0200: 41 00 77 77 01 03 22 22
> > 0600: 01
> > 0700: 01
> > 0701: 00 00 00 00
> > 0720: 00 01 00 00 00 01 01 00 00 00 00 00 01 00 00 01
> > 0732: 00 00
> >
> > $ sudo cat /sys/kernel/debug/dri/0/eDP-1/i915_dpcd
> > 0000: 12 14 84 40 00 00 01 01 02 00 00 00 00 0b 00
> > 0070: 01 00
> > 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> > 0100: 14 04 00 00 00 00 00 00 00 00 00
> > 0200: 41 00 00 00 80 00 66 66
> > 0600: 01
> > 0700: 02
> > 0701: 9f 40 00 00
> > 0720: 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00
> > 0732: 00 00
> >
> > new tool:
> >
> > $ sudo tools/dpcd_reg
> >
> > Dumping DPDDC-B
> > 0x0000: 12 14 c4 01 01 00 01 00 02 02 06 00 00 00 02
> > 0x0070: 00 00
> > 0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> > 0x0100: 14 84 00 06 06 06 06 00 01 04 00
> > 0x0200: 41 00 77 77 01 03 22 22
> > 0x0600: 01
> > 0x0700: 01
> > 0x0701: 00 00 00 00
> > 0x0720: 00 01 00 00 00 01 01 00 00 00 00 00 01 00 00 01
> > 0x0732: 00 00
> > 0x2008: 00
> >
> > Dumping DPDDC-A
> > 0x0000: 14 0a 82 41 00 00 01 c0 02 00 00 00 0f 09 80
> > 0x0070: 03 1b
> > 0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> > 0x0100: 00 82 00 00 00 00 00 00 01 08 00
> > 0x0200: 01 00 00 00 00 01 00 00
> > 0x0600: 01
> > 0x0700: 04
> > 0x0701: fb ff 00 00
> > 0x0720: 01 03 ff ff 10 0a 10 00 01 00 01 00 00 c0 00 00
> > 0x0732: 00 14
> > 0x2008: 02
> >
> > Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Signed-off-by: Tarun Vyas <tarun.vyas@intel.com>
> > ---
> > tools/dpcd_reg.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> > 1 file changed, 91 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/dpcd_reg.c b/tools/dpcd_reg.c
> > index 2761168d..51cec85f 100644
> > --- a/tools/dpcd_reg.c
> > +++ b/tools/dpcd_reg.c
> > @@ -35,6 +35,7 @@
> > #include <unistd.h>
> > #include <limits.h>
> > #include <stdbool.h>
> > +#include <dirent.h>
> >
> > #define MAX_DP_OFFSET 0xfffff
> > #define DRM_AUX_MINORS 256
> > @@ -109,6 +110,35 @@ static inline bool strtol_err_util(char *endptr, long *val)
> > return false;
> > }
> >
> > +static void connector_name(char *f_name, char *dpcd_name)
> > +{
> > + char sysfs_path[PATH_MAX];
> > + int sysfs_fd, ret;
> > +
> > + snprintf(sysfs_path, PATH_MAX,
> > + "/sys/class/drm_dp_aux_dev/%s/name",
> > + f_name);
> > + sysfs_fd = open(sysfs_path, O_RDONLY);
> > + if (sysfs_fd < 0) {
> > + fprintf(stderr,
> > + "fail to open %s\n", sysfs_path);
> > + return;
> > + }
> > +
> > + ret = read(sysfs_fd, dpcd_name, sizeof(dpcd_name) - 1);
>
> Serious bug #1. The sizeof doesn't do what you intend.
>
Yes, that was stupid. The original patch was doing it right where the array was declared. I messed it up while creating a new function out of it.
> Regular C bug. read() may return a positive result smaller than
> requested. See readN() in igt_sysfs.c.
>
>
Yes, but, if the read was partial (or zero) , then we would still like to treat it as a failure, in this specific case, right ?
> > + if (ret < 0) {
> > + fprintf(stderr,
> > + "fail to read dpcd name from %s\n\n", sysfs_path);
>
> Two newlines is unnecessary.
>
Ok.
> > + goto cleanup;
> > + }
> > +
> > + dpcd_name[ret] = '\0';
> > + printf("%s\n", dpcd_name);
>
> Why does this function both retrieve the name to the caller and print
> it? Those are two things that should stay orthogonal.
>
I kept them separate originally...will work on it in the next version.
> > +
> > +cleanup:
> > + close(sysfs_fd);
> > +}
> > +
> > static int parse_opts(struct dpcd_data *dpcd, int argc, char **argv)
> > {
> > int ret, vflag = 0;
> > @@ -280,13 +310,61 @@ static int dpcd_dump(int fd)
> > return ret;
> > }
> >
> > +static int dpcd_dump_all(void)
> > +{
> > + struct dirent *dirent;
> > + DIR *dir;
> > + char dev_path[PATH_MAX];
> > + int dev_fd, ret = 0;
> > + char dpcd_name[8];
> > + char discard;
> > +
> > + dir = opendir("/sys/class/drm_dp_aux_dev/");
> > + if (!dir) {
> > + fprintf(stderr, "fail to read /dev\n");
> > + return ENOENT;
> > + }
> > +
> > + while ((dirent = readdir(dir))) {
> > + if (strncmp(dirent->d_name, "drm_dp_aux", 10) == 0) {
> > + snprintf(dev_path, PATH_MAX,
> > + "/dev/%s", dirent->d_name);
> > +
> > + dev_fd = open(dev_path, O_RDONLY);
> > + if (dev_fd < 0) {
> > + fprintf(stderr,
> > + "fail to open %s\n", dev_path);
> > + continue;
> > + }
> > +
> > + printf("\nDumping ");
> > + connector_name(dirent->d_name, dpcd_name);
>
> And what if connector_name() fails?
>
I had connector_name() return an int but then changed it to void b/c I was like,
I'd still want to dump the registers regardless of connector_name.
Do we wanna skip it all if we cant get the connector_name ?
> > +
> > + /* Dummy read to check if dpcd is available */
> > + ret = read(dev_fd, &discard, 1);
>
> Serious bug #2. This read botches up the whole dump.
>
Hmm. we should skip the dump only if the read return a -ve...
> > + if (ret != 1) {
> > + printf("DPCD %s seems not available. skipping...\n",
> > + dpcd_name);
> > + continue;
> > + }
> > +
> > + dpcd_dump(dev_fd);
> > + close(dev_fd);
> > + }
> > + }
> > +
> > + closedir(dir);
> > +
> > + return EXIT_SUCCESS;
> > +}
> > int main(int argc, char **argv)
> > {
> > char dev_name[20];
> > + char sys_name[16], dpcd_name[8];
> > int ret, fd;
> >
> > struct dpcd_data dpcd = {
> > - .devid = 0,
> > + .devid = -1,
> > .file_op = O_RDONLY,
> > .rw.offset = 0x0,
> > .rw.count = 1,
> > @@ -297,7 +375,16 @@ int main(int argc, char **argv)
> > if (ret != EXIT_SUCCESS)
> > return ret;
> >
> > + if (dpcd.devid < 0) {
> > + if (dpcd.cmd == DUMP)
> > + return dpcd_dump_all();
> > +
> > + dpcd.devid = 0;
> > + }
> > +
> > snprintf(dev_name, strlen(aux_dev) + 4, "%s%d", aux_dev, dpcd.devid);
>
> That's not part of this patch, but what on earth does strlen(aux_dev)
> have to do with how much fits into dev_name?!?
>
Yes. Will fix it.
> > + snprintf(sys_name, 16, "drm_dp_aux%d", dpcd.devid);
>
> sizeof.
>
Right
> > +
>
> Superfluous newline.
>
Ok
> >
> > fd = open(dev_name, dpcd.file_op);
> > if (fd < 0) {
> > @@ -307,6 +394,9 @@ int main(int argc, char **argv)
> > return errno;
> > }
> >
> > + printf("\n");
> > + connector_name(sys_name, dpcd_name);
> > +
>
> Why is the output different for one vs. all devices dumping? Dumping one
> specified device should look exactly the same as dumping all devices
> when there's just one available device. Maybe this shouldn't be
> duplicated. Maybe the dump path shouldn't be in *any* way different for
> multiple vs one device. Maybe you could write a dump wrapper that takes
> the aux dev name pattern as input, and in the specified case it should
> only match one. Would make the whole thing much neater.
>
> BR,
> Jani.
>
My thought was that at this point, it wont be a dump anymore.
I meant this specifically for reads/writes of byte(s), to a specific device.
That's why I changed the connector_name() to include printing the dpcd_name
(but that's just not right). But, yea, the idea was to make this look different
than a regular dump of all registers, b/c here we just want to print the connector
name for the device we are looking at.

Thanks for the review Jani.

- Tarun
> > switch (dpcd.cmd) {
> > case READ:
> > ret = dpcd_read(fd, dpcd.rw.offset, dpcd.rw.count);
>
> --
> Jani Nikula, Intel Open Source Graphics Center