1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <linux/debugfs.h> 7 #include <linux/kernel.h> 8 9 #include <drm/drm_drv.h> 10 11 #include "intel_display_debugfs_params.h" 12 #include "i915_drv.h" 13 #include "intel_display_params.h" 14 15 /* int param */ 16 static int intel_display_param_int_show(struct seq_file *m, void *data) 17 { 18 int *value = m->private; 19 20 seq_printf(m, "%d\n", *value); 21 22 return 0; 23 } 24 25 static int intel_display_param_int_open(struct inode *inode, struct file *file) 26 { 27 return single_open(file, intel_display_param_int_show, inode->i_private); 28 } 29 30 static ssize_t intel_display_param_int_write(struct file *file, 31 const char __user *ubuf, size_t len, 32 loff_t *offp) 33 { 34 struct seq_file *m = file->private_data; 35 int *value = m->private; 36 int ret; 37 38 ret = kstrtoint_from_user(ubuf, len, 0, value); 39 if (ret) { 40 /* support boolean values too */ 41 bool b; 42 43 ret = kstrtobool_from_user(ubuf, len, &b); 44 if (!ret) 45 *value = b; 46 } 47 48 return ret ?: len; 49 } 50 51 static const struct file_operations intel_display_param_int_fops = { 52 .owner = THIS_MODULE, 53 .open = intel_display_param_int_open, 54 .read = seq_read, 55 .write = intel_display_param_int_write, 56 .llseek = default_llseek, 57 .release = single_release, 58 }; 59 60 static const struct file_operations intel_display_param_int_fops_ro = { 61 .owner = THIS_MODULE, 62 .open = intel_display_param_int_open, 63 .read = seq_read, 64 .llseek = default_llseek, 65 .release = single_release, 66 }; 67 68 /* unsigned int param */ 69 static int intel_display_param_uint_show(struct seq_file *m, void *data) 70 { 71 unsigned int *value = m->private; 72 73 seq_printf(m, "%u\n", *value); 74 75 return 0; 76 } 77 78 static int intel_display_param_uint_open(struct inode *inode, struct file *file) 79 { 80 return single_open(file, intel_display_param_uint_show, inode->i_private); 81 } 82 83 static ssize_t intel_display_param_uint_write(struct file *file, 84 const char __user *ubuf, size_t len, 85 loff_t *offp) 86 { 87 struct seq_file *m = file->private_data; 88 unsigned int *value = m->private; 89 int ret; 90 91 ret = kstrtouint_from_user(ubuf, len, 0, value); 92 if (ret) { 93 /* support boolean values too */ 94 bool b; 95 96 ret = kstrtobool_from_user(ubuf, len, &b); 97 if (!ret) 98 *value = b; 99 } 100 101 return ret ?: len; 102 } 103 104 static const struct file_operations intel_display_param_uint_fops = { 105 .owner = THIS_MODULE, 106 .open = intel_display_param_uint_open, 107 .read = seq_read, 108 .write = intel_display_param_uint_write, 109 .llseek = default_llseek, 110 .release = single_release, 111 }; 112 113 static const struct file_operations intel_display_param_uint_fops_ro = { 114 .owner = THIS_MODULE, 115 .open = intel_display_param_uint_open, 116 .read = seq_read, 117 .llseek = default_llseek, 118 .release = single_release, 119 }; 120 121 #define RO(mode) (((mode) & 0222) == 0) 122 123 __maybe_unused static struct dentry * 124 intel_display_debugfs_create_int(const char *name, umode_t mode, 125 struct dentry *parent, int *value) 126 { 127 return debugfs_create_file_unsafe(name, mode, parent, value, 128 RO(mode) ? &intel_display_param_int_fops_ro : 129 &intel_display_param_int_fops); 130 } 131 132 __maybe_unused static struct dentry * 133 intel_display_debugfs_create_uint(const char *name, umode_t mode, 134 struct dentry *parent, unsigned int *value) 135 { 136 return debugfs_create_file_unsafe(name, mode, parent, value, 137 RO(mode) ? &intel_display_param_uint_fops_ro : 138 &intel_display_param_uint_fops); 139 } 140 141 #define _intel_display_param_create_file(parent, name, mode, valp) \ 142 do { \ 143 if (mode) \ 144 _Generic(valp, \ 145 bool * : debugfs_create_bool, \ 146 int * : intel_display_debugfs_create_int, \ 147 unsigned int * : intel_display_debugfs_create_uint, \ 148 unsigned long * : debugfs_create_ulong, \ 149 char ** : debugfs_create_str) \ 150 (name, mode, parent, valp); \ 151 } while (0) 152 153 /* add a subdirectory with files for each intel display param */ 154 void intel_display_debugfs_params(struct drm_i915_private *i915) 155 { 156 struct drm_minor *minor = i915->drm.primary; 157 struct dentry *dir; 158 char dirname[16]; 159 160 snprintf(dirname, sizeof(dirname), "%s_params", i915->drm.driver->name); 161 dir = debugfs_lookup(dirname, minor->debugfs_root); 162 if (!dir) 163 dir = debugfs_create_dir(dirname, minor->debugfs_root); 164 if (IS_ERR(dir)) 165 return; 166 167 /* 168 * Note: We could create files for params needing special handling 169 * here. Set mode in params to 0 to skip the generic create file, or 170 * just let the generic create file fail silently with -EEXIST. 171 */ 172 173 #define REGISTER(T, x, unused, mode, ...) _intel_display_param_create_file( \ 174 dir, #x, mode, &i915->display.params.x); 175 INTEL_DISPLAY_PARAMS_FOR_EACH(REGISTER); 176 #undef REGISTER 177 } 178