drm/i915/display: Add framework to add parameters specific to display
authorJouni Högander <jouni.hogander@intel.com>
Tue, 24 Oct 2023 12:40:47 +0000 (15:40 +0300)
committerJouni Högander <jouni.hogander@intel.com>
Thu, 26 Oct 2023 09:13:02 +0000 (12:13 +0300)
Currently all module parameters are handled by i915_param.c/h. This
is a problem for display parameters when Xe driver is used. Add
a mechanism to add parameters specific to the display. This is mainly
copied from i915_[debugfs]_params.[ch]. Parameters are not yet moved. This
is done by subsequent patches.

v2:
  - Drop unused predefinition (dentry)
  - Clarify need for empty INTEL_DISPLAY_PARAMS_FOR_EACH in comment

Signed-off-by: Jouni Högander <jouni.hogander@intel.com>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231024124109.384973-2-jouni.hogander@intel.com
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/intel_display_core.h
drivers/gpu/drm/i915/display/intel_display_debugfs.c
drivers/gpu/drm/i915/display/intel_display_debugfs_params.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_display_debugfs_params.h [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_display_device.c
drivers/gpu/drm/i915/display/intel_display_device.h
drivers/gpu/drm/i915/display/intel_display_params.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_display_params.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_driver.c

index 88b2bb005014afeb0e39442acf6639e80b6c1615..3b9dcb606fc1accf24064bd5b94164b47998a7b4 100644 (file)
@@ -95,6 +95,7 @@ i915-$(CONFIG_DEBUG_FS) += \
        i915_debugfs.o \
        i915_debugfs_params.o \
        display/intel_display_debugfs.o \
+       display/intel_display_debugfs_params.o \
        display/intel_pipe_crc.o
 i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o
 
@@ -257,6 +258,7 @@ i915-y += \
        display/intel_display.o \
        display/intel_display_driver.o \
        display/intel_display_irq.o \
+       display/intel_display_params.o \
        display/intel_display_power.o \
        display/intel_display_power_map.o \
        display/intel_display_power_well.o \
index 53e5c33e08c3bb9e9d29a3eac798a6a2df4a373e..f2c84ae522170c93336f82511dcfa809c96a7cea 100644 (file)
@@ -19,6 +19,7 @@
 #include "intel_cdclk.h"
 #include "intel_display_device.h"
 #include "intel_display_limits.h"
+#include "intel_display_params.h"
 #include "intel_display_power.h"
 #include "intel_dpll_mgr.h"
 #include "intel_fbc.h"
@@ -517,6 +518,7 @@ struct intel_display {
        struct intel_hotplug hotplug;
        struct intel_opregion opregion;
        struct intel_overlay *overlay;
+       struct intel_display_params params;
        struct intel_vbt_data vbt;
        struct intel_wm wm;
 };
index 5d2f4fc5709be311f034989bb6e94504b9ee33f2..42bd352f9fee793d8cdf8a129343f673cf885232 100644 (file)
@@ -17,6 +17,7 @@
 #include "intel_de.h"
 #include "intel_crtc_state_dump.h"
 #include "intel_display_debugfs.h"
+#include "intel_display_debugfs_params.h"
 #include "intel_display_power.h"
 #include "intel_display_power_well.h"
 #include "intel_display_types.h"
@@ -1111,6 +1112,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915)
        intel_hpd_debugfs_register(i915);
        intel_psr_debugfs_register(i915);
        intel_wm_debugfs_register(i915);
