1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
// SPDX-License-Identifier: MIT
/*
* Copyright © 2020 Intel Corporation
*/
#include <linux/fs.h>
#include <drm/drm_print.h>
#include "gt/intel_gt_debugfs.h"
#include "intel_guc.h"
#include "intel_guc_log.h"
#include "intel_guc_log_debugfs.h"
#include "intel_uc.h"
static u32 obj_to_guc_log_dump_size(struct drm_i915_gem_object *obj)
{
u32 size;
if (!obj)
return PAGE_SIZE;
/* "0x%08x 0x%08x 0x%08x 0x%08x\n" => 16 bytes -> 44 chars => x2.75 */
size = ((obj->base.size * 11) + 3) / 4;
/* Add padding for final blank line, any extra header info, etc. */
size = PAGE_ALIGN(size + PAGE_SIZE);
return size;
}
static u32 guc_log_dump_size(struct intel_guc_log *log)
{
struct intel_guc *guc = log_to_guc(log);
if (!intel_guc_is_supported(guc))
return PAGE_SIZE;
if (!log->vma)
return PAGE_SIZE;
return obj_to_guc_log_dump_size(log->vma->obj);
}
static int guc_log_dump_show(struct seq_file *m, void *data)
{
struct drm_printer p = drm_seq_file_printer(m);
int ret;
ret = intel_guc_log_dump(m->private, &p, false);
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && seq_has_overflowed(m))
pr_warn_once("preallocated size:%zx for %s exceeded\n",
m->size, __func__);
return ret;
}
DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE_WITH_SIZE(guc_log_dump, guc_log_dump_size);
static u32 guc_load_err_dump_size(struct intel_guc_log *log)
{
struct intel_guc *guc = log_to_guc(log);
struct intel_uc *uc = container_of(guc, struct intel_uc, guc);
if (!intel_guc_is_supported(guc))
return PAGE_SIZE;
return obj_to_guc_log_dump_size(uc->load_err_log);
}
static int guc_load_err_log_dump_show(struct seq_file *m, void *data)
{
struct drm_printer p = drm_seq_file_printer(m);
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && seq_has_overflowed(m))
pr_warn_once("preallocated size:%zx for %s exceeded\n",
m->size, __func__);
return intel_guc_log_dump(m->private, &p, true);
}
DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE_WITH_SIZE(guc_load_err_log_dump, guc_load_err_dump_size);
static int guc_log_level_get(void *data, u64 *val)
{
struct intel_guc_log *log = data;
if (!log->vma)
return -ENODEV;
*val = intel_guc_log_get_level(log);
return 0;
}
static int guc_log_level_set(void *data, u64 val)
{
struct intel_guc_log *log = data;
if (!log->vma)
return -ENODEV;
return intel_guc_log_set_level(log, val);
}
DEFINE_SIMPLE_ATTRIBUTE(guc_log_level_fops,
guc_log_level_get, guc_log_level_set,
"%lld\n");
static int guc_log_relay_open(struct inode *inode, struct file *file)
{
struct intel_guc_log *log = inode->i_private;
if (!intel_guc_is_ready(log_to_guc(log)))
return -ENODEV;
file->private_data = log;
return intel_guc_log_relay_open(log);
}
static ssize_t
guc_log_relay_write(struct file *filp,
const char __user *ubuf,
size_t cnt,
loff_t *ppos)
{
struct intel_guc_log *log = filp->private_data;
int val;
int ret;
ret = kstrtoint_from_user(ubuf, cnt, 0, &val);
if (ret < 0)
return ret;
/*
* Enable and start the guc log relay on value of 1.
* Flush log relay for any other value.
*/
if (val == 1)
ret = intel_guc_log_relay_start(log);
else
intel_guc_log_relay_flush(log);
return ret ?: cnt;
}
static int guc_log_relay_release(struct inode *inode, struct file *file)
{
struct intel_guc_log *log = inode->i_private;
intel_guc_log_relay_close(log);
return 0;
}
static const struct file_operations guc_log_relay_fops = {
.owner = THIS_MODULE,
.open = guc_log_relay_open,
.write = guc_log_relay_write,
.release = guc_log_relay_release,
};
void intel_guc_log_debugfs_register(struct intel_guc_log *log,
struct dentry *root)
{
static const struct intel_gt_debugfs_file files[] = {
{ "guc_log_dump", &guc_log_dump_fops, NULL },
{ "guc_load_err_log_dump", &guc_load_err_log_dump_fops, NULL },
{ "guc_log_level", &guc_log_level_fops, NULL },
{ "guc_log_relay", &guc_log_relay_fops, NULL },
};
if (!intel_guc_is_supported(log_to_guc(log)))
return;
intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), log);
}
|