From patchwork Mon Dec 4 15:02:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Lionel Landwerlin X-Patchwork-Id: 10090603 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 89E6560327 for ; Mon, 4 Dec 2017 15:03:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 70EB029144 for ; Mon, 4 Dec 2017 15:03:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 65AD728F2C; Mon, 4 Dec 2017 15:03:23 +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=ham 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 86D282913B for ; Mon, 4 Dec 2017 15:03:22 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E84496E394; 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 6C3C96E38B; Mon, 4 Dec 2017 15:02:52 +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:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.45,359,1508828400"; d="scan'208"; a="1251705835" Received: from delly.ld.intel.com ([10.103.238.204]) by fmsmga002.fm.intel.com with ESMTP; 04 Dec 2017 07:02:51 -0800 From: Lionel Landwerlin To: intel-gfx@lists.freedesktop.org Subject: [PATCH v6 5/5] drm/i915: expose EU topology through sysfs Date: Mon, 4 Dec 2017 15:02:38 +0000 Message-Id: <20171204150238.28011-6-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 With the introduction of asymetric slices in CNL, we cannot rely on the previous SUBSLICE_MASK getparam. Here we introduce a more detailed way of querying the Gen's GPU topology that doesn't aggregate numbers. This is essential for monitoring parts of the GPU with the OA unit, because signals need to be accounted properly based on whether part of the GPU has been fused off. The current aggregated numbers like EU_TOTAL do not gives us sufficient information. Here is the sysfs layout on a Skylake GT4 : /sys/devices/pci0000:00/0000:00:02.0/drm/card0/gt/engines/rcs/topology/ ├── max_eus_per_subslice ├── max_slices ├── max_subslices_per_slice ├── slice0 │   ├── subslice0 │   │   └── eus_enabled_mask │   ├── subslice1 │   │   └── eus_enabled_mask │   ├── subslice2 │   │   └── eus_enabled_mask │   ├── subslice3 │   │   └── eus_enabled_mask │   └── subslices_enabled_mask ├── slice1 │   ├── subslice0 │   │   └── eus_enabled_mask │   ├── subslice1 │   │   └── eus_enabled_mask │   ├── subslice2 │   │   └── eus_enabled_mask │   ├── subslice3 │   │   └── eus_enabled_mask │   └── subslices_enabled_mask ├── slice2 │   ├── subslice0 │   │   └── eus_enabled_mask │   ├── subslice1 │   │   └── eus_enabled_mask │   ├── subslice2 │   │   └── eus_enabled_mask │   ├── subslice3 │   │   └── eus_enabled_mask │   └── subslices_enabled_mask └── slices_enabled_mask Each enabled_mask file gives us a mask of the enabled units : $ cat /sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/rcs/topology/slices_enabled_mask 0x7 $ cat /sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/rcs/topology/slice2/subslice1/eus_enabled_mask 0xff max_eus_per_subslice/max_slices/max_subslices_per_slice are useful numbers for userspace to build up a n-dimensional representation of the device so that it can allocated upfront and filled up while reading through each of the slices/subslices. v2: Move topology below rcs engine (Chris) Add max_eus_per_subslice/max_slices/max_subslices_per_slice (Lionel) v3: Rename enabled_mask (Lionel) v4: Move slices to drm/card/gt/rcs/topology (Tvrtko) Signed-off-by: Lionel Landwerlin --- drivers/gpu/drm/i915/i915_drv.h | 27 +++++ drivers/gpu/drm/i915/i915_sysfs.c | 208 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 893ecb0d4639..fbdfd59ed1bd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2260,6 +2260,24 @@ struct intel_cdclk_state { u8 voltage_level; }; +struct intel_topology_kobject { + struct kobject kobj; + struct drm_i915_private *dev_priv; +}; + +struct intel_slice_kobject { + struct kobject kobj; + struct drm_i915_private *dev_priv; + u8 slice_index; +}; + +struct intel_subslice_kobject { + struct kobject kobj; + struct drm_i915_private *dev_priv; + u8 slice_index; + u8 subslice_index; +}; + struct drm_i915_private { struct drm_device drm; @@ -2735,6 +2753,15 @@ struct drm_i915_private { struct kobject gt_kobj; struct kobject engines_kobj; struct kobject engines_classes_kobjs[MAX_ENGINE_CLASS + 1]; + struct kobject topology_kobj; + + struct sysfs_slice { + struct intel_slice_kobject kobj; + + struct sysfs_subslice { + struct intel_subslice_kobject kobj; + } subslices[GEN_MAX_SUBSLICES]; + } slices[GEN_MAX_SLICES]; } gt_topology; /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index d8ec8ec51cca..b277338ab3fb 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -570,6 +570,205 @@ static void i915_setup_error_capture(struct device *kdev) {} static void i915_teardown_error_capture(struct device *kdev) {} #endif +static struct attribute slices_enabled_mask_attr = { + .name = "slices_enabled_mask", + .mode = 0444, +}; + +static struct attribute subslices_enabled_mask_attr = { + .name = "subslices_enabled_mask", + .mode = 0444, +}; + +static struct attribute eus_enabled_mask_attr = { + .name = "eus_enabled_mask", + .mode = 0444, +}; + +static struct attribute max_slices_attr = { + .name = "max_slices", + .mode = 0444, +}; + +static struct attribute max_subslices_per_slice_attr = { + .name = "max_subslices_per_slice", + .mode = 0444, +}; + +static struct attribute max_eus_per_subslice_attr = { + .name = "max_eus_per_subslice", + .mode = 0444, +}; + +static ssize_t +show_topology_attr(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct drm_i915_private *dev_priv = + container_of(kobj, struct drm_i915_private, gt_topology.topology_kobj); + const struct sseu_dev_info *sseu = &INTEL_INFO(dev_priv)->sseu; + + if (attr == &slices_enabled_mask_attr) + return sprintf(buf, "0x%hhx\n", sseu->slice_mask); + if (attr == &max_eus_per_subslice_attr) + return sprintf(buf, "%hhd\n", sseu->max_eus_per_subslice); + if (attr == &max_subslices_per_slice_attr) + return sprintf(buf, "%hhd\n", sseu->max_subslices); + if (attr == &max_slices_attr) + return sprintf(buf, "%hhd\n", sseu->max_slices); + return sprintf(buf, "\n"); +} + +static const struct sysfs_ops topology_ops = { + .show = show_topology_attr, +}; + +static struct kobj_type topology_type = { + .sysfs_ops = &topology_ops, +}; + +static ssize_t +show_slice_attr(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct intel_slice_kobject *kobj_wrapper = + container_of(kobj, struct intel_slice_kobject, kobj); + struct drm_i915_private *dev_priv = kobj_wrapper->dev_priv; + const struct sseu_dev_info *sseu = &INTEL_INFO(dev_priv)->sseu; + + if (attr == &subslices_enabled_mask_attr) { + return sprintf(buf, "0x%hhx\n", + sseu->subslices_mask[kobj_wrapper->slice_index]); + } + return sprintf(buf, "\n"); +} + +static const struct sysfs_ops slice_ops = { + .show = show_slice_attr, +}; + +static struct kobj_type slice_type = { + .sysfs_ops = &slice_ops, +}; + +static ssize_t +show_subslice_attr(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct intel_subslice_kobject *kobj_wrapper = + container_of(kobj, struct intel_subslice_kobject, kobj); + struct drm_i915_private *dev_priv = kobj_wrapper->dev_priv; + const struct sseu_dev_info *sseu = &INTEL_INFO(dev_priv)->sseu; + int subslice_stride = ALIGN(sseu->max_eus_per_subslice, 8) / 8; + int slice_stride = sseu->max_subslices * subslice_stride; + + if (attr == &eus_enabled_mask_attr) + return sprintf(buf, "0x%hhx\n", + sseu->eu_mask[kobj_wrapper->slice_index * slice_stride + + kobj_wrapper->subslice_index * subslice_stride]); + return sprintf(buf, "\n"); +} + +static const struct sysfs_ops subslice_ops = { + .show = show_subslice_attr, +}; + +static struct kobj_type subslice_type = { + .sysfs_ops = &subslice_ops, +}; + +static int i915_setup_rcs_topology_sysfs(struct drm_i915_private *dev_priv, + struct kobject *engine_class_kobj) +{ + const struct sseu_dev_info *sseu = &INTEL_INFO(dev_priv)->sseu; + struct kobject *topology_kobj = &dev_priv->gt_topology.topology_kobj; + int ret, s, ss; + + ret = kobject_init_and_add(topology_kobj, &topology_type, + engine_class_kobj, "topology"); + if (ret) + return ret; + + ret = sysfs_create_file(topology_kobj, &slices_enabled_mask_attr); + if (ret) + return ret; + + ret = sysfs_create_file(topology_kobj, &max_slices_attr); + if (ret) + return ret; + + ret = sysfs_create_file(topology_kobj, &max_subslices_per_slice_attr); + if (ret) + return ret; + + ret = sysfs_create_file(topology_kobj, &max_eus_per_subslice_attr); + if (ret) + return ret; + + for (s = 0; s < sseu->max_slices; s++) { + struct intel_slice_kobject *slice_kobj = + &dev_priv->gt_topology.slices[s].kobj; + + slice_kobj->dev_priv = dev_priv; + slice_kobj->slice_index = s; + ret = kobject_init_and_add(&slice_kobj->kobj, &slice_type, + topology_kobj, "slice%i", s); + if (ret) + return ret; + + ret = sysfs_create_file(&slice_kobj->kobj, + &subslices_enabled_mask_attr); + if (ret) + return ret; + + for (ss = 0; ss < sseu->max_subslices; ss++) { + struct intel_subslice_kobject *subslice_kobj = + &dev_priv->gt_topology.slices[s].subslices[ss].kobj; + + subslice_kobj->dev_priv = dev_priv; + subslice_kobj->slice_index = s; + subslice_kobj->subslice_index = ss; + ret = kobject_init_and_add(&subslice_kobj->kobj, + &subslice_type, + &slice_kobj->kobj, + "subslice%i", ss); + if (ret) + return ret; + + ret = sysfs_create_file(&subslice_kobj->kobj, + &eus_enabled_mask_attr); + if (ret) + return ret; + } + } + + return 0; +} + +static void i915_teardown_rcs_topology_sysfs(struct drm_i915_private *dev_priv) +{ + const struct sseu_dev_info *sseu = &INTEL_INFO(dev_priv)->sseu; + struct kobject *topology_kobj = &dev_priv->gt_topology.topology_kobj; + int s, ss; + + for (s = 0; s < sseu->max_slices; s++) { + struct intel_slice_kobject *slice_kobj = + &dev_priv->gt_topology.slices[s].kobj; + + for (ss = 0; ss < sseu->max_subslices; ss++) { + struct intel_subslice_kobject *subslice_kobj = + &dev_priv->gt_topology.slices[s].subslices[ss].kobj; + + sysfs_remove_file(&subslice_kobj->kobj, + &eus_enabled_mask_attr); + } + + sysfs_remove_file(&slice_kobj->kobj, + &subslices_enabled_mask_attr); + } + sysfs_remove_file(topology_kobj, &slices_enabled_mask_attr); + sysfs_remove_file(topology_kobj, &max_eus_per_subslice_attr); + sysfs_remove_file(topology_kobj, &max_subslices_per_slice_attr); + sysfs_remove_file(topology_kobj, &max_slices_attr); +} + static struct attribute engine_class_attr = { .name = "class", .mode = 0444, @@ -662,6 +861,13 @@ static int i915_setup_engines_sysfs(struct drm_i915_private *dev_priv, if (ret) return ret; + if (engine_for_class->class == RENDER_CLASS) { + ret = i915_setup_rcs_topology_sysfs(dev_priv, + engine_class_kobj); + if (ret) + return ret; + } + for_each_engine(engine, dev_priv, id) { if (engine->class != engine_for_class->class) continue; @@ -710,6 +916,8 @@ static void i915_teardown_engines_sysfs(struct drm_i915_private *dev_priv) struct intel_engine_cs *engine; enum intel_engine_id id; + i915_teardown_rcs_topology_sysfs(dev_priv); + 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);