From patchwork Mon Dec 4 15:02:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Lionel Landwerlin X-Patchwork-Id: 10090601 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 30B0960327 for ; Mon, 4 Dec 2017 15:03:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 126B829045 for ; Mon, 4 Dec 2017 15:03:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 06F0328E6D; Mon, 4 Dec 2017 15:03:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4BC1F28E6D for ; Mon, 4 Dec 2017 15:03:12 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5FD9E6E391; Mon, 4 Dec 2017 15:02:53 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by gabe.freedesktop.org (Postfix) with ESMTPS id 1F79F6E382; Mon, 4 Dec 2017 15:02:51 +0000 (UTC) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 04 Dec 2017 07:02:51 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.45,359,1508828400"; d="scan'208"; a="1251705823" Received: from delly.ld.intel.com ([10.103.238.204]) by fmsmga002.fm.intel.com with ESMTP; 04 Dec 2017 07:02:49 -0800 From: Lionel Landwerlin To: intel-gfx@lists.freedesktop.org Subject: [PATCH v6 4/5] drm/i915: expose engine availability through sysfs Date: Mon, 4 Dec 2017 15:02:37 +0000 Message-Id: <20171204150238.28011-5-lionel.g.landwerlin@intel.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20171204150238.28011-1-lionel.g.landwerlin@intel.com> References: <20171204150238.28011-1-lionel.g.landwerlin@intel.com> MIME-Version: 1.0 Cc: dri-devel@lists.freedesktop.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP This enables userspace to discover the engines available on the GPU. Here is the layout on a Skylake GT4: /sys/devices/pci0000:00/0000:00:02.0/drm/card0/gt/ └── engines ├── bcs │   └── 0 │   ├── capabilities │   ├── class │   ├── id │   └── instance ├── rcs │   └── 0 │   ├── capabilities │   ├── class │   ├── id │   └── instance ├── vcs │   ├── 0 │   │   ├── capabilities │   │   │   └── hevc │   │   ├── class │   │   ├── id │   │   └── instance │   └── 1 │   ├── capabilities │   ├── class │   ├── id │   └── instance └── vecs └── 0 ├── capabilities ├── class ├── id └── instance Instance is the instance number of the engine for a particular class : $ cat /sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/bcs/0/instance 0 Id is a global id used from submitting commands from userspace through execbuf : $ cat /sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/bcs/0/id 3 Class maps to enum drm_i915_gem_engine_class in i915_drm.h : $ cat /sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/bcs/0/class 1 Further capabilities can be added later as attributes of each engine. v2: Add capabilities sub directory (Tvrtko) Move engines directory to drm/card/gt (Chris) v3: Move engines to drm/card/gt/engines/ (Tvrtko) Add instance attribute to engines (Tvrtko) v4: Fix dev_priv->gt_topology.engines_classes_kobj size (Lionel) Signed-off-by: Lionel Landwerlin --- drivers/gpu/drm/i915/i915_drv.h | 6 ++ drivers/gpu/drm/i915/i915_sysfs.c | 178 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_engine_cs.c | 12 +++ drivers/gpu/drm/i915/intel_ringbuffer.h | 4 + 4 files changed, 200 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0a8e8a3772e5..893ecb0d4639 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2731,6 +2731,12 @@ struct drm_i915_private { } oa; } perf; + struct { + struct kobject gt_kobj; + struct kobject engines_kobj; + struct kobject engines_classes_kobjs[MAX_ENGINE_CLASS + 1]; + } gt_topology; + /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ struct { void (*resume)(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index c74a20b80182..d8ec8ec51cca 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -570,6 +570,178 @@ static void i915_setup_error_capture(struct device *kdev) {} static void i915_teardown_error_capture(struct device *kdev) {} #endif +static struct attribute engine_class_attr = { + .name = "class", + .mode = 0444, +}; + +static struct attribute engine_id_attr = { + .name = "id", + .mode = 0444, +}; + +static struct attribute engine_instance_attr = { + .name = "instance", + .mode = 0444, +}; + +static ssize_t +show_engine_attr(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct intel_engine_cs *engine = + container_of(kobj, struct intel_engine_cs, instance_kobj); + + if (attr == &engine_class_attr) + return sprintf(buf, "%hhu\n", engine->uabi_class); + if (attr == &engine_id_attr) + return sprintf(buf, "%hhu\n", engine->uabi_id); + if (attr == &engine_instance_attr) + return sprintf(buf, "%hhu\n", engine->instance); + return sprintf(buf, "\n"); +} + +static const struct sysfs_ops engine_ops = { + .show = show_engine_attr, +}; + +static struct kobj_type engine_type = { + .sysfs_ops = &engine_ops, +}; + +static struct attribute engine_capability_hevc_attr = { + .name = "hevc", + .mode = 0444, +}; + +static ssize_t +show_engine_capabilities_attr(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct intel_engine_cs *engine = + container_of(kobj, struct intel_engine_cs, capabilities_kobj); + + if (attr == &engine_capability_hevc_attr) + return sprintf(buf, "%i\n", INTEL_GEN(engine->i915) >= 8); + return sprintf(buf, "\n"); +} + +static const struct sysfs_ops engine_capabilities_ops = { + .show = show_engine_capabilities_attr, +}; + +static struct kobj_type engine_capabilities_type = { + .sysfs_ops = &engine_capabilities_ops, +}; + +static int i915_setup_engines_sysfs(struct drm_i915_private *dev_priv, + struct kobject *gt_kobj) +{ + struct intel_engine_cs *engine_for_class, *engine; + enum intel_engine_id id_for_class, id; + struct kobject *engines_kobj = &dev_priv->gt_topology.engines_kobj; + bool registred[MAX_ENGINE_CLASS + 1] = { false, }; + int ret; + + ret = kobject_init_and_add(engines_kobj, gt_kobj->ktype, gt_kobj, + "engines"); + if (ret) + return ret; + + for_each_engine(engine_for_class, dev_priv, id_for_class) { + struct kobject *engine_class_kobj = + &dev_priv->gt_topology.engines_classes_kobjs[engine_for_class->class]; + + if (registred[engine_for_class->class]) + continue; + + registred[engine_for_class->class] = true; + + ret = kobject_init_and_add(engine_class_kobj, + engines_kobj->ktype, + engines_kobj, + intel_engine_get_class_name(engine_for_class)); + if (ret) + return ret; + + for_each_engine(engine, dev_priv, id) { + if (engine->class != engine_for_class->class) + continue; + + ret = kobject_init_and_add(&engine->instance_kobj, + &engine_type, + engine_class_kobj, + "%d", engine->instance); + if (ret) + return ret; + + ret = sysfs_create_file(&engine->instance_kobj, + &engine_class_attr); + if (ret) + return ret; + ret = sysfs_create_file(&engine->instance_kobj, + &engine_id_attr); + if (ret) + return ret; + ret = sysfs_create_file(&engine->instance_kobj, + &engine_instance_attr); + if (ret) + return ret; + + ret = kobject_init_and_add(&engine->capabilities_kobj, + &engine_capabilities_type, + &engine->instance_kobj, + "capabilities"); + if (ret) + return ret; + + if (engine->id == VCS) { + ret = sysfs_create_file(&engine->capabilities_kobj, + &engine_capability_hevc_attr); + if (ret) + return ret; + } + } + } + + return 0; +} + +static void i915_teardown_engines_sysfs(struct drm_i915_private *dev_priv) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + + for_each_engine(engine, dev_priv, id) { + sysfs_remove_file(&engine->instance_kobj, &engine_class_attr); + sysfs_remove_file(&engine->instance_kobj, &engine_id_attr); + sysfs_remove_file(&engine->instance_kobj, &engine_instance_attr); + sysfs_remove_file(&engine->capabilities_kobj, + &engine_capability_hevc_attr); + } +} + +static int i915_setup_gt_sysfs(struct drm_i915_private *dev_priv, + struct device *kdev) +{ + int ret; + + ret = kobject_init_and_add(&dev_priv->gt_topology.gt_kobj, + kdev->kobj.ktype, + &kdev->kobj, + "gt"); + if (ret) + return ret; + + return i915_setup_engines_sysfs(dev_priv, &dev_priv->gt_topology.gt_kobj); +} + +static void i915_teardown_gt_sysfs(struct drm_i915_private *dev_priv) +{ + i915_teardown_engines_sysfs(dev_priv); + + kobject_get(&dev_priv->gt_topology.gt_kobj); + kobject_del(&dev_priv->gt_topology.gt_kobj); +} + void i915_setup_sysfs(struct drm_i915_private *dev_priv) { struct device *kdev = dev_priv->drm.primary->kdev; @@ -616,6 +788,10 @@ void i915_setup_sysfs(struct drm_i915_private *dev_priv) if (ret) DRM_ERROR("RPS sysfs setup failed\n"); + ret = i915_setup_gt_sysfs(dev_priv, kdev); + if (ret) + DRM_ERROR("GT sysfs setup failed\n"); + i915_setup_error_capture(kdev); } @@ -625,6 +801,8 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv) i915_teardown_error_capture(kdev); + i915_teardown_gt_sysfs(dev_priv); + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) sysfs_remove_files(&kdev->kobj, vlv_attrs); else diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 86d4c85c8725..7bda1c283f2c 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -131,6 +131,18 @@ static const struct engine_info intel_engines[] = { }, }; +/** + * intel_engine_get_class_name() - return the name of the class for an engine + * @engine: engine + * + * Return: a string naming the class of the engine + */ +const char * +intel_engine_get_class_name(struct intel_engine_cs *engine) +{ + return intel_engine_classes[engine->class].name; +} + /** * ___intel_engine_context_size() - return the size of the context for an engine * @dev_priv: i915 device private diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 9c4434438965..dc4eeb897407 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -282,6 +282,9 @@ struct intel_engine_cs { struct drm_i915_private *i915; char name[INTEL_ENGINE_CS_MAX_NAME]; + struct kobject instance_kobj; + struct kobject capabilities_kobj; + enum intel_engine_id id; unsigned int hw_id; unsigned int guc_id; @@ -995,6 +998,7 @@ gen8_emit_ggtt_write(u32 *cs, u32 value, u32 gtt_offset) return cs; } +const char *intel_engine_get_class_name(struct intel_engine_cs *engine); bool intel_engine_is_idle(struct intel_engine_cs *engine); bool intel_engines_are_idle(struct drm_i915_private *dev_priv);