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