+       intel_display_debugfs_params(i915);
 }
 
 static int i915_panel_show(struct seq_file *m, void *data)
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c
new file mode 100644 (file)
index 0000000..b7e68eb
--- /dev/null
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include <linux/kernel.h>
+
+#include <drm/drm_drv.h>
+
+#include "intel_display_debugfs_params.h"
+#include "i915_drv.h"
+#include "intel_display_params.h"
+
+/* int param */
+static int intel_display_param_int_show(struct seq_file *m, void *data)
+{
+       int *value = m->private;
+
+       seq_printf(m, "%d\n", *value);
+
+       return 0;
+}
+
+static int intel_display_param_int_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, intel_display_param_int_show, inode->i_private);
+}
+
+static ssize_t intel_display_param_int_write(struct file *file,
+                                            const char __user *ubuf, size_t len,
+                                            loff_t *offp)
+{
+       struct seq_file *m = file->private_data;
+       int *value = m->private;
+       int ret;
+
+       ret = kstrtoint_from_user(ubuf, len, 0, value);
+       if (ret) {
+               /* support boolean values too */
+               bool b;
+
+               ret = kstrtobool_from_user(ubuf, len, &b);
+               if (!ret)
+                       *value = b;
+       }
+
+       return ret ?: len;
+}
+
+static const struct file_operations intel_display_param_int_fops = {
+       .owner = THIS_MODULE,
+       .open = intel_display_param_int_open,
+       .read = seq_read,
+       .write = intel_display_param_int_write,
+       .llseek = default_llseek,
+       .release = single_release,
+};
+
+static const struct file_operations intel_display_param_int_fops_ro = {
+       .owner = THIS_MODULE,
+       .open = intel_display_param_int_open,
+       .read = seq_read,
+       .llseek = default_llseek,
+       .release = single_release,
+};
+
+/* unsigned int param */
+static int intel_display_param_uint_show(struct seq_file *m, void *data)
+{
+       unsigned int *value = m->private;
+
+       seq_printf(m, "%u\n", *value);
+
+       return 0;
+}
+
+static int intel_display_param_uint_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, intel_display_param_uint_show, inode->i_private);
+}
+
+static ssize_t intel_display_param_uint_write(struct file *file,
+                                             const char __user *ubuf, size_t len,
+                                             loff_t *offp)
+{
+       struct seq_file *m = file->private_data;
+       unsigned int *value = m->private;
+       int ret;
+
+       ret = kstrtouint_from_user(ubuf, len, 0, value);
+       if (ret) {
+               /* support boolean values too */
+               bool b;
+
+               ret = kstrtobool_from_user(ubuf, len, &b);
+               if (!ret)
+                       *value = b;
+       }
+
+       return ret ?: len;
+}
+
+static const struct file_operations intel_display_param_uint_fops = {
+       .owner = THIS_MODULE,
+       .open = intel_display_param_uint_open,
+       .read = seq_read,
+       .write = intel_display_param_uint_write,
+       .llseek = default_llseek,
+       .release = single_release,
+};
+
+static const struct file_operations intel_display_param_uint_fops_ro = {
+       .owner = THIS_MODULE,
+       .open = intel_display_param_uint_open,
+       .read = seq_read,
+       .llseek = default_llseek,
+       .release = single_release,
+};
+
+#define RO(mode) (((mode) & 0222) == 0)
+
+__maybe_unused static struct dentry *
+intel_display_debugfs_create_int(const char *name, umode_t mode,
+                       struct dentry *parent, int *value)
+{
+       return debugfs_create_file_unsafe(name, mode, parent, value,
+                                         RO(mode) ? &intel_display_param_int_fops_ro :
+                                         &intel_display_param_int_fops);
+}
+
+__maybe_unused static struct dentry *
+intel_display_debugfs_create_uint(const char *name, umode_t mode,
+                        struct dentry *parent, unsigned int *value)
+{
+       return debugfs_create_file_unsafe(name, mode, parent, value,
+                                         RO(mode) ? &intel_display_param_uint_fops_ro :
+                                         &intel_display_param_uint_fops);
+}
+
+#define _intel_display_param_create_file(parent, name, mode, valp)     \
+       do {                                                            \
+               if (mode)                                               \
+                       _Generic(valp,                                  \
+                                bool * : debugfs_create_bool,          \
+                                int * : intel_display_debugfs_create_int, \
+                                unsigned int * : intel_display_debugfs_create_uint, \
+                                unsigned long * : debugfs_create_ulong, \
+                                char ** : debugfs_create_str) \
+                               (name, mode, parent, valp);             \
+       } while (0)
+
+/* add a subdirectory with files for each intel display param */
+void intel_display_debugfs_params(struct drm_i915_private *i915)
+{
+       struct drm_minor *minor = i915->drm.primary;
+       struct dentry *dir;
+       char dirname[16];
+
+       snprintf(dirname, sizeof(dirname), "%s_params", i915->drm.driver->name);
+       dir = debugfs_lookup(dirname, minor->debugfs_root);
+       if (!dir)
+               dir = debugfs_create_dir(dirname, minor->debugfs_root);
+       if (IS_ERR(dir))
+               return;
+
+       /*
+        * Note: We could create files for params needing special handling
+        * here. Set mode in params to 0 to skip the generic create file, or
+        * just let the generic create file fail silently with -EEXIST.
+        */
+
+#define REGISTER(T, x, unused, mode, ...) _intel_display_param_create_file( \
+               dir, #x, mode, &i915->display.params.x);
+       INTEL_DISPLAY_PARAMS_FOR_EACH(REGISTER);
+#undef REGISTER
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h
new file mode 100644 (file)
index 0000000..1e9945a
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_DISPLAY_DEBUGFS_PARAMS__
+#define __INTEL_DISPLAY_DEBUGFS_PARAMS__
+
+struct drm_i915_private;
+
+void intel_display_debugfs_params(struct drm_i915_private *i915);
+
+#endif /* __INTEL_DISPLAY_DEBUGFS_PARAMS__ */
index 2b1ec23ba9c33fc3f39c5d734cde6b98057810be..e80842d1e7c73d529ea2eeb38962ecc34d9a2797 100644 (file)
@@ -12,6 +12,7 @@
 #include "intel_de.h"
 #include "intel_display.h"
 #include "intel_display_device.h"
+#include "intel_display_params.h"
 #include "intel_display_power.h"
 #include "intel_display_reg_defs.h"
 #include "intel_fbc.h"
@@ -937,6 +938,13 @@ void intel_display_device_probe(struct drm_i915_private *i915)
                DISPLAY_RUNTIME_INFO(i915)->ip.rel = rel;
                DISPLAY_RUNTIME_INFO(i915)->ip.step = step;
        }
