mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'drm-misc-next-2024-08-29' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v6.12: UAPI Changes: devfs: - support device numbers up to MINORBITS limit Core Changes: ci: - increase job timeout devfs: - use XArray for minor ids displayport: - mst: GUID improvements docs: - add fixes and cleanups panic: - optionally display QR code Driver Changes: amdgpu: - faster vblank disabling - GUID improvements gm12u320 - convert to struct drm_edid host1x: - fix syncpoint IRQ during resume - use iommu_paging_domain_alloc() imx: - ipuv3: convert to struct drm_edid omapdrm: - improve error handling panel: - add support for BOE TV101WUM-LL2 plus DT bindings - novatek-nt35950: improve error handling - nv3051d: improve error handling - panel-edp: add support for BOE NE140WUM-N6G; revert support for SDC ATNA45AF01 - visionox-vtdr6130: improve error handling; use devm_regulator_bulk_get_const() renesas: - rz-du: add support for RZ/G2UL plus DT bindings sti: - convert to struct drm_edid tegra: - gr3d: improve PM domain handling - convert to struct drm_edid Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patchwork.freedesktop.org/patch/msgid/20240829144654.GA145538@linux.fritz.box
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/boe,tv101wum-ll2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: BOE TV101WUM-LL2 DSI Display Panel
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: boe,tv101wum-ll2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: DSI virtual channel
|
||||
|
||||
backlight: true
|
||||
reset-gpios: true
|
||||
vsp-supply: true
|
||||
vsn-supply: true
|
||||
port: true
|
||||
rotation: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- vsp-supply
|
||||
- vsn-supply
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "boe,tv101wum-ll2";
|
||||
reg = <0>;
|
||||
|
||||
vsn-supply = <&vsn_lcd>;
|
||||
vsp-supply = <&vsp_lcd>;
|
||||
|
||||
reset-gpios = <&pio 45 GPIO_ACTIVE_LOW>;
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&dsi_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -18,6 +18,7 @@ properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- renesas,r9a07g043u-du # RZ/G2UL
|
||||
- renesas,r9a07g044-du # RZ/G2{L,LC}
|
||||
- items:
|
||||
- enum:
|
||||
@@ -60,9 +61,6 @@ properties:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
renesas,vsps:
|
||||
@@ -88,6 +86,34 @@ required:
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a07g043u-du
|
||||
then:
|
||||
properties:
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPI
|
||||
|
||||
required:
|
||||
- port@0
|
||||
else:
|
||||
properties:
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DSI
|
||||
port@1:
|
||||
description: DPI
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
examples:
|
||||
# RZ/G2L DU
|
||||
- |
|
||||
|
||||
@@ -7343,10 +7343,10 @@ F: drivers/gpu/drm/udl/
|
||||
|
||||
DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
|
||||
M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
|
||||
M: Melissa Wen <melissa.srw@gmail.com>
|
||||
M: Maíra Canal <mairacanal@riseup.net>
|
||||
R: Haneen Mohammed <hamohammed.sa@gmail.com>
|
||||
R: Daniel Vetter <daniel@ffwll.ch>
|
||||
R: Melissa Wen <melissa.srw@gmail.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Maintained
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#include <drm/drm_accel.h>
|
||||
#include <drm/drm_auth.h>
|
||||
@@ -18,8 +18,7 @@
|
||||
#include <drm/drm_ioctl.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
static DEFINE_SPINLOCK(accel_minor_lock);
|
||||
static struct idr accel_minors_idr;
|
||||
DEFINE_XARRAY_ALLOC(accel_minors_xa);
|
||||
|
||||
static struct dentry *accel_debugfs_root;
|
||||
|
||||
@@ -117,99 +116,6 @@ void accel_set_device_instance_params(struct device *kdev, int index)
|
||||
kdev->type = &accel_sysfs_device_minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_minor_alloc() - Allocates a new accel minor
|
||||
*
|
||||
* This function access the accel minors idr and allocates from it
|
||||
* a new id to represent a new accel minor
|
||||
*
|
||||
* Return: A new id on success or error code in case idr_alloc failed
|
||||
*/
|
||||
int accel_minor_alloc(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
r = idr_alloc(&accel_minors_idr, NULL, 0, ACCEL_MAX_MINORS, GFP_NOWAIT);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_minor_remove() - Remove an accel minor
|
||||
* @index: The minor id to remove.
|
||||
*
|
||||
* This function access the accel minors idr and removes from
|
||||
* it the member with the id that is passed to this function.
|
||||
*/
|
||||
void accel_minor_remove(int index)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
idr_remove(&accel_minors_idr, index);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_minor_replace() - Replace minor pointer in accel minors idr.
|
||||
* @minor: Pointer to the new minor.
|
||||
* @index: The minor id to replace.
|
||||
*
|
||||
* This function access the accel minors idr structure and replaces the pointer
|
||||
* that is associated with an existing id. Because the minor pointer can be
|
||||
* NULL, we need to explicitly pass the index.
|
||||
*
|
||||
* Return: 0 for success, negative value for error
|
||||
*/
|
||||
void accel_minor_replace(struct drm_minor *minor, int index)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
idr_replace(&accel_minors_idr, minor, index);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up the given minor-ID and returns the respective DRM-minor object. The
|
||||
* refence-count of the underlying device is increased so you must release this
|
||||
* object with accel_minor_release().
|
||||
*
|
||||
* The object can be only a drm_minor that represents an accel device.
|
||||
*
|
||||
* As long as you hold this minor, it is guaranteed that the object and the
|
||||
* minor->dev pointer will stay valid! However, the device may get unplugged and
|
||||
* unregistered while you hold the minor.
|
||||
*/
|
||||
static struct drm_minor *accel_minor_acquire(unsigned int minor_id)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
minor = idr_find(&accel_minors_idr, minor_id);
|
||||
if (minor)
|
||||
drm_dev_get(minor->dev);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
|
||||
if (!minor) {
|
||||
return ERR_PTR(-ENODEV);
|
||||
} else if (drm_dev_is_unplugged(minor->dev)) {
|
||||
drm_dev_put(minor->dev);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
return minor;
|
||||
}
|
||||
|
||||
static void accel_minor_release(struct drm_minor *minor)
|
||||
{
|
||||
drm_dev_put(minor->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_open - open method for ACCEL file
|
||||
* @inode: device inode
|
||||
@@ -227,7 +133,7 @@ int accel_open(struct inode *inode, struct file *filp)
|
||||
struct drm_minor *minor;
|
||||
int retcode;
|
||||
|
||||
minor = accel_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -246,7 +152,7 @@ int accel_open(struct inode *inode, struct file *filp)
|
||||
|
||||
err_undo:
|
||||
atomic_dec(&dev->open_count);
|
||||
accel_minor_release(minor);
|
||||
drm_minor_release(minor);
|
||||
return retcode;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(accel_open);
|
||||
@@ -257,7 +163,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
|
||||
struct drm_minor *minor;
|
||||
int err;
|
||||
|
||||
minor = accel_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -274,7 +180,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
accel_minor_release(minor);
|
||||
drm_minor_release(minor);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -290,15 +196,13 @@ void accel_core_exit(void)
|
||||
unregister_chrdev(ACCEL_MAJOR, "accel");
|
||||
debugfs_remove(accel_debugfs_root);
|
||||
accel_sysfs_destroy();
|
||||
idr_destroy(&accel_minors_idr);
|
||||
WARN_ON(!xa_empty(&accel_minors_xa));
|
||||
}
|
||||
|
||||
int __init accel_core_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
idr_init(&accel_minors_idr);
|
||||
|
||||
ret = accel_sysfs_init();
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Cannot create ACCEL class: %d\n", ret);
|
||||
|
||||
@@ -149,6 +149,37 @@ config DRM_PANIC_SCREEN
|
||||
or by writing to /sys/module/drm/parameters/panic_screen sysfs entry
|
||||
Default is "user"
|
||||
|
||||
config DRM_PANIC_SCREEN_QR_CODE
|
||||
bool "Add a panic screen with a QR code"
|
||||
depends on DRM_PANIC && RUST
|
||||
help
|
||||
This option adds a QR code generator, and a panic screen with a QR
|
||||
code. The QR code will contain the last lines of kmsg and other debug
|
||||
information. This should be easier for the user to report a kernel
|
||||
panic, with all debug information available.
|
||||
To use this panic screen, also set DRM_PANIC_SCREEN to "qr_code"
|
||||
|
||||
config DRM_PANIC_SCREEN_QR_CODE_URL
|
||||
string "Base URL of the QR code in the panic screen"
|
||||
depends on DRM_PANIC_SCREEN_QR_CODE
|
||||
help
|
||||
This option sets the base URL to report the kernel panic. If it's set
|
||||
the QR code will contain the URL and the kmsg compressed with zlib as
|
||||
a URL parameter. If it's empty, the QR code will contain the kmsg as
|
||||
uncompressed text only.
|
||||
There is a demo code in javascript, to decode and uncompress the kmsg
|
||||
data from the URL parameter at https://github.com/kdj0c/panic_report
|
||||
|
||||
config DRM_PANIC_SCREEN_QR_VERSION
|
||||
int "Maximum version (size) of the QR code."
|
||||
depends on DRM_PANIC_SCREEN_QR_CODE
|
||||
default 40
|
||||
help
|
||||
This option limits the version (or size) of the QR code. QR code
|
||||
version ranges from Version 1 (21x21) to Version 40 (177x177).
|
||||
Smaller QR code are easier to read, but will contain less debugging
|
||||
data. Default is 40.
|
||||
|
||||
config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
|
||||
bool "Enable refcount backtrace history in the DP MST helpers"
|
||||
depends on STACKTRACE_SUPPORT
|
||||
|
||||
@@ -89,6 +89,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
|
||||
drm_privacy_screen_x86.o
|
||||
drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
|
||||
drm-$(CONFIG_DRM_PANIC) += drm_panic.o
|
||||
drm-$(CONFIG_DRM_PANIC_SCREEN_QR_CODE) += drm_panic_qr.o
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
|
||||
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
|
||||
|
||||
@@ -2579,9 +2579,9 @@ static int dm_late_init(void *handle)
|
||||
|
||||
static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
|
||||
{
|
||||
u8 buf[UUID_SIZE];
|
||||
guid_t guid;
|
||||
int ret;
|
||||
u8 guid[16];
|
||||
u64 tmp64;
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
if (!mgr->mst_primary)
|
||||
@@ -2602,26 +2602,27 @@ static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
|
||||
}
|
||||
|
||||
/* Some hubs forget their guids after they resume */
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
|
||||
if (ret != 16) {
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf));
|
||||
if (ret != sizeof(buf)) {
|
||||
drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
if (memchr_inv(guid, 0, 16) == NULL) {
|
||||
tmp64 = get_jiffies_64();
|
||||
memcpy(&guid[0], &tmp64, sizeof(u64));
|
||||
memcpy(&guid[8], &tmp64, sizeof(u64));
|
||||
import_guid(&guid, buf);
|
||||
|
||||
ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, guid, 16);
|
||||
if (guid_is_null(&guid)) {
|
||||
guid_gen(&guid);
|
||||
export_guid(buf, &guid);
|
||||
|
||||
if (ret != 16) {
|
||||
ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, buf, sizeof(buf));
|
||||
|
||||
if (ret != sizeof(buf)) {
|
||||
drm_dbg_kms(mgr->dev, "check mstb guid failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(mgr->mst_primary->guid, guid, 16);
|
||||
guid_copy(&mgr->mst_primary->guid, &guid);
|
||||
|
||||
out_fail:
|
||||
mutex_unlock(&mgr->lock);
|
||||
@@ -4947,12 +4948,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
|
||||
if (psr_feature_enabled)
|
||||
amdgpu_dm_set_psr_caps(link);
|
||||
|
||||
/* TODO: Fix vblank control helpers to delay PSR entry to allow this when
|
||||
* PSR is also supported.
|
||||
*/
|
||||
if (link->psr_settings.psr_feature_enabled)
|
||||
adev_to_drm(adev)->vblank_disable_immediate = false;
|
||||
}
|
||||
}
|
||||
amdgpu_set_panel_orientation(&aconnector->base);
|
||||
@@ -8248,12 +8243,66 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev,
|
||||
|
||||
static void manage_dm_interrupts(struct amdgpu_device *adev,
|
||||
struct amdgpu_crtc *acrtc,
|
||||
bool enable)
|
||||
struct dm_crtc_state *acrtc_state)
|
||||
{
|
||||
if (enable)
|
||||
drm_crtc_vblank_on(&acrtc->base);
|
||||
else
|
||||
/*
|
||||
* We have no guarantee that the frontend index maps to the same
|
||||
* backend index - some even map to more than one.
|
||||
*
|
||||
* TODO: Use a different interrupt or check DC itself for the mapping.
|
||||
*/
|
||||
int irq_type =
|
||||
amdgpu_display_crtc_idx_to_irq_type(
|
||||
adev,
|
||||
acrtc->crtc_id);
|
||||
struct drm_vblank_crtc_config config = {0};
|
||||
struct dc_crtc_timing *timing;
|
||||
int offdelay;
|
||||
|
||||
if (acrtc_state) {
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
|
||||
IP_VERSION(3, 5, 0) ||
|
||||
acrtc_state->stream->link->psr_settings.psr_version <
|
||||
DC_PSR_VERSION_UNSUPPORTED) {
|
||||
timing = &acrtc_state->stream->timing;
|
||||
|
||||
/* at least 2 frames */
|
||||
offdelay = DIV64_U64_ROUND_UP((u64)20 *
|
||||
timing->v_total *
|
||||
timing->h_total,
|
||||
timing->pix_clk_100hz);
|
||||
|
||||
config.offdelay_ms = offdelay ?: 30;
|
||||
} else {
|
||||
config.disable_immediate = true;
|
||||
}
|
||||
|
||||
drm_crtc_vblank_on_config(&acrtc->base,
|
||||
&config);
|
||||
|
||||
amdgpu_irq_get(
|
||||
adev,
|
||||
&adev->pageflip_irq,
|
||||
irq_type);
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
amdgpu_irq_get(
|
||||
adev,
|
||||
&adev->vline0_irq,
|
||||
irq_type);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
amdgpu_irq_put(
|
||||
adev,
|
||||
&adev->vline0_irq,
|
||||
irq_type);
|
||||
#endif
|
||||
amdgpu_irq_put(
|
||||
adev,
|
||||
&adev->pageflip_irq,
|
||||
irq_type);
|
||||
drm_crtc_vblank_off(&acrtc->base);
|
||||
}
|
||||
}
|
||||
|
||||
static void dm_update_pflip_irq_state(struct amdgpu_device *adev,
|
||||
@@ -9305,7 +9354,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
|
||||
if (old_crtc_state->active &&
|
||||
(!new_crtc_state->active ||
|
||||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
|
||||
manage_dm_interrupts(adev, acrtc, false);
|
||||
manage_dm_interrupts(adev, acrtc, NULL);
|
||||
dc_stream_release(dm_old_crtc_state->stream);
|
||||
}
|
||||
}
|
||||
@@ -9821,7 +9870,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
|
||||
dc_stream_retain(dm_new_crtc_state->stream);
|
||||
acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;
|
||||
manage_dm_interrupts(adev, acrtc, true);
|
||||
manage_dm_interrupts(adev, acrtc, dm_new_crtc_state);
|
||||
}
|
||||
/* Handle vrr on->off / off->on transitions */
|
||||
amdgpu_dm_handle_vrr_transition(dm_old_crtc_state, dm_new_crtc_state);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
.lava-test:
|
||||
extends:
|
||||
- .test-rules
|
||||
timeout: "1h30m"
|
||||
script:
|
||||
# Note: Build dir (and thus install) may be dirty due to GIT_STRATEGY
|
||||
- rm -rf install
|
||||
@@ -71,6 +72,7 @@
|
||||
- .baremetal-test-arm64
|
||||
- .use-debian/baremetal_arm64_test
|
||||
- .test-rules
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
FDO_CI_CONCURRENT: 10
|
||||
HWCI_TEST_SCRIPT: "/install/igt_runner.sh"
|
||||
@@ -215,7 +217,6 @@ panfrost:rk3399:
|
||||
extends:
|
||||
- .lava-igt:x86_64
|
||||
stage: i915
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
DRIVER_NAME: i915
|
||||
DTB: ""
|
||||
@@ -414,6 +415,7 @@ panfrost:g12b:
|
||||
|
||||
virtio_gpu:none:
|
||||
stage: software-driver
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
CROSVM_GALLIUM_DRIVER: llvmpipe
|
||||
DRIVER_NAME: virtio_gpu
|
||||
@@ -436,6 +438,7 @@ virtio_gpu:none:
|
||||
|
||||
vkms:none:
|
||||
stage: software-driver
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
DRIVER_NAME: vkms
|
||||
GPU_VERSION: none
|
||||
|
||||
@@ -89,7 +89,7 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
|
||||
struct drm_dp_mst_branch *mstb,
|
||||
struct drm_dp_mst_port *port);
|
||||
static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
|
||||
u8 *guid);
|
||||
guid_t *guid);
|
||||
|
||||
static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port);
|
||||
static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port);
|
||||
@@ -801,7 +801,7 @@ static bool drm_dp_sideband_parse_link_address(const struct drm_dp_mst_topology_
|
||||
int idx = 1;
|
||||
int i;
|
||||
|
||||
memcpy(repmsg->u.link_addr.guid, &raw->msg[idx], 16);
|
||||
import_guid(&repmsg->u.link_addr.guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
repmsg->u.link_addr.nports = raw->msg[idx] & 0xf;
|
||||
idx++;
|
||||
@@ -829,7 +829,7 @@ static bool drm_dp_sideband_parse_link_address(const struct drm_dp_mst_topology_
|
||||
idx++;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
memcpy(repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx], 16);
|
||||
import_guid(&repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
@@ -1029,7 +1029,7 @@ static bool drm_dp_sideband_parse_reply(const struct drm_dp_mst_topology_mgr *mg
|
||||
msg->req_type = (raw->msg[0] & 0x7f);
|
||||
|
||||
if (msg->reply_type == DP_SIDEBAND_REPLY_NAK) {
|
||||
memcpy(msg->u.nak.guid, &raw->msg[1], 16);
|
||||
import_guid(&msg->u.nak.guid, &raw->msg[1]);
|
||||
msg->u.nak.reason = raw->msg[17];
|
||||
msg->u.nak.nak_data = raw->msg[18];
|
||||
return false;
|
||||
@@ -1078,7 +1078,7 @@ drm_dp_sideband_parse_connection_status_notify(const struct drm_dp_mst_topology_
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
|
||||
memcpy(msg->u.conn_stat.guid, &raw->msg[idx], 16);
|
||||
import_guid(&msg->u.conn_stat.guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
@@ -1107,7 +1107,7 @@ static bool drm_dp_sideband_parse_resource_status_notify(const struct drm_dp_mst
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
|
||||
memcpy(msg->u.resource_stat.guid, &raw->msg[idx], 16);
|
||||
import_guid(&msg->u.resource_stat.guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
@@ -2174,20 +2174,24 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
|
||||
offset, size, buffer);
|
||||
}
|
||||
|
||||
static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
|
||||
static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, guid_t *guid)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
memcpy(mstb->guid, guid, 16);
|
||||
guid_copy(&mstb->guid, guid);
|
||||
|
||||
if (!drm_dp_validate_guid(mstb->mgr, &mstb->guid)) {
|
||||
u8 buf[UUID_SIZE];
|
||||
|
||||
export_guid(buf, &mstb->guid);
|
||||
|
||||
if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
|
||||
if (mstb->port_parent) {
|
||||
ret = drm_dp_send_dpcd_write(mstb->mgr,
|
||||
mstb->port_parent,
|
||||
DP_GUID, 16, mstb->guid);
|
||||
DP_GUID, sizeof(buf), buf);
|
||||
} else {
|
||||
ret = drm_dp_dpcd_write(mstb->mgr->aux,
|
||||
DP_GUID, mstb->guid, 16);
|
||||
DP_GUID, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2567,9 +2571,9 @@ out:
|
||||
return mstb;
|
||||
}
|
||||
|
||||
static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
|
||||
struct drm_dp_mst_branch *mstb,
|
||||
const uint8_t *guid)
|
||||
static struct drm_dp_mst_branch *
|
||||
get_mst_branch_device_by_guid_helper(struct drm_dp_mst_branch *mstb,
|
||||
const guid_t *guid)
|
||||
{
|
||||
struct drm_dp_mst_branch *found_mstb;
|
||||
struct drm_dp_mst_port *port;
|
||||
@@ -2577,10 +2581,9 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
|
||||
if (!mstb)
|
||||
return NULL;
|
||||
|
||||
if (memcmp(mstb->guid, guid, 16) == 0)
|
||||
if (guid_equal(&mstb->guid, guid))
|
||||
return mstb;
|
||||
|
||||
|
||||
list_for_each_entry(port, &mstb->ports, next) {
|
||||
found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
|
||||
|
||||
@@ -2593,7 +2596,7 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
|
||||
|
||||
static struct drm_dp_mst_branch *
|
||||
drm_dp_get_mst_branch_device_by_guid(struct drm_dp_mst_topology_mgr *mgr,
|
||||
const uint8_t *guid)
|
||||
const guid_t *guid)
|
||||
{
|
||||
struct drm_dp_mst_branch *mstb;
|
||||
int ret;
|
||||
@@ -2695,17 +2698,12 @@ static void drm_dp_mst_queue_probe_work(struct drm_dp_mst_topology_mgr *mgr)
|
||||
}
|
||||
|
||||
static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
|
||||
u8 *guid)
|
||||
guid_t *guid)
|
||||
{
|
||||
u64 salt;
|
||||
|
||||
if (memchr_inv(guid, 0, 16))
|
||||
if (!guid_is_null(guid))
|
||||
return true;
|
||||
|
||||
salt = get_jiffies_64();
|
||||
|
||||
memcpy(&guid[0], &salt, sizeof(u64));
|
||||
memcpy(&guid[8], &salt, sizeof(u64));
|
||||
guid_gen(guid);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -2945,7 +2943,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
|
||||
drm_dbg_kms(mgr->dev, "link address reply: %d\n", reply->nports);
|
||||
drm_dp_dump_link_address(mgr, reply);
|
||||
|
||||
ret = drm_dp_check_mstb_guid(mstb, reply->guid);
|
||||
ret = drm_dp_check_mstb_guid(mstb, &reply->guid);
|
||||
if (ret) {
|
||||
char buf[64];
|
||||
|
||||
@@ -3799,8 +3797,9 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend);
|
||||
int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
|
||||
bool sync)
|
||||
{
|
||||
u8 buf[UUID_SIZE];
|
||||
guid_t guid;
|
||||
int ret;
|
||||
u8 guid[16];
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
if (!mgr->mst_primary)
|
||||
@@ -3821,13 +3820,15 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
|
||||
}
|
||||
|
||||
/* Some hubs forget their guids after they resume */
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
|
||||
if (ret != 16) {
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf));
|
||||
if (ret != sizeof(buf)) {
|
||||
drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid);
|
||||
import_guid(&guid, buf);
|
||||
|
||||
ret = drm_dp_check_mstb_guid(mgr->mst_primary, &guid);
|
||||
if (ret) {
|
||||
drm_dbg_kms(mgr->dev, "check mstb failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
@@ -4005,12 +4006,12 @@ drm_dp_mst_process_up_req(struct drm_dp_mst_topology_mgr *mgr,
|
||||
bool hotplug = false, dowork = false;
|
||||
|
||||
if (hdr->broadcast) {
|
||||
const u8 *guid = NULL;
|
||||
const guid_t *guid = NULL;
|
||||
|
||||
if (msg->req_type == DP_CONNECTION_STATUS_NOTIFY)
|
||||
guid = msg->u.conn_stat.guid;
|
||||
guid = &msg->u.conn_stat.guid;
|
||||
else if (msg->req_type == DP_RESOURCE_STATUS_NOTIFY)
|
||||
guid = msg->u.resource_stat.guid;
|
||||
guid = &msg->u.resource_stat.guid;
|
||||
|
||||
if (guid)
|
||||
mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid);
|
||||
@@ -5598,7 +5599,6 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_check_mgr);
|
||||
* drm_dp_atomic_release_time_slots()
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 0 if the new state is valid, negative error code otherwise.
|
||||
*/
|
||||
int drm_dp_mst_atomic_check(struct drm_atomic_state *state)
|
||||
@@ -5635,7 +5635,6 @@ EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs);
|
||||
* topology object.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* The MST topology state or error pointer.
|
||||
*/
|
||||
struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
|
||||
@@ -5655,7 +5654,6 @@ EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
|
||||
* topology object.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* The old MST topology state, or NULL if there's no topology state for this MST mgr
|
||||
* in the global atomic state
|
||||
*/
|
||||
@@ -5680,7 +5678,6 @@ EXPORT_SYMBOL(drm_atomic_get_old_mst_topology_state);
|
||||
* topology object.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* The new MST topology state, or NULL if there's no topology state for this MST mgr
|
||||
* in the global atomic state
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,6 @@ EXPORT_SYMBOL(__drm_crtc_commit_free);
|
||||
* hardware and flipped to.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
int drm_crtc_commit_wait(struct drm_crtc_commit *commit)
|
||||
@@ -337,7 +336,6 @@ EXPORT_SYMBOL(__drm_atomic_state_free);
|
||||
* not created by userspace through an IOCTL call.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted. All other errors are fatal.
|
||||
@@ -518,7 +516,6 @@ static int drm_atomic_connector_check(struct drm_connector *connector,
|
||||
* is consistent.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted. All other errors are fatal.
|
||||
@@ -828,7 +825,6 @@ EXPORT_SYMBOL(drm_atomic_private_obj_fini);
|
||||
* object lock to make sure that the state is consistent.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into a pointer.
|
||||
*/
|
||||
struct drm_private_state *
|
||||
@@ -1061,7 +1057,6 @@ EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
|
||||
* make sure that the state is consistent.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted. All other errors are fatal.
|
||||
@@ -1169,7 +1164,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
|
||||
* state is consistent.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted.
|
||||
|
||||
@@ -2266,7 +2266,6 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
|
||||
* automatically.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 0 on success. -EBUSY when userspace schedules nonblocking commits too fast,
|
||||
* -ENOMEM on allocation failures and -EINTR when a signal is pending.
|
||||
*/
|
||||
@@ -3009,7 +3008,6 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
|
||||
* don't pass the right state structures to the callbacks.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Returns 0 on success. Can return -ERESTARTSYS when @stall is true and the
|
||||
* waiting for the previous commits has been interrupted.
|
||||
*/
|
||||
|
||||
@@ -320,10 +320,14 @@ drm_edid_load_firmware(struct drm_connector *connector)
|
||||
bool drm_panic_is_enabled(struct drm_device *dev);
|
||||
void drm_panic_register(struct drm_device *dev);
|
||||
void drm_panic_unregister(struct drm_device *dev);
|
||||
void drm_panic_init(void);
|
||||
void drm_panic_exit(void);
|
||||
#else
|
||||
static inline bool drm_panic_is_enabled(struct drm_device *dev) { return false; }
|
||||
static inline void drm_panic_register(struct drm_device *dev) {}
|
||||
static inline void drm_panic_unregister(struct drm_device *dev) {}
|
||||
static inline void drm_panic_init(void) {}
|
||||
static inline void drm_panic_exit(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* __DRM_CRTC_INTERNAL_H__ */
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <linux/pseudo_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/srcu.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#include <drm/drm_accel.h>
|
||||
#include <drm/drm_cache.h>
|
||||
@@ -54,8 +55,7 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
|
||||
MODULE_DESCRIPTION("DRM shared core routines");
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
|
||||
static DEFINE_SPINLOCK(drm_minor_lock);
|
||||
static struct idr drm_minors_idr;
|
||||
DEFINE_XARRAY_ALLOC(drm_minors_xa);
|
||||
|
||||
/*
|
||||
* If the drm core fails to init for whatever reason,
|
||||
@@ -83,6 +83,18 @@ DEFINE_STATIC_SRCU(drm_unplug_srcu);
|
||||
* registered and unregistered dynamically according to device-state.
|
||||
*/
|
||||
|
||||
static struct xarray *drm_minor_get_xa(enum drm_minor_type type)
|
||||
{
|
||||
if (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER)
|
||||
return &drm_minors_xa;
|
||||
#if IS_ENABLED(CONFIG_DRM_ACCEL)
|
||||
else if (type == DRM_MINOR_ACCEL)
|
||||
return &accel_minors_xa;
|
||||
#endif
|
||||
else
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
|
||||
enum drm_minor_type type)
|
||||
{
|
||||
@@ -101,25 +113,31 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
|
||||
static void drm_minor_alloc_release(struct drm_device *dev, void *data)
|
||||
{
|
||||
struct drm_minor *minor = data;
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(dev != minor->dev);
|
||||
|
||||
put_device(minor->kdev);
|
||||
|
||||
if (minor->type == DRM_MINOR_ACCEL) {
|
||||
accel_minor_remove(minor->index);
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
idr_remove(&drm_minors_idr, minor->index);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
}
|
||||
xa_erase(drm_minor_get_xa(minor->type), minor->index);
|
||||
}
|
||||
|
||||
/*
|
||||
* DRM used to support 64 devices, for backwards compatibility we need to maintain the
|
||||
* minor allocation scheme where minors 0-63 are primary nodes, 64-127 are control nodes,
|
||||
* and 128-191 are render nodes.
|
||||
* After reaching the limit, we're allocating minors dynamically - first-come, first-serve.
|
||||
* Accel nodes are using a distinct major, so the minors are allocated in continuous 0-MAX
|
||||
* range.
|
||||
*/
|
||||
#define DRM_MINOR_LIMIT(t) ({ \
|
||||
typeof(t) _t = (t); \
|
||||
_t == DRM_MINOR_ACCEL ? XA_LIMIT(0, ACCEL_MAX_MINORS) : XA_LIMIT(64 * _t, 64 * _t + 63); \
|
||||
})
|
||||
#define DRM_EXTENDED_MINOR_LIMIT XA_LIMIT(192, (1 << MINORBITS) - 1)
|
||||
|
||||
static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL);
|
||||
@@ -129,25 +147,14 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
|
||||
minor->type = type;
|
||||
minor->dev = dev;
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
if (type == DRM_MINOR_ACCEL) {
|
||||
r = accel_minor_alloc();
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
r = idr_alloc(&drm_minors_idr,
|
||||
NULL,
|
||||
64 * type,
|
||||
64 * (type + 1),
|
||||
GFP_NOWAIT);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
}
|
||||
idr_preload_end();
|
||||
|
||||
r = xa_alloc(drm_minor_get_xa(type), &minor->index,
|
||||
NULL, DRM_MINOR_LIMIT(type), GFP_KERNEL);
|
||||
if (r == -EBUSY && (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER))
|
||||
r = xa_alloc(&drm_minors_xa, &minor->index,
|
||||
NULL, DRM_EXTENDED_MINOR_LIMIT, GFP_KERNEL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
minor->index = r;
|
||||
|
||||
r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);
|
||||
if (r)
|
||||
return r;
|
||||
@@ -163,7 +170,7 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
|
||||
static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
void *entry;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
@@ -186,13 +193,12 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
|
||||
goto err_debugfs;
|
||||
|
||||
/* replace NULL with @minor so lookups will succeed from now on */
|
||||
if (minor->type == DRM_MINOR_ACCEL) {
|
||||
accel_minor_replace(minor, minor->index);
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
idr_replace(&drm_minors_idr, minor, minor->index);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
entry = xa_store(drm_minor_get_xa(type), minor->index, minor, GFP_KERNEL);
|
||||
if (xa_is_err(entry)) {
|
||||
ret = xa_err(entry);
|
||||
goto err_debugfs;
|
||||
}
|
||||
WARN_ON(entry);
|
||||
|
||||
DRM_DEBUG("new minor registered %d\n", minor->index);
|
||||
return 0;
|
||||
@@ -205,20 +211,13 @@ err_debugfs:
|
||||
static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type type)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
|
||||
minor = *drm_minor_get_slot(dev, type);
|
||||
if (!minor || !device_is_registered(minor->kdev))
|
||||
return;
|
||||
|
||||
/* replace @minor with NULL so lookups will fail from now on */
|
||||
if (minor->type == DRM_MINOR_ACCEL) {
|
||||
accel_minor_replace(NULL, minor->index);
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
idr_replace(&drm_minors_idr, NULL, minor->index);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
}
|
||||
xa_store(drm_minor_get_xa(type), minor->index, NULL, GFP_KERNEL);
|
||||
|
||||
device_del(minor->kdev);
|
||||
dev_set_drvdata(minor->kdev, NULL); /* safety belt */
|
||||
@@ -234,16 +233,15 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ
|
||||
* minor->dev pointer will stay valid! However, the device may get unplugged and
|
||||
* unregistered while you hold the minor.
|
||||
*/
|
||||
struct drm_minor *drm_minor_acquire(unsigned int minor_id)
|
||||
struct drm_minor *drm_minor_acquire(struct xarray *minor_xa, unsigned int minor_id)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
minor = idr_find(&drm_minors_idr, minor_id);
|
||||
xa_lock(minor_xa);
|
||||
minor = xa_load(minor_xa, minor_id);
|
||||
if (minor)
|
||||
drm_dev_get(minor->dev);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
xa_unlock(minor_xa);
|
||||
|
||||
if (!minor) {
|
||||
return ERR_PTR(-ENODEV);
|
||||
@@ -1036,7 +1034,7 @@ static int drm_stub_open(struct inode *inode, struct file *filp)
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
minor = drm_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -1067,11 +1065,12 @@ static const struct file_operations drm_stub_fops = {
|
||||
static void drm_core_exit(void)
|
||||
{
|
||||
drm_privacy_screen_lookup_exit();
|
||||
drm_panic_exit();
|
||||
accel_core_exit();
|
||||
unregister_chrdev(DRM_MAJOR, "drm");
|
||||
debugfs_remove(drm_debugfs_root);
|
||||
drm_sysfs_destroy();
|
||||
idr_destroy(&drm_minors_idr);
|
||||
WARN_ON(!xa_empty(&drm_minors_xa));
|
||||
drm_connector_ida_destroy();
|
||||
}
|
||||
|
||||
@@ -1080,7 +1079,6 @@ static int __init drm_core_init(void)
|
||||
int ret;
|
||||
|
||||
drm_connector_ida_init();
|
||||
idr_init(&drm_minors_idr);
|
||||
drm_memcpy_init_early();
|
||||
|
||||
ret = drm_sysfs_init();
|
||||
@@ -1099,6 +1097,8 @@ static int __init drm_core_init(void)
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
drm_panic_init();
|
||||
|
||||
drm_privacy_screen_lookup_init();
|
||||
|
||||
drm_core_init_complete = true;
|
||||
|
||||
@@ -347,7 +347,6 @@ int drm_open_helper(struct file *filp, struct drm_minor *minor)
|
||||
* resources for it. It also calls the &drm_driver.open driver callback.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success or negative errno value on failure.
|
||||
*/
|
||||
int drm_open(struct inode *inode, struct file *filp)
|
||||
@@ -356,7 +355,7 @@ int drm_open(struct inode *inode, struct file *filp)
|
||||
struct drm_minor *minor;
|
||||
int retcode;
|
||||
|
||||
minor = drm_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -406,7 +405,6 @@ static void drm_lastclose(struct drm_device *dev)
|
||||
* in-kernel DRM client.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Always succeeds and returns 0.
|
||||
*/
|
||||
int drm_release(struct inode *inode, struct file *filp)
|
||||
@@ -477,7 +475,6 @@ void drm_file_update_pid(struct drm_file *filp)
|
||||
* then restores the active in-kernel DRM client.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Always succeeds and returns 0.
|
||||
*/
|
||||
int drm_release_noglobal(struct inode *inode, struct file *filp)
|
||||
@@ -520,7 +517,6 @@ EXPORT_SYMBOL(drm_release_noglobal);
|
||||
* safety.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Number of bytes read (always aligned to full events, and can be 0) or a
|
||||
* negative error code on failure.
|
||||
*/
|
||||
@@ -606,7 +602,6 @@ EXPORT_SYMBOL(drm_read);
|
||||
* See also drm_read().
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Mask of POLL flags indicating the current status of the file.
|
||||
*/
|
||||
__poll_t drm_poll(struct file *filp, struct poll_table_struct *wait)
|
||||
@@ -644,7 +639,6 @@ EXPORT_SYMBOL(drm_poll);
|
||||
* already hold &drm_device.event_lock.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_event_reserve_init_locked(struct drm_device *dev,
|
||||
@@ -686,7 +680,6 @@ EXPORT_SYMBOL(drm_event_reserve_init_locked);
|
||||
* drm_event_reserve_init_locked() instead.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_event_reserve_init(struct drm_device *dev,
|
||||
|
||||
@@ -689,7 +689,6 @@ static int objects_lookup(struct drm_file *filp, u32 *handle, int count,
|
||||
* For a single handle lookup, use drm_gem_object_lookup().
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* @objs filled in with GEM object pointers. Returned GEM objects need to be
|
||||
* released with drm_gem_object_put(). -ENOENT is returned on a lookup
|
||||
* failure. 0 is returned on success.
|
||||
@@ -737,12 +736,11 @@ EXPORT_SYMBOL(drm_gem_objects_lookup);
|
||||
* @filp: DRM file private date
|
||||
* @handle: userspace handle
|
||||
*
|
||||
* Returns:
|
||||
* If looking up an array of handles, use drm_gem_objects_lookup().
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the object named by the handle if such exists on @filp, NULL
|
||||
* otherwise.
|
||||
*
|
||||
* If looking up an array of handles, use drm_gem_objects_lookup().
|
||||
*/
|
||||
struct drm_gem_object *
|
||||
drm_gem_object_lookup(struct drm_file *filp, u32 handle)
|
||||
@@ -763,7 +761,6 @@ EXPORT_SYMBOL(drm_gem_object_lookup);
|
||||
* @timeout: timeout value in jiffies or zero to return immediately
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
|
||||
* greater than 0 on success.
|
||||
*/
|
||||
|
||||
@@ -80,10 +80,6 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
|
||||
void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
|
||||
uint32_t handle);
|
||||
|
||||
/* drm_drv.c */
|
||||
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
|
||||
void drm_minor_release(struct drm_minor *minor);
|
||||
|
||||
/* drm_managed.c */
|
||||
void drm_managed_release(struct drm_device *dev);
|
||||
void drmm_add_final_kfree(struct drm_device *dev, void *container);
|
||||
|
||||
@@ -539,7 +539,6 @@ static int fill_analog_mode(struct drm_device *dev,
|
||||
* to reach those resolutions.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* A pointer to the mode, allocated with drm_mode_create(). Returns NULL
|
||||
* on error.
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
@@ -26,6 +28,7 @@
|
||||
#include <drm/drm_panic.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_rect.h>
|
||||
|
||||
#include "drm_crtc_internal.h"
|
||||
|
||||
@@ -85,7 +88,7 @@ static struct drm_panic_line panic_msg[] = {
|
||||
PANIC_LINE(""), /* will be replaced by the panic description */
|
||||
};
|
||||
|
||||
#define PANIC_MSG_LINES ARRAY_SIZE(panic_msg)
|
||||
static const size_t panic_msg_lines = ARRAY_SIZE(panic_msg);
|
||||
|
||||
static const struct drm_panic_line logo_ascii[] = {
|
||||
PANIC_LINE(" .--. _"),
|
||||
@@ -97,7 +100,7 @@ static const struct drm_panic_line logo_ascii[] = {
|
||||
PANIC_LINE(" \\___)=(___/"),
|
||||
};
|
||||
|
||||
#define PANIC_LOGO_LINES ARRAY_SIZE(logo_ascii)
|
||||
static const size_t logo_ascii_lines = ARRAY_SIZE(logo_ascii);
|
||||
|
||||
#if defined(CONFIG_LOGO) && !defined(MODULE)
|
||||
static const struct linux_logo *logo_mono;
|
||||
@@ -257,20 +260,20 @@ static bool drm_panic_is_pixel_fg(const u8 *sbuf8, unsigned int spitch, int x, i
|
||||
static void drm_panic_blit16(struct iosys_map *dmap, unsigned int dpitch,
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int height, unsigned int width,
|
||||
u16 fg16)
|
||||
unsigned int scale, u16 fg16)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
|
||||
iosys_map_wr(dmap, y * dpitch + x * sizeof(u16), u16, fg16);
|
||||
}
|
||||
|
||||
static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int height, unsigned int width,
|
||||
u32 fg32)
|
||||
unsigned int scale, u32 fg32)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
@@ -278,7 +281,7 @@ static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
|
||||
for (x = 0; x < width; x++) {
|
||||
u32 off = y * dpitch + x * 3;
|
||||
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y)) {
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) {
|
||||
/* write blue-green-red to output in little endianness */
|
||||
iosys_map_wr(dmap, off, u8, (fg32 & 0x000000FF) >> 0);
|
||||
iosys_map_wr(dmap, off + 1, u8, (fg32 & 0x0000FF00) >> 8);
|
||||
@@ -291,24 +294,25 @@ static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
|
||||
static void drm_panic_blit32(struct iosys_map *dmap, unsigned int dpitch,
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int height, unsigned int width,
|
||||
u32 fg32)
|
||||
unsigned int scale, u32 fg32)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
|
||||
iosys_map_wr(dmap, y * dpitch + x * sizeof(u32), u32, fg32);
|
||||
}
|
||||
|
||||
static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect *clip,
|
||||
const u8 *sbuf8, unsigned int spitch, u32 fg_color)
|
||||
const u8 *sbuf8, unsigned int spitch, unsigned int scale,
|
||||
u32 fg_color)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
for (y = 0; y < drm_rect_height(clip); y++)
|
||||
for (x = 0; x < drm_rect_width(clip); x++)
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
|
||||
sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, fg_color);
|
||||
}
|
||||
|
||||
@@ -318,18 +322,22 @@ static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect
|
||||
* @clip: destination rectangle
|
||||
* @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
|
||||
* @spitch: source pitch in bytes
|
||||
* @scale: integer scale, source buffer is scale time smaller than destination
|
||||
* rectangle
|
||||
* @fg_color: foreground color, in destination format
|
||||
*
|
||||
* This can be used to draw a font character, which is a monochrome image, to a
|
||||
* framebuffer in other supported format.
|
||||
*/
|
||||
static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip,
|
||||
const u8 *sbuf8, unsigned int spitch, u32 fg_color)
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int scale, u32 fg_color)
|
||||
|
||||
{
|
||||
struct iosys_map map;
|
||||
|
||||
if (sb->set_pixel)
|
||||
return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, fg_color);
|
||||
return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, scale, fg_color);
|
||||
|
||||
map = sb->map[0];
|
||||
iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]);
|
||||
@@ -337,15 +345,15 @@ static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip,
|
||||
switch (sb->format->cpp[0]) {
|
||||
case 2:
|
||||
drm_panic_blit16(&map, sb->pitch[0], sbuf8, spitch,
|
||||
drm_rect_height(clip), drm_rect_width(clip), fg_color);
|
||||
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
|
||||
break;
|
||||
case 3:
|
||||
drm_panic_blit24(&map, sb->pitch[0], sbuf8, spitch,
|
||||
drm_rect_height(clip), drm_rect_width(clip), fg_color);
|
||||
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
|
||||
break;
|
||||
case 4:
|
||||
drm_panic_blit32(&map, sb->pitch[0], sbuf8, spitch,
|
||||
drm_rect_height(clip), drm_rect_width(clip), fg_color);
|
||||
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Can't blit with pixel width %d\n", sb->format->cpp[0]);
|
||||
@@ -485,37 +493,50 @@ static void draw_txt_rectangle(struct drm_scanout_buffer *sb,
|
||||
for (j = 0; j < line_len; j++) {
|
||||
src = get_char_bitmap(font, msg[i].txt[j], font_pitch);
|
||||
rec.x2 = rec.x1 + font->width;
|
||||
drm_panic_blit(sb, &rec, src, font_pitch, color);
|
||||
drm_panic_blit(sb, &rec, src, font_pitch, 1, color);
|
||||
rec.x1 += font->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_panic_logo_rect(struct drm_rect *rect, const struct font_desc *font)
|
||||
{
|
||||
if (logo_mono) {
|
||||
drm_rect_init(rect, 0, 0, logo_mono->width, logo_mono->height);
|
||||
} else {
|
||||
int logo_width = get_max_line_len(logo_ascii, logo_ascii_lines) * font->width;
|
||||
|
||||
drm_rect_init(rect, 0, 0, logo_width, logo_ascii_lines * font->height);
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_panic_logo_draw(struct drm_scanout_buffer *sb, struct drm_rect *rect,
|
||||
const struct font_desc *font, u32 fg_color)
|
||||
{
|
||||
if (logo_mono)
|
||||
drm_panic_blit(sb, rect, logo_mono->data,
|
||||
DIV_ROUND_UP(drm_rect_width(rect), 8), 1, fg_color);
|
||||
else
|
||||
draw_txt_rectangle(sb, font, logo_ascii, logo_ascii_lines, false, rect,
|
||||
fg_color);
|
||||
}
|
||||
|
||||
static void draw_panic_static_user(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
|
||||
u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
|
||||
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
|
||||
struct drm_rect r_screen, r_logo, r_msg;
|
||||
unsigned int logo_width, logo_height;
|
||||
unsigned int msg_width, msg_height;
|
||||
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
|
||||
drm_panic_logo_rect(&r_logo, font);
|
||||
|
||||
if (logo_mono) {
|
||||
logo_width = logo_mono->width;
|
||||
logo_height = logo_mono->height;
|
||||
} else {
|
||||
logo_width = get_max_line_len(logo_ascii, PANIC_LOGO_LINES) * font->width;
|
||||
logo_height = PANIC_LOGO_LINES * font->height;
|
||||
}
|
||||
r_logo = DRM_RECT_INIT(0, 0, logo_width, logo_height);
|
||||
|
||||
msg_width = min(get_max_line_len(panic_msg, PANIC_MSG_LINES) * font->width, sb->width);
|
||||
msg_height = min(PANIC_MSG_LINES * font->height, sb->height);
|
||||
msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
|
||||
msg_height = min(panic_msg_lines * font->height, sb->height);
|
||||
r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
|
||||
|
||||
/* Center the panic message */
|
||||
@@ -524,16 +545,10 @@ static void draw_panic_static_user(struct drm_scanout_buffer *sb)
|
||||
/* Fill with the background color, and draw text on top */
|
||||
drm_panic_fill(sb, &r_screen, bg_color);
|
||||
|
||||
if ((r_msg.x1 >= logo_width || r_msg.y1 >= logo_height) &&
|
||||
logo_width <= sb->width && logo_height <= sb->height) {
|
||||
if (logo_mono)
|
||||
drm_panic_blit(sb, &r_logo, logo_mono->data, DIV_ROUND_UP(logo_width, 8),
|
||||
fg_color);
|
||||
else
|
||||
draw_txt_rectangle(sb, font, logo_ascii, PANIC_LOGO_LINES, false, &r_logo,
|
||||
fg_color);
|
||||
}
|
||||
draw_txt_rectangle(sb, font, panic_msg, PANIC_MSG_LINES, true, &r_msg, fg_color);
|
||||
if (!drm_rect_overlap(&r_logo, &r_msg))
|
||||
drm_panic_logo_draw(sb, &r_logo, font, fg_color);
|
||||
|
||||
draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -615,6 +630,233 @@ static void draw_panic_static_kmsg(struct drm_scanout_buffer *sb)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
|
||||
/*
|
||||
* It is unwise to allocate memory in the panic callback, so the buffers are
|
||||
* pre-allocated. Only 2 buffers and the zlib workspace are needed.
|
||||
* Two buffers are enough, using the following buffer usage:
|
||||
* 1) kmsg messages are dumped in buffer1
|
||||
* 2) kmsg is zlib-compressed into buffer2
|
||||
* 3) compressed kmsg is encoded as QR-code Numeric stream in buffer1
|
||||
* 4) QR-code image is generated in buffer2
|
||||
* The Max QR code size is V40, 177x177, 4071 bytes for image, 2956 bytes for
|
||||
* data segments.
|
||||
*
|
||||
* Typically, ~7500 bytes of kmsg, are compressed into 2800 bytes, which fits in
|
||||
* a V40 QR-code (177x177).
|
||||
*
|
||||
* If CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL is not set, the kmsg data will be put
|
||||
* directly in the QR code.
|
||||
* 1) kmsg messages are dumped in buffer1
|
||||
* 2) kmsg message is encoded as byte stream in buffer2
|
||||
* 3) QR-code image is generated in buffer1
|
||||
*/
|
||||
|
||||
static uint panic_qr_version = CONFIG_DRM_PANIC_SCREEN_QR_VERSION;
|
||||
module_param(panic_qr_version, uint, 0644);
|
||||
MODULE_PARM_DESC(panic_qr_version, "maximum version (size) of the QR code");
|
||||
|
||||
#define MAX_QR_DATA 2956
|
||||
#define MAX_ZLIB_RATIO 3
|
||||
#define QR_BUFFER1_SIZE (MAX_ZLIB_RATIO * MAX_QR_DATA) /* Must also be > 4071 */
|
||||
#define QR_BUFFER2_SIZE 4096
|
||||
#define QR_MARGIN 4 /* 4 modules of foreground color around the qr code */
|
||||
|
||||
/* Compression parameters */
|
||||
#define COMPR_LEVEL 6
|
||||
#define WINDOW_BITS 12
|
||||
#define MEM_LEVEL 4
|
||||
|
||||
static char *qrbuf1;
|
||||
static char *qrbuf2;
|
||||
static struct z_stream_s stream;
|
||||
|
||||
static void __init drm_panic_qr_init(void)
|
||||
{
|
||||
qrbuf1 = kmalloc(QR_BUFFER1_SIZE, GFP_KERNEL);
|
||||
qrbuf2 = kmalloc(QR_BUFFER2_SIZE, GFP_KERNEL);
|
||||
stream.workspace = kmalloc(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void drm_panic_qr_exit(void)
|
||||
{
|
||||
kfree(qrbuf1);
|
||||
qrbuf1 = NULL;
|
||||
kfree(qrbuf2);
|
||||
qrbuf2 = NULL;
|
||||
kfree(stream.workspace);
|
||||
stream.workspace = NULL;
|
||||
}
|
||||
|
||||
extern size_t drm_panic_qr_max_data_size(u8 version, size_t url_len);
|
||||
|
||||
extern u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size,
|
||||
u8 *tmp, size_t tmp_size);
|
||||
|
||||
static int drm_panic_get_qr_code_url(u8 **qr_image)
|
||||
{
|
||||
struct kmsg_dump_iter iter;
|
||||
char url[256];
|
||||
size_t kmsg_len, max_kmsg_size;
|
||||
char *kmsg;
|
||||
int max_qr_data_size, url_len;
|
||||
|
||||
url_len = snprintf(url, sizeof(url), CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL "?a=%s&v=%s&zl=",
|
||||
utsname()->machine, utsname()->release);
|
||||
|
||||
max_qr_data_size = drm_panic_qr_max_data_size(panic_qr_version, url_len);
|
||||
max_kmsg_size = min(MAX_ZLIB_RATIO * max_qr_data_size, QR_BUFFER1_SIZE);
|
||||
|
||||
/* get kmsg to buffer 1 */
|
||||
kmsg_dump_rewind(&iter);
|
||||
kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
|
||||
|
||||
if (!kmsg_len)
|
||||
return -ENODATA;
|
||||
kmsg = qrbuf1;
|
||||
|
||||
try_again:
|
||||
if (zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
|
||||
MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||
return -EINVAL;
|
||||
|
||||
stream.next_in = kmsg;
|
||||
stream.avail_in = kmsg_len;
|
||||
stream.total_in = 0;
|
||||
stream.next_out = qrbuf2;
|
||||
stream.avail_out = QR_BUFFER2_SIZE;
|
||||
stream.total_out = 0;
|
||||
|
||||
if (zlib_deflate(&stream, Z_FINISH) != Z_STREAM_END)
|
||||
return -EINVAL;
|
||||
|
||||
if (zlib_deflateEnd(&stream) != Z_OK)
|
||||
return -EINVAL;
|
||||
|
||||
if (stream.total_out > max_qr_data_size) {
|
||||
/* too much data for the QR code, so skip the first line and try again */
|
||||
kmsg = strchr(kmsg, '\n');
|
||||
if (!kmsg)
|
||||
return -EINVAL;
|
||||
/* skip the first \n */
|
||||
kmsg += 1;
|
||||
kmsg_len = strlen(kmsg);
|
||||
goto try_again;
|
||||
}
|
||||
*qr_image = qrbuf2;
|
||||
|
||||
/* generate qr code image in buffer2 */
|
||||
return drm_panic_qr_generate(url, qrbuf2, stream.total_out, QR_BUFFER2_SIZE,
|
||||
qrbuf1, QR_BUFFER1_SIZE);
|
||||
}
|
||||
|
||||
static int drm_panic_get_qr_code_raw(u8 **qr_image)
|
||||
{
|
||||
struct kmsg_dump_iter iter;
|
||||
size_t kmsg_len;
|
||||
size_t max_kmsg_size = min(drm_panic_qr_max_data_size(panic_qr_version, 0),
|
||||
QR_BUFFER1_SIZE);
|
||||
|
||||
kmsg_dump_rewind(&iter);
|
||||
kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
|
||||
if (!kmsg_len)
|
||||
return -ENODATA;
|
||||
|
||||
*qr_image = qrbuf1;
|
||||
return drm_panic_qr_generate(NULL, qrbuf1, kmsg_len, QR_BUFFER1_SIZE,
|
||||
qrbuf2, QR_BUFFER2_SIZE);
|
||||
}
|
||||
|
||||
static int drm_panic_get_qr_code(u8 **qr_image)
|
||||
{
|
||||
if (strlen(CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL) > 0)
|
||||
return drm_panic_get_qr_code_url(qr_image);
|
||||
else
|
||||
return drm_panic_get_qr_code_raw(qr_image);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the panic message at the center of the screen, with a QR Code
|
||||
*/
|
||||
static int _draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
|
||||
u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
|
||||
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
|
||||
struct drm_rect r_screen, r_logo, r_msg, r_qr, r_qr_canvas;
|
||||
unsigned int max_qr_size, scale;
|
||||
unsigned int msg_width, msg_height;
|
||||
int qr_width, qr_canvas_width, qr_pitch, v_margin;
|
||||
u8 *qr_image;
|
||||
|
||||
if (!font || !qrbuf1 || !qrbuf2 || !stream.workspace)
|
||||
return -ENOMEM;
|
||||
|
||||
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
|
||||
|
||||
drm_panic_logo_rect(&r_logo, font);
|
||||
|
||||
msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
|
||||
msg_height = min(panic_msg_lines * font->height, sb->height);
|
||||
r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
|
||||
|
||||
max_qr_size = min(3 * sb->width / 4, 3 * sb->height / 4);
|
||||
|
||||
qr_width = drm_panic_get_qr_code(&qr_image);
|
||||
if (qr_width <= 0)
|
||||
return -ENOSPC;
|
||||
|
||||
qr_canvas_width = qr_width + QR_MARGIN * 2;
|
||||
scale = max_qr_size / qr_canvas_width;
|
||||
/* QR code is not readable if not scaled at least by 2 */
|
||||
if (scale < 2)
|
||||
return -ENOSPC;
|
||||
|
||||
pr_debug("QR width %d and scale %d\n", qr_width, scale);
|
||||
r_qr_canvas = DRM_RECT_INIT(0, 0, qr_canvas_width * scale, qr_canvas_width * scale);
|
||||
|
||||
v_margin = (sb->height - drm_rect_height(&r_qr_canvas) - drm_rect_height(&r_msg)) / 5;
|
||||
|
||||
drm_rect_translate(&r_qr_canvas, (sb->width - r_qr_canvas.x2) / 2, 2 * v_margin);
|
||||
r_qr = DRM_RECT_INIT(r_qr_canvas.x1 + QR_MARGIN * scale, r_qr_canvas.y1 + QR_MARGIN * scale,
|
||||
qr_width * scale, qr_width * scale);
|
||||
|
||||
/* Center the panic message */
|
||||
drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2,
|
||||
3 * v_margin + drm_rect_height(&r_qr_canvas));
|
||||
|
||||
/* Fill with the background color, and draw text on top */
|
||||
drm_panic_fill(sb, &r_screen, bg_color);
|
||||
|
||||
if (!drm_rect_overlap(&r_logo, &r_msg) && !drm_rect_overlap(&r_logo, &r_qr))
|
||||
drm_panic_logo_draw(sb, &r_logo, font, fg_color);
|
||||
|
||||
draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
|
||||
|
||||
/* Draw the qr code */
|
||||
qr_pitch = DIV_ROUND_UP(qr_width, 8);
|
||||
drm_panic_fill(sb, &r_qr_canvas, fg_color);
|
||||
drm_panic_fill(sb, &r_qr, bg_color);
|
||||
drm_panic_blit(sb, &r_qr, qr_image, qr_pitch, scale, fg_color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
if (_draw_panic_static_qr_code(sb))
|
||||
draw_panic_static_user(sb);
|
||||
}
|
||||
#else
|
||||
static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
draw_panic_static_user(sb);
|
||||
}
|
||||
|
||||
static void drm_panic_qr_init(void) {};
|
||||
static void drm_panic_qr_exit(void) {};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* drm_panic_is_format_supported()
|
||||
* @format: a fourcc color code
|
||||
@@ -633,6 +875,8 @@ static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
if (!strcmp(drm_panic_screen, "kmsg")) {
|
||||
draw_panic_static_kmsg(sb);
|
||||
} else if (!strcmp(drm_panic_screen, "qr_code")) {
|
||||
draw_panic_static_qr_code(sb);
|
||||
} else {
|
||||
draw_panic_static_user(sb);
|
||||
}
|
||||
@@ -643,7 +887,7 @@ static void drm_panic_set_description(const char *description)
|
||||
u32 len;
|
||||
|
||||
if (description) {
|
||||
struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1];
|
||||
struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
|
||||
|
||||
desc_line->txt = description;
|
||||
len = strlen(description);
|
||||
@@ -656,7 +900,7 @@ static void drm_panic_set_description(const char *description)
|
||||
|
||||
static void drm_panic_clear_description(void)
|
||||
{
|
||||
struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1];
|
||||
struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
|
||||
|
||||
desc_line->len = 0;
|
||||
desc_line->txt = NULL;
|
||||
@@ -802,3 +1046,19 @@ void drm_panic_unregister(struct drm_device *dev)
|
||||
kmsg_dump_unregister(&plane->kmsg_panic);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_panic_init() - initialize DRM panic.
|
||||
*/
|
||||
void __init drm_panic_init(void)
|
||||
{
|
||||
drm_panic_qr_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_panic_exit() - Free the resources taken by drm_panic_exit()
|
||||
*/
|
||||
void drm_panic_exit(void)
|
||||
{
|
||||
drm_panic_qr_exit();
|
||||
}
|
||||
|
||||
1003
drivers/gpu/drm/drm_panic_qr.rs
Normal file
1003
drivers/gpu/drm/drm_panic_qr.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,6 @@ static u32 clip_scaled(int src, int dst, int *clip)
|
||||
* factors from @src to @dst.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* %true if rectangle @dst is still visible after being clipped,
|
||||
* %false otherwise.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user