aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJani Nikula <jani.nikula@intel.com>2017-08-17 07:52:09 -0400
committerJani Nikula <jani.nikula@intel.com>2017-08-17 09:34:54 -0400
commitab3595bc4ff328ec90d20714f8e2674f3abfa2cd (patch)
treed376bb589edba6da51798dfaecb8b855c1ddd564
parenta029fa4d758f6a0a0f53c8f226d446206f32373f (diff)
drm/i915/opregion: let user specify override VBT via firmware load
Sometimes it would be most enlightening to debug systems by replacing the VBT to be used. For example, in the referenced bug the BIOS provides different VBT depending on the boot mode (UEFI vs. legacy). It would be interesting to try the failing boot mode with the VBT from the working boot, and see if that makes a difference. Add a module parameter to load the VBT using the firmware loader, not unlike the EDID firmware mechanism. As a starting point for experimenting, one can pick up the BIOS provided VBT from /sys/kernel/debug/dri/0/i915_opregion/i915_vbt. v2: clarify firmware load return value check (Bob) v3: kfree the loaded firmware blob References: https://bugs.freedesktop.org/show_bug.cgi?id=97822#c83 Reviewed-by: Bob Paauwe <bob.j.paauwe@intel.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20170817115209.25912-1-jani.nikula@intel.com
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_params.c4
-rw-r--r--drivers/gpu/drm/i915/i915_params.h1
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c45
4 files changed, 51 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 6c25c8520c87..3ee4fd2a9b41 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -646,6 +646,7 @@ struct intel_opregion {
646 u32 swsci_sbcb_sub_functions; 646 u32 swsci_sbcb_sub_functions;
647 struct opregion_asle *asle; 647 struct opregion_asle *asle;
648 void *rvda; 648 void *rvda;
649 void *vbt_firmware;
649 const void *vbt; 650 const void *vbt;
650 u32 vbt_size; 651 u32 vbt_size;
651 u32 *lid_state; 652 u32 *lid_state;
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 14e2c2e57f96..8ab003dca113 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -118,6 +118,10 @@ MODULE_PARM_DESC(vbt_sdvo_panel_type,
118module_param_named_unsafe(reset, i915.reset, int, 0600); 118module_param_named_unsafe(reset, i915.reset, int, 0600);
119MODULE_PARM_DESC(reset, "Attempt GPU resets (0=disabled, 1=full gpu reset, 2=engine reset [default])"); 119MODULE_PARM_DESC(reset, "Attempt GPU resets (0=disabled, 1=full gpu reset, 2=engine reset [default])");
120 120
121module_param_named_unsafe(vbt_firmware, i915.vbt_firmware, charp, 0400);
122MODULE_PARM_DESC(vbt_firmware,
123 "Load VBT from specified file under /lib/firmware");
124
121#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) 125#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
122module_param_named(error_capture, i915.error_capture, bool, 0600); 126module_param_named(error_capture, i915.error_capture, bool, 0600);
123MODULE_PARM_DESC(error_capture, 127MODULE_PARM_DESC(error_capture,
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index febbfdbd30bd..ac844709c97e 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -28,6 +28,7 @@
28#include <linux/cache.h> /* for __read_mostly */ 28#include <linux/cache.h> /* for __read_mostly */
29 29
30#define I915_PARAMS_FOR_EACH(func) \ 30#define I915_PARAMS_FOR_EACH(func) \
31 func(char *, vbt_firmware); \
31 func(int, modeset); \ 32 func(int, modeset); \
32 func(int, panel_ignore_lid); \ 33 func(int, panel_ignore_lid); \
33 func(int, semaphores); \ 34 func(int, semaphores); \
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 2bd03001cc70..98154efcb2f4 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -27,6 +27,7 @@
27 27
28#include <linux/acpi.h> 28#include <linux/acpi.h>
29#include <linux/dmi.h> 29#include <linux/dmi.h>
30#include <linux/firmware.h>
30#include <acpi/video.h> 31#include <acpi/video.h>
31 32
32#include <drm/drmP.h> 33#include <drm/drmP.h>
@@ -829,6 +830,10 @@ void intel_opregion_unregister(struct drm_i915_private *dev_priv)
829 memunmap(opregion->rvda); 830 memunmap(opregion->rvda);
830 opregion->rvda = NULL; 831 opregion->rvda = NULL;
831 } 832 }
833 if (opregion->vbt_firmware) {
834 kfree(opregion->vbt_firmware);
835 opregion->vbt_firmware = NULL;
836 }
832 opregion->header = NULL; 837 opregion->header = NULL;
833 opregion->acpi = NULL; 838 opregion->acpi = NULL;
834 opregion->swsci = NULL; 839 opregion->swsci = NULL;
@@ -912,6 +917,43 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = {
912 { } 917 { }
913}; 918};
914 919
920static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv)
921{
922 struct intel_opregion *opregion = &dev_priv->opregion;
923 const struct firmware *fw = NULL;
924 const char *name = i915.vbt_firmware;
925 int ret;
926
927 if (!name || !*name)
928 return -ENOENT;
929
930 ret = request_firmware(&fw, name, &dev_priv->drm.pdev->dev);
931 if (ret) {
932 DRM_ERROR("Requesting VBT firmware \"%s\" failed (%d)\n",
933 name, ret);
934 return ret;
935 }
936
937 if (intel_bios_is_valid_vbt(fw->data, fw->size)) {
938 opregion->vbt_firmware = kmemdup(fw->data, fw->size, GFP_KERNEL);
939 if (opregion->vbt_firmware) {
940 DRM_DEBUG_KMS("Found valid VBT firmware \"%s\"\n", name);
941 opregion->vbt = opregion->vbt_firmware;
942 opregion->vbt_size = fw->size;
943 ret = 0;
944 } else {
945 ret = -ENOMEM;
946 }
947 } else {
948 DRM_DEBUG_KMS("Invalid VBT firmware \"%s\"\n", name);
949 ret = -EINVAL;
950 }
951
952 release_firmware(fw);
953
954 return ret;
955}
956
915int intel_opregion_setup(struct drm_i915_private *dev_priv) 957int intel_opregion_setup(struct drm_i915_private *dev_priv)
916{ 958{
917 struct intel_opregion *opregion = &dev_priv->opregion; 959 struct intel_opregion *opregion = &dev_priv->opregion;
@@ -974,6 +1016,9 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
974 if (mboxes & MBOX_ASLE_EXT) 1016 if (mboxes & MBOX_ASLE_EXT)
975 DRM_DEBUG_DRIVER("ASLE extension supported\n"); 1017 DRM_DEBUG_DRIVER("ASLE extension supported\n");
976 1018
1019 if (intel_load_vbt_firmware(dev_priv) == 0)
1020 goto out;
1021
977 if (dmi_check_system(intel_no_opregion_vbt)) 1022 if (dmi_check_system(intel_no_opregion_vbt))
978 goto out; 1023 goto out;
979 1024