On 09.11.2016 19:08, Emil Velikov wrote: > From: Emil Velikov <emil.velikov at collabora.com> > > Parsing config sysfs file wakes up the device. The latter of which may > be slow and isn't required to begin with. > > Reading through config is/was required since the revision is not > available by other means, although with a kernel patch in the way that > is about to change. > > Since returning 0 when one might expect a valid value is a no-go add a > workaround drmDeviceUseRevisionFile() which one can use to say "I don't > care if the revision file returns 0." > > v2: Complete rework - add new API to control the method, instead of > changing it underneat the users' feet. > > Cc: Michel Dänzer <michel.daenzer at amd.com> > Cc: Mauro Santos <registo.mailling at gmail.com> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98502 > Signed-off-by: Emil Velikov <emil.velikov at collabora.com> > --- > I don't have a strong preference for/against this or v1. > > With this Mesa will require a 2 line patch. With v1 things will get > fixed magically, when rebuilt against newer libdrm. > > Mauro I'll send the mesa patch in a second. Feel free to give it a spin. > > Thanks > --- > xf86drm.c | 70 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- > xf86drm.h | 11 ++++++++++ > 2 files changed, 78 insertions(+), 3 deletions(-) > > diff --git a/xf86drm.c b/xf86drm.c > index 52add5e..676effc 100644 > --- a/xf86drm.c > +++ b/xf86drm.c > @@ -113,6 +113,13 @@ void drmSetServerInfo(drmServerInfoPtr info) > drm_server_info = info; > } > > +static bool use_revision_file; > + > +void drmDeviceUseRevisionFile(void) > +{ > + use_revision_file = true; > +}
I think this API of setting a magic hidden global variable is really nasty. Can we add new drmGetDevice[s] entry points with a flags parameter and a flag (per Michel's suggestion) which says "I don't care about the revision ID"? It kind of sucks because they'll have to get a silly name like drmGetDevice[s]2, but I think that's still better than magic global state. Cheers, Nicolai > + > /** > * Output a message to stderr. > * > @@ -2946,10 +2953,56 @@ static int drmGetMaxNodeName(void) > 3 /* length of the node number */; > } > > -static int drmParsePciDeviceInfo(const char *d_name, > - drmPciDeviceInfoPtr device) > -{ > #ifdef __linux__ > +static int parse_separate_sysfs_files(const char *d_name, > + drmPciDeviceInfoPtr device) > +{ > +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) > + static const char *attrs[] = { > + "revision", /* XXX: make sure it's always first, see note below */ > + "vendor", > + "device", > + "subsystem_vendor", > + "subsystem_device", > + }; > + char path[PATH_MAX + 1]; > + unsigned int data[ARRAY_SIZE(attrs)]; > + FILE *fp; > + int ret; > + > + for (unsigned i = 0; i < ARRAY_SIZE(attrs); i++) { > + snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/%s", > + d_name, attrs[i]); > + fp = fopen(path, "r"); > + if (!fp) { > + /* Note: First we check the revision, since older kernels > + * may not have it. Default to zero in such cases. */ > + if (i == 0) { > + data[i] = 0; > + continue; > + } > + return -errno; > + } > + > + ret = fscanf(fp, "%x", &data[i]); > + fclose(fp); > + if (ret != 1) > + return -errno; > + > + } > + > + device->revision_id = data[0] & 0xff; > + device->vendor_id = data[1] & 0xffff; > + device->device_id = data[2] & 0xffff; > + device->subvendor_id = data[3] & 0xffff; > + device->subdevice_id = data[4] & 0xffff; > + > + return 0; > +} > + > +static int parse_config_sysfs_file(const char *d_name, > + drmPciDeviceInfoPtr device) > +{ > char path[PATH_MAX + 1]; > unsigned char config[64]; > int fd, ret; > @@ -2971,6 +3024,17 @@ static int drmParsePciDeviceInfo(const char *d_name, > device->subdevice_id = config[46] | (config[47] << 8); > > return 0; > +} > +#endif > + > +static int drmParsePciDeviceInfo(const char *d_name, > + drmPciDeviceInfoPtr device) > +{ > +#ifdef __linux__ > + if (use_revision_file) > + return parse_separate_sysfs_files(d_name, device); > + > + return parse_config_sysfs_file(d_name, device); > #else > #warning "Missing implementation of drmParsePciDeviceInfo" > return -EINVAL; > diff --git a/xf86drm.h b/xf86drm.h > index 481d882..d1ebc32 100644 > --- a/xf86drm.h > +++ b/xf86drm.h > @@ -796,6 +796,17 @@ extern void drmFreeDevice(drmDevicePtr *device); > extern int drmGetDevices(drmDevicePtr devices[], int max_devices); > extern void drmFreeDevices(drmDevicePtr devices[], int count); > > + > +/** > + * Force any sequential calls to drmGetDevice/drmGetDevices to use the > + * revision sysfs file instead of config one. The latter wakes up the device > + * if powered off. > + * > + * A value of 0 will be returned for the revision_id field if the sysfs file > + * is missing. DO NOT USE THIS if you depend on a correct revision_id. > + */ > +extern void drmDeviceUseRevisionFile(void); > + > #if defined(__cplusplus) > } > #endif >