+
+       intel_display_params_copy(&i915->display.params);
+}
+
+void intel_display_device_remove(struct drm_i915_private *i915)
+{
+       intel_display_params_free(&i915->display.params);
 }
 
 static void __intel_display_device_info_runtime_init(struct drm_i915_private *i915)
index 5b5c0e53307fa5143e8185a9a084e13fe4ec2f20..4299cc452e0504525c9ce58f31179bd70c4adb5a 100644 (file)
@@ -161,6 +161,7 @@ struct intel_display_device_info {
 
 bool intel_display_device_enabled(struct drm_i915_private *i915);
 void intel_display_device_probe(struct drm_i915_private *i915);
+void intel_display_device_remove(struct drm_i915_private *i915);
 void intel_display_device_info_runtime_init(struct drm_i915_private *i915);
 
 void intel_display_device_info_print(const struct intel_display_device_info *info,
diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c
new file mode 100644 (file)
index 0000000..91953ae
--- /dev/null
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include "intel_display_params.h"
+#include "i915_drv.h"
+
+#define intel_display_param_named(name, T, perm, desc) \
+       module_param_named(name, intel_display_modparams.name, T, perm); \
+       MODULE_PARM_DESC(name, desc)
+#define intel_display_param_named_unsafe(name, T, perm, desc) \
+       module_param_named_unsafe(name, intel_display_modparams.name, T, perm); \
+       MODULE_PARM_DESC(name, desc)
+
+static struct intel_display_params intel_display_modparams __read_mostly = {
+#define MEMBER(T, member, value, ...) .member = (value),
+       INTEL_DISPLAY_PARAMS_FOR_EACH(MEMBER)
+#undef MEMBER
+};
+/*
+ * Note: As a rule, keep module parameter sysfs permissions read-only
+ * 0400. Runtime changes are only supported through i915 debugfs.
+ *
+ * For any exceptions requiring write access and runtime changes through module
+ * parameter sysfs, prevent debugfs file creation by setting the parameter's
+ * debugfs mode to 0.
+ */
+
+__maybe_unused static void _param_dup_charp(char **valp)
+{
+       *valp = kstrdup(*valp ? *valp : "", GFP_ATOMIC);
+}
+
+__maybe_unused static void _param_nop(void *valp)
+{
+}
+
+#define _param_dup(valp)                               \
+       _Generic(valp,                                  \
+                char ** : _param_dup_charp,            \
+                default : _param_nop)                  \
+               (valp)
+
+void intel_display_params_copy(struct intel_display_params *dest)
+{
+       *dest = intel_display_modparams;
+#define DUP(T, x, ...) _param_dup(&dest->x);
+       INTEL_DISPLAY_PARAMS_FOR_EACH(DUP);
+#undef DUP
+}
+
+__maybe_unused static void _param_free_charp(char **valp)
+{
+       kfree(*valp);
+       *valp = NULL;
+}
+
+#define _param_free(valp)                              \
+       _Generic(valp,                                  \
+                char ** : _param_free_charp,           \
+                default : _param_nop)                  \
+               (valp)
+
+/* free the allocated members, *not* the passed in params itself */
+void intel_display_params_free(struct intel_display_params *params)
+{
+#define FREE(T, x, ...) _param_free(&params->x);
+       INTEL_DISPLAY_PARAMS_FOR_EACH(FREE);
+#undef FREE
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h
new file mode 100644 (file)
index 0000000..9f4f45d
--- /dev/null
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef _INTEL_DISPLAY_PARAMS_H_
+#define _INTEL_DISPLAY_PARAMS_H_
+
+struct drm_printer;
+
+/*
+ * Invoke param, a function-like macro, for each intel display param, with
+ * arguments:
+ *
+ * param(type, name, value, mode)
+ *
+ * type: parameter type, one of {bool, int, unsigned int, unsigned long, char *}
+ * name: name of the parameter
+ * value: initial/default value of the parameter
+ * mode: debugfs file permissions, one of {0400, 0600, 0}, use 0 to not create
+ *       debugfs file
+ */
+#define INTEL_DISPLAY_PARAMS_FOR_EACH(param) /* empty define to avoid build failure */
+
+#define MEMBER(T, member, ...) T member;
+struct intel_display_params {
+       INTEL_DISPLAY_PARAMS_FOR_EACH(MEMBER);
+};
+#undef MEMBER
+
+void intel_display_params_copy(struct intel_display_params *dest);
+void intel_display_params_free(struct intel_display_params *params);
+
+#endif
index f30a0861541cc46fe02979508da38bdde56e05b7..3d86db5638fc8c628fd37550927802f848f85363 100644 (file)
@@ -908,6 +908,8 @@ static void i915_driver_release(struct drm_device *dev)
        intel_runtime_pm_driver_release(rpm);
 
        i915_driver_late_release(dev_priv);
+
+       intel_display_device_remove(dev_priv);
 }
 
 static int i915_driver_open(struct drm_device *dev, struct drm_file *file)