Skip to content

Commit

Permalink
drm/i915/opregion: let user specify override VBT via firmware load
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Daniel Vetter <[email protected]>
Signed-off-by: Jani Nikula <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
jnikula committed Aug 17, 2017
1 parent a029fa4 commit ab3595b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ struct intel_opregion {
u32 swsci_sbcb_sub_functions;
struct opregion_asle *asle;
void *rvda;
void *vbt_firmware;
const void *vbt;
u32 vbt_size;
u32 *lid_state;
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/i915_params.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ MODULE_PARM_DESC(vbt_sdvo_panel_type,
module_param_named_unsafe(reset, i915.reset, int, 0600);
MODULE_PARM_DESC(reset, "Attempt GPU resets (0=disabled, 1=full gpu reset, 2=engine reset [default])");

module_param_named_unsafe(vbt_firmware, i915.vbt_firmware, charp, 0400);
MODULE_PARM_DESC(vbt_firmware,
"Load VBT from specified file under /lib/firmware");

#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
module_param_named(error_capture, i915.error_capture, bool, 0600);
MODULE_PARM_DESC(error_capture,
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/cache.h> /* for __read_mostly */

#define I915_PARAMS_FOR_EACH(func) \
func(char *, vbt_firmware); \
func(int, modeset); \
func(int, panel_ignore_lid); \
func(int, semaphores); \
Expand Down
45 changes: 45 additions & 0 deletions drivers/gpu/drm/i915/intel_opregion.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/firmware.h>
#include <acpi/video.h>

#include <drm/drmP.h>
Expand Down Expand Up @@ -829,6 +830,10 @@ void intel_opregion_unregister(struct drm_i915_private *dev_priv)
memunmap(opregion->rvda);
opregion->rvda = NULL;
}
if (opregion->vbt_firmware) {
kfree(opregion->vbt_firmware);
opregion->vbt_firmware = NULL;
}
opregion->header = NULL;
opregion->acpi = NULL;
opregion->swsci = NULL;
Expand Down Expand Up @@ -912,6 +917,43 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = {
{ }
};

static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv)
{
struct intel_opregion *opregion = &dev_priv->opregion;
const struct firmware *fw = NULL;
const char *name = i915.vbt_firmware;
int ret;

if (!name || !*name)
return -ENOENT;

ret = request_firmware(&fw, name, &dev_priv->drm.pdev->dev);
if (ret) {
DRM_ERROR("Requesting VBT firmware \"%s\" failed (%d)\n",
name, ret);
return ret;
}

if (intel_bios_is_valid_vbt(fw->data, fw->size)) {
opregion->vbt_firmware = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (opregion->vbt_firmware) {
DRM_DEBUG_KMS("Found valid VBT firmware \"%s\"\n", name);
opregion->vbt = opregion->vbt_firmware;
opregion->vbt_size = fw->size;
ret = 0;
} else {
ret = -ENOMEM;
}
} else {
DRM_DEBUG_KMS("Invalid VBT firmware \"%s\"\n", name);
ret = -EINVAL;
}

release_firmware(fw);

return ret;
}

int intel_opregion_setup(struct drm_i915_private *dev_priv)
{
struct intel_opregion *opregion = &dev_priv->opregion;
Expand Down Expand Up @@ -974,6 +1016,9 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
if (mboxes & MBOX_ASLE_EXT)
DRM_DEBUG_DRIVER("ASLE extension supported\n");

if (intel_load_vbt_firmware(dev_priv) == 0)
goto out;

if (dmi_check_system(intel_no_opregion_vbt))
goto out;

Expand Down

0 comments on commit ab3595b

Please sign in to comment.