Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2012 Intel Corporation
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0020  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0021  * IN THE SOFTWARE.
0022  *
0023  * Authors:
0024  *    Ben Widawsky <ben@bwidawsk.net>
0025  *
0026  */
0027 
0028 #include <linux/device.h>
0029 #include <linux/module.h>
0030 #include <linux/stat.h>
0031 #include <linux/sysfs.h>
0032 
0033 #include "gt/intel_gt_regs.h"
0034 #include "gt/intel_rc6.h"
0035 #include "gt/intel_rps.h"
0036 #include "gt/sysfs_engines.h"
0037 
0038 #include "i915_drv.h"
0039 #include "i915_sysfs.h"
0040 #include "intel_pm.h"
0041 
0042 struct drm_i915_private *kdev_minor_to_i915(struct device *kdev)
0043 {
0044     struct drm_minor *minor = dev_get_drvdata(kdev);
0045     return to_i915(minor->dev);
0046 }
0047 
0048 static int l3_access_valid(struct drm_i915_private *i915, loff_t offset)
0049 {
0050     if (!HAS_L3_DPF(i915))
0051         return -EPERM;
0052 
0053     if (!IS_ALIGNED(offset, sizeof(u32)))
0054         return -EINVAL;
0055 
0056     if (offset >= GEN7_L3LOG_SIZE)
0057         return -ENXIO;
0058 
0059     return 0;
0060 }
0061 
0062 static ssize_t
0063 i915_l3_read(struct file *filp, struct kobject *kobj,
0064          struct bin_attribute *attr, char *buf,
0065          loff_t offset, size_t count)
0066 {
0067     struct device *kdev = kobj_to_dev(kobj);
0068     struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
0069     int slice = (int)(uintptr_t)attr->private;
0070     int ret;
0071 
0072     ret = l3_access_valid(i915, offset);
0073     if (ret)
0074         return ret;
0075 
0076     count = round_down(count, sizeof(u32));
0077     count = min_t(size_t, GEN7_L3LOG_SIZE - offset, count);
0078     memset(buf, 0, count);
0079 
0080     spin_lock(&i915->gem.contexts.lock);
0081     if (i915->l3_parity.remap_info[slice])
0082         memcpy(buf,
0083                i915->l3_parity.remap_info[slice] + offset / sizeof(u32),
0084                count);
0085     spin_unlock(&i915->gem.contexts.lock);
0086 
0087     return count;
0088 }
0089 
0090 static ssize_t
0091 i915_l3_write(struct file *filp, struct kobject *kobj,
0092           struct bin_attribute *attr, char *buf,
0093           loff_t offset, size_t count)
0094 {
0095     struct device *kdev = kobj_to_dev(kobj);
0096     struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
0097     int slice = (int)(uintptr_t)attr->private;
0098     u32 *remap_info, *freeme = NULL;
0099     struct i915_gem_context *ctx;
0100     int ret;
0101 
0102     ret = l3_access_valid(i915, offset);
0103     if (ret)
0104         return ret;
0105 
0106     if (count < sizeof(u32))
0107         return -EINVAL;
0108 
0109     remap_info = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
0110     if (!remap_info)
0111         return -ENOMEM;
0112 
0113     spin_lock(&i915->gem.contexts.lock);
0114 
0115     if (i915->l3_parity.remap_info[slice]) {
0116         freeme = remap_info;
0117         remap_info = i915->l3_parity.remap_info[slice];
0118     } else {
0119         i915->l3_parity.remap_info[slice] = remap_info;
0120     }
0121 
0122     count = round_down(count, sizeof(u32));
0123     memcpy(remap_info + offset / sizeof(u32), buf, count);
0124 
0125     /* NB: We defer the remapping until we switch to the context */
0126     list_for_each_entry(ctx, &i915->gem.contexts.list, link)
0127         ctx->remap_slice |= BIT(slice);
0128 
0129     spin_unlock(&i915->gem.contexts.lock);
0130     kfree(freeme);
0131 
0132     /*
0133      * TODO: Ideally we really want a GPU reset here to make sure errors
0134      * aren't propagated. Since I cannot find a stable way to reset the GPU
0135      * at this point it is left as a TODO.
0136     */
0137 
0138     return count;
0139 }
0140 
0141 static const struct bin_attribute dpf_attrs = {
0142     .attr = {.name = "l3_parity", .mode = (S_IRUSR | S_IWUSR)},
0143     .size = GEN7_L3LOG_SIZE,
0144     .read = i915_l3_read,
0145     .write = i915_l3_write,
0146     .mmap = NULL,
0147     .private = (void *)0
0148 };
0149 
0150 static const struct bin_attribute dpf_attrs_1 = {
0151     .attr = {.name = "l3_parity_slice_1", .mode = (S_IRUSR | S_IWUSR)},
0152     .size = GEN7_L3LOG_SIZE,
0153     .read = i915_l3_read,
0154     .write = i915_l3_write,
0155     .mmap = NULL,
0156     .private = (void *)1
0157 };
0158 
0159 #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
0160 
0161 static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
0162                 struct bin_attribute *attr, char *buf,
0163                 loff_t off, size_t count)
0164 {
0165 
0166     struct device *kdev = kobj_to_dev(kobj);
0167     struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
0168     struct i915_gpu_coredump *gpu;
0169     ssize_t ret = 0;
0170 
0171     /*
0172      * FIXME: Concurrent clients triggering resets and reading + clearing
0173      * dumps can cause inconsistent sysfs reads when a user calls in with a
0174      * non-zero offset to complete a prior partial read but the
0175      * gpu_coredump has been cleared or replaced.
0176      */
0177 
0178     gpu = i915_first_error_state(i915);
0179     if (IS_ERR(gpu)) {
0180         ret = PTR_ERR(gpu);
0181     } else if (gpu) {
0182         ret = i915_gpu_coredump_copy_to_buffer(gpu, buf, off, count);
0183         i915_gpu_coredump_put(gpu);
0184     } else {
0185         const char *str = "No error state collected\n";
0186         size_t len = strlen(str);
0187 
0188         if (off < len) {
0189             ret = min_t(size_t, count, len - off);
0190             memcpy(buf, str + off, ret);
0191         }
0192     }
0193 
0194     return ret;
0195 }
0196 
0197 static ssize_t error_state_write(struct file *file, struct kobject *kobj,
0198                  struct bin_attribute *attr, char *buf,
0199                  loff_t off, size_t count)
0200 {
0201     struct device *kdev = kobj_to_dev(kobj);
0202     struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
0203 
0204     drm_dbg(&dev_priv->drm, "Resetting error state\n");
0205     i915_reset_error_state(dev_priv);
0206 
0207     return count;
0208 }
0209 
0210 static const struct bin_attribute error_state_attr = {
0211     .attr.name = "error",
0212     .attr.mode = S_IRUSR | S_IWUSR,
0213     .size = 0,
0214     .read = error_state_read,
0215     .write = error_state_write,
0216 };
0217 
0218 static void i915_setup_error_capture(struct device *kdev)
0219 {
0220     if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr))
0221         DRM_ERROR("error_state sysfs setup failed\n");
0222 }
0223 
0224 static void i915_teardown_error_capture(struct device *kdev)
0225 {
0226     sysfs_remove_bin_file(&kdev->kobj, &error_state_attr);
0227 }
0228 #else
0229 static void i915_setup_error_capture(struct device *kdev) {}
0230 static void i915_teardown_error_capture(struct device *kdev) {}
0231 #endif
0232 
0233 void i915_setup_sysfs(struct drm_i915_private *dev_priv)
0234 {
0235     struct device *kdev = dev_priv->drm.primary->kdev;
0236     int ret;
0237 
0238     if (HAS_L3_DPF(dev_priv)) {
0239         ret = device_create_bin_file(kdev, &dpf_attrs);
0240         if (ret)
0241             drm_err(&dev_priv->drm,
0242                 "l3 parity sysfs setup failed\n");
0243 
0244         if (NUM_L3_SLICES(dev_priv) > 1) {
0245             ret = device_create_bin_file(kdev,
0246                              &dpf_attrs_1);
0247             if (ret)
0248                 drm_err(&dev_priv->drm,
0249                     "l3 parity slice 1 setup failed\n");
0250         }
0251     }
0252 
0253     dev_priv->sysfs_gt = kobject_create_and_add("gt", &kdev->kobj);
0254     if (!dev_priv->sysfs_gt)
0255         drm_warn(&dev_priv->drm,
0256              "failed to register GT sysfs directory\n");
0257 
0258     i915_setup_error_capture(kdev);
0259 
0260     intel_engines_add_sysfs(dev_priv);
0261 }
0262 
0263 void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
0264 {
0265     struct device *kdev = dev_priv->drm.primary->kdev;
0266 
0267     i915_teardown_error_capture(kdev);
0268 
0269     device_remove_bin_file(kdev,  &dpf_attrs_1);
0270     device_remove_bin_file(kdev,  &dpf_attrs);
0271 
0272     kobject_put(dev_priv->sysfs_gt);
0273 }