drm-misc-next for v7.1:

Cross-subsystem Changes:
 
 dma-buf:
 - Prepare for compile-time concurrency analysis
 
 Core Changes:
 
 buddy:
 - Improve assert testing
 
 sched:
 - Fix race condition in drm_sched_fini()
 - Mark slow tests
 
 Driver Changes:
 
 bridge:
 - waveshare-dsi: Fix register and attach; Support 1..4 DSI lanes plus DT bindings
 
 gma500:
 - Use DRM client buffer for fbdev framebuffer
 
 gud:
 - Test for imported buffers with helper
 
 imagination:
 - Fix power domain handling
 
 ivpu:
 - Update boot API to v3.29.4
 - Limit per-user number of doorbells and contexts
 
 nouveau:
 - Test for imported buffers with helper
 
 panel:
 - panel-edp: Fix timings for BOE NV140WUM-N64
 
 panfrost:
 - Test for imported buffers with helper
 
 panthor:
 - Test for imported buffers with helper
 
 vc4:
 - Test for imported buffers with helper
 -----BEGIN PGP SIGNATURE-----
 
 iQFPBAABCgA5FiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmmpOo4bFIAAAAAABAAO
 bWFudTIsMi41KzEuMTIsMiwyAAoJEGgNwR1TC3oj7ZkIAIgJzirL4ZoSEojD2MRd
 OC0I7PZBLEVT5JvQ1IEt//FaD0bIBjwvyd0LTuRLK+Q6/trY+cOBuLJ2YRaTdZOY
 FrfNU9kifJueJzeVpeJWS0nMZi4DvhR/3AEgKkJ1fRJT14qkPr1Rl1lJdocwygIx
 N/qV6P8JujOVC61aGB/KIwrgzSuOkOUu6KRqEu2daB83kc8x+Mwy1Yy04h4Fd43W
 d/NN327LE9pV2MD8ASlok00kAwqalkcraevIS9LgFkLY9s4xaICNcBn8eJl+VmXz
 OmSfrko5hXgUX0ijvyI2jaxx9F1zbrtmv0sj4g5OhVIZcy2ATaASusmxRrHYJR/8
 JZ8=
 =1puI
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2026-03-05' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v7.1:

Cross-subsystem Changes:

dma-buf:
- Prepare for compile-time concurrency analysis

Core Changes:

buddy:
- Improve assert testing

sched:
- Fix race condition in drm_sched_fini()
- Mark slow tests

Driver Changes:

bridge:
- waveshare-dsi: Fix register and attach; Support 1..4 DSI lanes plus DT bindings

gma500:
- Use DRM client buffer for fbdev framebuffer

gud:
- Test for imported buffers with helper

imagination:
- Fix power domain handling

ivpu:
- Update boot API to v3.29.4
- Limit per-user number of doorbells and contexts

nouveau:
- Test for imported buffers with helper

panel:
- panel-edp: Fix timings for BOE NV140WUM-N64

panfrost:
- Test for imported buffers with helper

panthor:
- Test for imported buffers with helper

vc4:
- Test for imported buffers with helper

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260305081140.GA171266@linux.fritz.box
This commit is contained in:
Dave Airlie 2026-03-09 06:06:57 +10:00
commit 5f0a63f81a
24 changed files with 388 additions and 371 deletions

View File

@ -40,9 +40,12 @@ properties:
properties:
data-lanes:
description: array of physical DSI data lane indexes.
minItems: 1
items:
- const: 1
- const: 2
- const: 3
- const: 4
required:
- data-lanes

View File

@ -67,6 +67,73 @@ bool ivpu_force_snoop;
module_param_named(force_snoop, ivpu_force_snoop, bool, 0444);
MODULE_PARM_DESC(force_snoop, "Force snooping for NPU host memory access");
static struct ivpu_user_limits *ivpu_user_limits_alloc(struct ivpu_device *vdev, uid_t uid)
{
struct ivpu_user_limits *limits;
limits = kzalloc_obj(*limits);
if (!limits)
return ERR_PTR(-ENOMEM);
kref_init(&limits->ref);
atomic_set(&limits->db_count, 0);
limits->vdev = vdev;
limits->uid = uid;
/* Allow root user to allocate all contexts */
if (uid == 0) {
limits->max_ctx_count = ivpu_get_context_count(vdev);
limits->max_db_count = ivpu_get_doorbell_count(vdev);
} else {
limits->max_ctx_count = ivpu_get_context_count(vdev) / 2;
limits->max_db_count = ivpu_get_doorbell_count(vdev) / 2;
}
hash_add(vdev->user_limits, &limits->hash_node, uid);
return limits;
}
static struct ivpu_user_limits *ivpu_user_limits_get(struct ivpu_device *vdev)
{
struct ivpu_user_limits *limits;
uid_t uid = current_uid().val;
guard(mutex)(&vdev->user_limits_lock);
hash_for_each_possible(vdev->user_limits, limits, hash_node, uid) {
if (limits->uid == uid) {
if (kref_read(&limits->ref) >= limits->max_ctx_count) {
ivpu_dbg(vdev, IOCTL, "User %u exceeded max ctx count %u\n", uid,
limits->max_ctx_count);
return ERR_PTR(-EMFILE);
}
kref_get(&limits->ref);
return limits;
}
}
return ivpu_user_limits_alloc(vdev, uid);
}
static void ivpu_user_limits_release(struct kref *ref)
{
struct ivpu_user_limits *limits = container_of(ref, struct ivpu_user_limits, ref);
struct ivpu_device *vdev = limits->vdev;
lockdep_assert_held(&vdev->user_limits_lock);
drm_WARN_ON(&vdev->drm, atomic_read(&limits->db_count));
hash_del(&limits->hash_node);
kfree(limits);
}
static void ivpu_user_limits_put(struct ivpu_device *vdev, struct ivpu_user_limits *limits)
{
guard(mutex)(&vdev->user_limits_lock);
kref_put(&limits->ref, ivpu_user_limits_release);
}
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
{
struct ivpu_device *vdev = file_priv->vdev;
@ -110,6 +177,7 @@ static void file_priv_release(struct kref *ref)
mutex_unlock(&vdev->context_list_lock);
pm_runtime_put_autosuspend(vdev->drm.dev);
ivpu_user_limits_put(vdev, file_priv->user_limits);
mutex_destroy(&file_priv->ms_lock);
mutex_destroy(&file_priv->lock);
kfree(file_priv);
@ -169,7 +237,7 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
args->value = ivpu_hw_dpu_max_freq_get(vdev);
break;
case DRM_IVPU_PARAM_NUM_CONTEXTS:
args->value = ivpu_get_context_count(vdev);
args->value = file_priv->user_limits->max_ctx_count;
break;
case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
args->value = vdev->hw->ranges.user.start;
@ -231,22 +299,30 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file)
{
struct ivpu_device *vdev = to_ivpu_device(dev);
struct ivpu_file_priv *file_priv;
struct ivpu_user_limits *limits;
u32 ctx_id;
int idx, ret;
if (!drm_dev_enter(dev, &idx))
return -ENODEV;
limits = ivpu_user_limits_get(vdev);
if (IS_ERR(limits)) {
ret = PTR_ERR(limits);
goto err_dev_exit;
}
file_priv = kzalloc_obj(*file_priv);
if (!file_priv) {
ret = -ENOMEM;
goto err_dev_exit;
goto err_user_limits_put;
}
INIT_LIST_HEAD(&file_priv->ms_instance_list);
file_priv->vdev = vdev;
file_priv->bound = true;
file_priv->user_limits = limits;
kref_init(&file_priv->ref);
mutex_init(&file_priv->lock);
mutex_init(&file_priv->ms_lock);
@ -284,6 +360,8 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file)
mutex_destroy(&file_priv->ms_lock);
mutex_destroy(&file_priv->lock);
kfree(file_priv);
err_user_limits_put:
ivpu_user_limits_put(vdev, limits);
err_dev_exit:
drm_dev_exit(idx);
return ret;
@ -343,8 +421,7 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev)
ivpu_ipc_consumer_del(vdev, &cons);
if (!ret && ipc_hdr.data_addr != IVPU_IPC_BOOT_MSG_DATA_ADDR) {
ivpu_err(vdev, "Invalid NPU ready message: 0x%x\n",
ipc_hdr.data_addr);
ivpu_err(vdev, "Invalid NPU ready message: 0x%x\n", ipc_hdr.data_addr);
return -EIO;
}
@ -453,7 +530,7 @@ int ivpu_shutdown(struct ivpu_device *vdev)
}
static const struct file_operations ivpu_fops = {
.owner = THIS_MODULE,
.owner = THIS_MODULE,
DRM_ACCEL_FOPS,
#ifdef CONFIG_PROC_FS
.show_fdinfo = drm_show_fdinfo,
@ -592,6 +669,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1);
xa_init_flags(&vdev->db_xa, XA_FLAGS_ALLOC1);
INIT_LIST_HEAD(&vdev->bo_list);
hash_init(vdev->user_limits);
vdev->db_limit.min = IVPU_MIN_DB;
vdev->db_limit.max = IVPU_MAX_DB;
@ -600,6 +678,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
if (ret)
goto err_xa_destroy;
ret = drmm_mutex_init(&vdev->drm, &vdev->user_limits_lock);
if (ret)
goto err_xa_destroy;
ret = drmm_mutex_init(&vdev->drm, &vdev->submitted_jobs_lock);
if (ret)
goto err_xa_destroy;
@ -717,7 +799,7 @@ static struct pci_device_id ivpu_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PTL_P) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_WCL) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_NVL) },
{ }
{}
};
MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);

View File

@ -12,6 +12,7 @@
#include <drm/drm_mm.h>
#include <drm/drm_print.h>
#include <linux/hashtable.h>
#include <linux/pci.h>
#include <linux/xarray.h>
#include <uapi/drm/ivpu_accel.h>
@ -43,7 +44,7 @@
/* SSID 1 is used by the VPU to represent reserved context */
#define IVPU_RESERVED_CONTEXT_MMU_SSID 1
#define IVPU_USER_CONTEXT_MIN_SSID 2
#define IVPU_USER_CONTEXT_MAX_SSID (IVPU_USER_CONTEXT_MIN_SSID + 63)
#define IVPU_USER_CONTEXT_MAX_SSID (IVPU_USER_CONTEXT_MIN_SSID + 128)
#define IVPU_MIN_DB 1
#define IVPU_MAX_DB 255
@ -51,9 +52,6 @@
#define IVPU_JOB_ID_JOB_MASK GENMASK(7, 0)
#define IVPU_JOB_ID_CONTEXT_MASK GENMASK(31, 8)
#define IVPU_NUM_PRIORITIES 4
#define IVPU_NUM_CMDQS_PER_CTX (IVPU_NUM_PRIORITIES)
#define IVPU_CMDQ_MIN_ID 1
#define IVPU_CMDQ_MAX_ID 255
@ -123,6 +121,16 @@ struct ivpu_fw_info;
struct ivpu_ipc_info;
struct ivpu_pm_info;
struct ivpu_user_limits {
struct hlist_node hash_node;
struct ivpu_device *vdev;
struct kref ref;
u32 max_ctx_count;
u32 max_db_count;
u32 uid;
atomic_t db_count;
};
struct ivpu_device {
struct drm_device drm;
void __iomem *regb;
@ -142,6 +150,8 @@ struct ivpu_device {
struct mutex context_list_lock; /* Protects user context addition/removal */
struct xarray context_xa;
struct xa_limit context_xa_limit;
DECLARE_HASHTABLE(user_limits, 8);
struct mutex user_limits_lock; /* Protects user_limits */
struct xarray db_xa;
struct xa_limit db_limit;
@ -189,6 +199,7 @@ struct ivpu_file_priv {
struct list_head ms_instance_list;
struct ivpu_bo *ms_info_bo;
struct xa_limit job_limit;
struct ivpu_user_limits *user_limits;
u32 job_id_next;
struct xa_limit cmdq_limit;
u32 cmdq_id_next;
@ -286,6 +297,13 @@ static inline u32 ivpu_get_context_count(struct ivpu_device *vdev)
return (ctx_limit.max - ctx_limit.min + 1);
}
static inline u32 ivpu_get_doorbell_count(struct ivpu_device *vdev)
{
struct xa_limit db_limit = vdev->db_limit;
return (db_limit.max - db_limit.min + 1);
}
static inline u32 ivpu_get_platform(struct ivpu_device *vdev)
{
WARN_ON_ONCE(vdev->platform == IVPU_PLATFORM_INVALID);

View File

@ -173,7 +173,7 @@ static struct ivpu_cmdq *ivpu_cmdq_create(struct ivpu_file_priv *file_priv, u8 p
ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &cmdq->id, cmdq, file_priv->cmdq_limit,
&file_priv->cmdq_id_next, GFP_KERNEL);
if (ret < 0) {
ivpu_err(vdev, "Failed to allocate command queue ID: %d\n", ret);
ivpu_dbg(vdev, IOCTL, "Failed to allocate command queue ID: %d\n", ret);
goto err_free_cmdq;
}
@ -215,14 +215,22 @@ static int ivpu_hws_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq
static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
{
struct ivpu_user_limits *limits = file_priv->user_limits;
struct ivpu_device *vdev = file_priv->vdev;
int ret;
if (atomic_inc_return(&limits->db_count) > limits->max_db_count) {
ivpu_dbg(vdev, IOCTL, "Maximum number of %u doorbells for uid %u reached\n",
limits->max_db_count, limits->uid);
ret = -EBUSY;
goto err_dec_db_count;
}
ret = xa_alloc_cyclic(&vdev->db_xa, &cmdq->db_id, NULL, vdev->db_limit, &vdev->db_next,
GFP_KERNEL);
if (ret < 0) {
ivpu_err(vdev, "Failed to allocate doorbell ID: %d\n", ret);
return ret;
ivpu_dbg(vdev, IOCTL, "Failed to allocate doorbell ID: %d\n", ret);
goto err_dec_db_count;
}
if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
@ -231,15 +239,18 @@ static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *
else
ret = ivpu_jsm_register_db(vdev, file_priv->ctx.id, cmdq->db_id,
cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem));
if (!ret) {
ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d priority %d\n",
cmdq->db_id, cmdq->id, file_priv->ctx.id, cmdq->priority);
} else {
if (ret) {
xa_erase(&vdev->db_xa, cmdq->db_id);
cmdq->db_id = 0;
goto err_dec_db_count;
}
ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d priority %d\n",
cmdq->db_id, cmdq->id, file_priv->ctx.id, cmdq->priority);
return 0;
err_dec_db_count:
atomic_dec(&limits->db_count);
return ret;
}
@ -298,6 +309,7 @@ static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct ivpu_cm
}
xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
atomic_dec(&file_priv->user_limits->db_count);
cmdq->db_id = 0;
return 0;
@ -313,6 +325,7 @@ static inline u8 ivpu_job_to_jsm_priority(u8 priority)
static void ivpu_cmdq_destroy(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
{
lockdep_assert_held(&file_priv->lock);
ivpu_cmdq_unregister(file_priv, cmdq);
xa_erase(&file_priv->cmdq_xa, cmdq->id);
ivpu_cmdq_free(file_priv, cmdq);
@ -380,8 +393,11 @@ static void ivpu_cmdq_reset(struct ivpu_file_priv *file_priv)
mutex_lock(&file_priv->lock);
xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) {
xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
cmdq->db_id = 0;
if (cmdq->db_id) {
xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
atomic_dec(&file_priv->user_limits->db_count);
cmdq->db_id = 0;
}
}
mutex_unlock(&file_priv->lock);

View File

@ -1,12 +1,22 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright (c) 2020-2024, Intel Corporation.
* Copyright (c) 2020-2025, Intel Corporation.
*/
/**
* @addtogroup Boot
* @{
*/
/**
* @file
* @brief Boot API public header file.
*/
#ifndef VPU_BOOT_API_H
#define VPU_BOOT_API_H
/*
/**
* The below values will be used to construct the version info this way:
* fw_bin_header->api_version[VPU_BOOT_API_VER_ID] = (VPU_BOOT_API_VER_MAJOR << 16) |
* VPU_BOOT_API_VER_MINOR;
@ -16,24 +26,24 @@
* partial info a build error will be generated.
*/
/*
/**
* Major version changes that break backward compatibility.
* Major version must start from 1 and can only be incremented.
*/
#define VPU_BOOT_API_VER_MAJOR 3
/*
/**
* Minor version changes when API backward compatibility is preserved.
* Resets to 0 if Major version is incremented.
*/
#define VPU_BOOT_API_VER_MINOR 28
#define VPU_BOOT_API_VER_MINOR 29
/*
/**
* API header changed (field names, documentation, formatting) but API itself has not been changed
*/
#define VPU_BOOT_API_VER_PATCH 3
#define VPU_BOOT_API_VER_PATCH 4
/*
/**
* Index in the API version table
* Must be unique for each API
*/
@ -41,7 +51,7 @@
#pragma pack(push, 4)
/*
/**
* Firmware image header format
*/
#define VPU_FW_HEADER_SIZE 4096
@ -61,44 +71,41 @@ struct vpu_firmware_header {
u32 firmware_version_size;
u64 boot_params_load_address;
u32 api_version[VPU_FW_API_VER_NUM];
/* Size of memory require for firmware execution */
/** Size of memory require for firmware execution */
u32 runtime_size;
u32 shave_nn_fw_size;
/*
/**
* Size of primary preemption buffer, assuming a 2-job submission queue.
* NOTE: host driver is expected to adapt size accordingly to actual
* submission queue size and device capabilities.
*/
u32 preemption_buffer_1_size;
/*
/**
* Size of secondary preemption buffer, assuming a 2-job submission queue.
* NOTE: host driver is expected to adapt size accordingly to actual
* submission queue size and device capabilities.
*/
u32 preemption_buffer_2_size;
/*
/**
* Maximum preemption buffer size that the FW can use: no need for the host
* driver to allocate more space than that specified by these fields.
* A value of 0 means no declared limit.
*/
u32 preemption_buffer_1_max_size;
u32 preemption_buffer_2_max_size;
/* Space reserved for future preemption-related fields. */
/** Space reserved for future preemption-related fields. */
u32 preemption_reserved[4];
/* FW image read only section start address, 4KB aligned */
/** FW image read only section start address, 4KB aligned */
u64 ro_section_start_address;
/* FW image read only section size, 4KB aligned */
/** FW image read only section size, 4KB aligned */
u32 ro_section_size;
u32 reserved;
};
/*
/**
* Firmware boot parameters format
*/
#define VPU_BOOT_PLL_COUNT 3
#define VPU_BOOT_PLL_OUT_COUNT 4
/** Values for boot_type field */
#define VPU_BOOT_TYPE_COLDBOOT 0
#define VPU_BOOT_TYPE_WARMBOOT 1
@ -166,7 +173,7 @@ enum vpu_trace_destination {
#define VPU_TRACE_PROC_BIT_ACT_SHV_3 22
#define VPU_TRACE_PROC_NO_OF_HW_DEVS 23
/* VPU 30xx HW component IDs are sequential, so define first and last IDs. */
/** VPU 30xx HW component IDs are sequential, so define first and last IDs. */
#define VPU_TRACE_PROC_BIT_30XX_FIRST VPU_TRACE_PROC_BIT_LRT
#define VPU_TRACE_PROC_BIT_30XX_LAST VPU_TRACE_PROC_BIT_SHV_15
@ -175,15 +182,7 @@ struct vpu_boot_l2_cache_config {
u8 cfg;
};
struct vpu_warm_boot_section {
u32 src;
u32 dst;
u32 size;
u32 core_id;
u32 is_clear_op;
};
/*
/**
* When HW scheduling mode is enabled, a present period is defined.
* It will be used by VPU to swap between normal and focus priorities
* to prevent starving of normal priority band (when implemented).
@ -206,24 +205,24 @@ struct vpu_warm_boot_section {
* Enum for dvfs_mode boot param.
*/
enum vpu_governor {
VPU_GOV_DEFAULT = 0, /* Default Governor for the system */
VPU_GOV_MAX_PERFORMANCE = 1, /* Maximum performance governor */
VPU_GOV_ON_DEMAND = 2, /* On Demand frequency control governor */
VPU_GOV_POWER_SAVE = 3, /* Power save governor */
VPU_GOV_ON_DEMAND_PRIORITY_AWARE = 4 /* On Demand priority based governor */
VPU_GOV_DEFAULT = 0, /** Default Governor for the system */
VPU_GOV_MAX_PERFORMANCE = 1, /** Maximum performance governor */
VPU_GOV_ON_DEMAND = 2, /** On Demand frequency control governor */
VPU_GOV_POWER_SAVE = 3, /** Power save governor */
VPU_GOV_ON_DEMAND_PRIORITY_AWARE = 4 /** On Demand priority based governor */
};
struct vpu_boot_params {
u32 magic;
u32 vpu_id;
u32 vpu_count;
u32 pad0[5];
/* Clock frequencies: 0x20 - 0xFF */
u32 reserved_0[5];
/** Clock frequencies: 0x20 - 0xFF */
u32 frequency;
u32 pll[VPU_BOOT_PLL_COUNT][VPU_BOOT_PLL_OUT_COUNT];
u32 reserved_1[12];
u32 perf_clk_frequency;
u32 pad1[42];
/* Memory regions: 0x100 - 0x1FF */
u32 reserved_2[42];
/** Memory regions: 0x100 - 0x1FF */
u64 ipc_header_area_start;
u32 ipc_header_area_size;
u64 shared_region_base;
@ -234,41 +233,24 @@ struct vpu_boot_params {
u32 global_aliased_pio_size;
u32 autoconfig;
struct vpu_boot_l2_cache_config cache_defaults[VPU_BOOT_L2_CACHE_CFG_NUM];
u64 global_memory_allocator_base;
u32 global_memory_allocator_size;
u32 reserved_3[3];
/**
* ShaveNN FW section VPU base address
* On VPU2.7 HW this address must be within 2GB range starting from L2C_PAGE_TABLE base
*/
u64 shave_nn_fw_base;
u64 save_restore_ret_address; /* stores the address of FW's restore entry point */
u32 pad2[43];
/* IRQ re-direct numbers: 0x200 - 0x2FF */
u64 save_restore_ret_address; /** stores the address of FW's restore entry point */
u32 reserved_4[43];
/** IRQ re-direct numbers: 0x200 - 0x2FF */
s32 watchdog_irq_mss;
s32 watchdog_irq_nce;
/* ARM -> VPU doorbell interrupt. ARM is notifying VPU of async command or compute job. */
/** ARM -> VPU doorbell interrupt. ARM is notifying VPU of async command or compute job. */
u32 host_to_vpu_irq;
/* VPU -> ARM job done interrupt. VPU is notifying ARM of compute job completion. */
/** VPU -> ARM job done interrupt. VPU is notifying ARM of compute job completion. */
u32 job_done_irq;
/* VPU -> ARM IRQ line to use to request MMU update. */
u32 mmu_update_request_irq;
/* ARM -> VPU IRQ line to use to notify of MMU update completion. */
u32 mmu_update_done_irq;
/* ARM -> VPU IRQ line to use to request power level change. */
u32 set_power_level_irq;
/* VPU -> ARM IRQ line to use to notify of power level change completion. */
u32 set_power_level_done_irq;
/* VPU -> ARM IRQ line to use to notify of VPU idle state change */
u32 set_vpu_idle_update_irq;
/* VPU -> ARM IRQ line to use to request counter reset. */
u32 metric_query_event_irq;
/* ARM -> VPU IRQ line to use to notify of counter reset completion. */
u32 metric_query_event_done_irq;
/* VPU -> ARM IRQ line to use to notify of preemption completion. */
u32 preemption_done_irq;
/* Padding. */
u32 pad3[52];
/* Silicon information: 0x300 - 0x3FF */
/** Padding. */
u32 reserved_5[60];
/** Silicon information: 0x300 - 0x3FF */
u32 host_version_id;
u32 si_stepping;
u64 device_id;
@ -294,7 +276,7 @@ struct vpu_boot_params {
u32 crit_tracing_buff_size;
u64 verbose_tracing_buff_addr;
u32 verbose_tracing_buff_size;
u64 verbose_tracing_sw_component_mask; /* TO BE REMOVED */
u64 verbose_tracing_sw_component_mask; /** TO BE REMOVED */
/**
* Mask of destinations to which logging messages are delivered; bitwise OR
* of values defined in vpu_trace_destination enum.
@ -308,11 +290,7 @@ struct vpu_boot_params {
/** Mask of trace message formats supported by the driver */
u64 tracing_buff_message_format_mask;
u64 trace_reserved_1[2];
/**
* Period at which the VPU reads the temp sensor values into MMIO, on
* platforms where that is necessary (in ms). 0 to disable reads.
*/
u32 temp_sensor_period_ms;
u32 reserved_6;
/** PLL ratio for efficient clock frequency */
u32 pn_freq_pll_ratio;
/**
@ -347,11 +325,11 @@ struct vpu_boot_params {
* 1: IPC message required to save state on D0i3 entry flow.
*/
u32 d0i3_delayed_entry;
/* Time spent by VPU in D0i3 state */
/** Time spent by VPU in D0i3 state */
u64 d0i3_residency_time_us;
/* Value of VPU perf counter at the time of entering D0i3 state . */
/** Value of VPU perf counter at the time of entering D0i3 state . */
u64 d0i3_entry_vpu_ts;
/*
/**
* The system time of the host operating system in microseconds.
* E.g the number of microseconds since 1st of January 1970, or whatever
* date the host operating system uses to maintain system time.
@ -359,57 +337,52 @@ struct vpu_boot_params {
* The KMD is required to update this value on every VPU reset.
*/
u64 system_time_us;
u32 pad4[2];
/*
u32 reserved_7[2];
/**
* The delta between device monotonic time and the current value of the
* HW timestamp register, in ticks. Written by the firmware during boot.
* Can be used by the KMD to calculate device time.
*/
u64 device_time_delta_ticks;
u32 pad7[14];
/* Warm boot information: 0x400 - 0x43F */
u32 warm_boot_sections_count;
u32 warm_boot_start_address_reference;
u32 warm_boot_section_info_address_offset;
u32 pad5[13];
/* Power States transitions timestamps: 0x440 - 0x46F*/
struct {
/* VPU_IDLE -> VPU_ACTIVE transition initiated timestamp */
u32 reserved_8[30];
/** Power States transitions timestamps: 0x440 - 0x46F*/
struct power_states_timestamps {
/** VPU_IDLE -> VPU_ACTIVE transition initiated timestamp */
u64 vpu_active_state_requested;
/* VPU_IDLE -> VPU_ACTIVE transition completed timestamp */
/** VPU_IDLE -> VPU_ACTIVE transition completed timestamp */
u64 vpu_active_state_achieved;
/* VPU_ACTIVE -> VPU_IDLE transition initiated timestamp */
/** VPU_ACTIVE -> VPU_IDLE transition initiated timestamp */
u64 vpu_idle_state_requested;
/* VPU_ACTIVE -> VPU_IDLE transition completed timestamp */
/** VPU_ACTIVE -> VPU_IDLE transition completed timestamp */
u64 vpu_idle_state_achieved;
/* VPU_IDLE -> VPU_STANDBY transition initiated timestamp */
/** VPU_IDLE -> VPU_STANDBY transition initiated timestamp */
u64 vpu_standby_state_requested;
/* VPU_IDLE -> VPU_STANDBY transition completed timestamp */
/** VPU_IDLE -> VPU_STANDBY transition completed timestamp */
u64 vpu_standby_state_achieved;
} power_states_timestamps;
/* VPU scheduling mode. Values defined by VPU_SCHEDULING_MODE_* macros. */
/** VPU scheduling mode. Values defined by VPU_SCHEDULING_MODE_* macros. */
u32 vpu_scheduling_mode;
/* Present call period in milliseconds. */
/** Present call period in milliseconds. */
u32 vpu_focus_present_timer_ms;
/* VPU ECC Signaling */
/** VPU ECC Signaling */
u32 vpu_uses_ecc_mca_signal;
/* Values defined by POWER_PROFILE* macros */
/** Values defined by POWER_PROFILE* macros */
u32 power_profile;
/* Microsecond value for DCT active cycle */
/** Microsecond value for DCT active cycle */
u32 dct_active_us;
/* Microsecond value for DCT inactive cycle */
/** Microsecond value for DCT inactive cycle */
u32 dct_inactive_us;
/* Unused/reserved: 0x488 - 0xFFF */
u32 pad6[734];
/** Unused/reserved: 0x488 - 0xFFF */
u32 reserved_9[734];
};
/* Magic numbers set between host and vpu to detect corruption of tracing init */
/** Magic numbers set between host and vpu to detect corruption of tracing init */
#define VPU_TRACING_BUFFER_CANARY (0xCAFECAFE)
/* Tracing buffer message format definitions */
/** Tracing buffer message format definitions */
#define VPU_TRACING_FORMAT_STRING 0
#define VPU_TRACING_FORMAT_MIPI 2
/*
/**
* Header of the tracing buffer.
* The below defined header will be stored at the beginning of
* each allocated tracing buffer, followed by a series of 256b
@ -421,53 +394,55 @@ struct vpu_tracing_buffer_header {
* @see VPU_TRACING_BUFFER_CANARY
*/
u32 host_canary_start;
/* offset from start of buffer for trace entries */
/** offset from start of buffer for trace entries */
u32 read_index;
/* keeps track of wrapping on the reader side */
/** keeps track of wrapping on the reader side */
u32 read_wrap_count;
u32 pad_to_cache_line_size_0[13];
/* End of first cache line */
/** End of first cache line */
/**
* Magic number set by host to detect corruption
* @see VPU_TRACING_BUFFER_CANARY
*/
u32 vpu_canary_start;
/* offset from start of buffer from write start */
/** offset from start of buffer from write start */
u32 write_index;
/* counter for buffer wrapping */
/** counter for buffer wrapping */
u32 wrap_count;
/* legacy field - do not use */
/** legacy field - do not use */
u32 reserved_0;
/**
* Size of the log buffer include this header (@header_size) and space
* reserved for all messages. If @alignment` is greater that 0 the @Size
* must be multiple of @Alignment.
* Size of the log buffer including this header (`header_size`) and space
* reserved for all messages. If `alignment` is greater than 0, the `size`
* must be a multiple of `alignment`.
*/
u32 size;
/* Header version */
/** Header version */
u16 header_version;
/* Header size */
/** Header size */
u16 header_size;
/*
/**
* Format of the messages in the trace buffer
* 0 - null terminated string
* 1 - size + null terminated string
* 2 - MIPI-SysT encoding
*/
u32 format;
/*
/**
* Message alignment
* 0 - messages are place 1 after another
* n - every message starts and multiple on offset
*/
u32 alignment; /* 64, 128, 256 */
/* Name of the logging entity, i.e "LRT", "LNN", "SHV0", etc */
u32 alignment; /** 64, 128, 256 */
/** Name of the logging entity, i.e "LRT", "LNN", "SHV0", etc */
char name[16];
u32 pad_to_cache_line_size_1[4];
/* End of second cache line */
/** End of second cache line */
};
#pragma pack(pop)
#endif
///@}

View File

@ -790,8 +790,11 @@ static int __init dma_resv_lockdep(void)
mmap_read_lock(mm);
ww_acquire_init(&ctx, &reservation_ww_class);
ret = dma_resv_lock(&obj, &ctx);
if (ret == -EDEADLK)
if (ret) {
/* Only EDEADLK from the error injection is possible here */
WARN_ON(ret != -EDEADLK);
dma_resv_lock_slow(&obj, &ctx);
}
fs_reclaim_acquire(GFP_KERNEL);
/* for unmap_mapping_range on trylocked buffer objects in shrinkers */
i_mmap_lock_write(&mapping);

View File

@ -3,8 +3,7 @@
* Copyright © 2021 Intel Corporation
*/
#include <kunit/test-bug.h>
#include <linux/bug.h>
#include <linux/export.h>
#include <linux/kmemleak.h>
#include <linux/module.h>
@ -12,6 +11,28 @@
#include <linux/gpu_buddy.h>
/**
* gpu_buddy_assert - assert a condition in the buddy allocator
* @condition: condition expected to be true
*
* When CONFIG_KUNIT is enabled, evaluates @condition and, if false, triggers
* a WARN_ON() and also calls kunit_fail_current_test() so that any running
* kunit test is properly marked as failed. The stringified condition is
* included in the failure message for easy identification.
*
* When CONFIG_KUNIT is not enabled, this reduces to WARN_ON() so production
* builds retain the same warning semantics as before.
*/
#if IS_ENABLED(CONFIG_KUNIT)
#include <kunit/test-bug.h>
#define gpu_buddy_assert(condition) do { \
if (WARN_ON(!(condition))) \
kunit_fail_current_test("gpu_buddy_assert(" #condition ")"); \
} while (0)
#else
#define gpu_buddy_assert(condition) WARN_ON(!(condition))
#endif
static struct kmem_cache *slab_blocks;
static unsigned int
@ -268,8 +289,8 @@ static int __force_merge(struct gpu_buddy *mm,
if (!gpu_buddy_block_is_free(buddy))
continue;
WARN_ON(gpu_buddy_block_is_clear(block) ==
gpu_buddy_block_is_clear(buddy));
gpu_buddy_assert(gpu_buddy_block_is_clear(block) !=
gpu_buddy_block_is_clear(buddy));
/*
* Advance to the next node when the current node is the buddy,
@ -415,8 +436,7 @@ void gpu_buddy_fini(struct gpu_buddy *mm)
start = gpu_buddy_block_offset(mm->roots[i]);
__force_merge(mm, start, start + size, order);
if (WARN_ON(!gpu_buddy_block_is_free(mm->roots[i])))
kunit_fail_current_test("buddy_fini() root");
gpu_buddy_assert(gpu_buddy_block_is_free(mm->roots[i]));
gpu_block_free(mm, mm->roots[i]);
@ -424,7 +444,7 @@ void gpu_buddy_fini(struct gpu_buddy *mm)
size -= root_size;
}
WARN_ON(mm->avail != mm->size);
gpu_buddy_assert(mm->avail == mm->size);
for_each_free_tree(i)
kfree(mm->free_trees[i]);
@ -541,7 +561,7 @@ static void __gpu_buddy_free_list(struct gpu_buddy *mm,
{
struct gpu_buddy_block *block, *on;
WARN_ON(mark_dirty && mark_clear);
gpu_buddy_assert(!(mark_dirty && mark_clear));
list_for_each_entry_safe(block, on, objects, link) {
if (mark_clear)

View File

@ -66,7 +66,12 @@ static int ws_bridge_attach_dsi(struct ws_bridge *ws)
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->lanes = 2;
dsi->lanes = drm_of_get_data_lanes_count_ep(dev->of_node, 0, 0, 1, 4);
if (dsi->lanes < 0) {
dev_warn(dev, "Invalid or missing DSI lane count %d, falling back to 2 lanes\n",
dsi->lanes);
dsi->lanes = 2; /* Old DT backward compatibility */
}
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret < 0)
@ -80,11 +85,6 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct ws_bridge *ws = bridge_to_ws_bridge(bridge);
int ret;
ret = ws_bridge_attach_dsi(ws);
if (ret)
return ret;
return drm_bridge_attach(encoder, ws->next_bridge,
&ws->bridge, flags);
@ -179,7 +179,7 @@ static int ws_bridge_probe(struct i2c_client *i2c)
ws->bridge.of_node = dev->of_node;
devm_drm_bridge_add(dev, &ws->bridge);
return 0;
return ws_bridge_attach_dsi(ws);
}
static const struct of_device_id ws_bridge_of_ids[] = {

View File

@ -204,7 +204,7 @@ void drm_client_buffer_delete(struct drm_client_buffer *buffer)
}
EXPORT_SYMBOL(drm_client_buffer_delete);
static struct drm_client_buffer *
struct drm_client_buffer *
drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
u32 format, u32 handle, u32 pitch)
{
@ -265,6 +265,7 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
kfree(buffer);
return ERR_PTR(ret);
}
EXPORT_SYMBOL(drm_client_buffer_create);
/**
* drm_client_buffer_vmap_local - Map DRM client buffer into address space

View File

@ -72,17 +72,10 @@ static int psb_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
static void psb_fbdev_fb_destroy(struct fb_info *info)
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
struct drm_gem_object *obj = fb->obj[0];
drm_fb_helper_fini(fb_helper);
drm_framebuffer_unregister_private(fb);
drm_framebuffer_cleanup(fb);
kfree(fb);
drm_gem_object_put(obj);
drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
}
@ -105,78 +98,76 @@ static const struct drm_fb_helper_funcs psb_fbdev_fb_helper_funcs = {
int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_surface_size *sizes)
{
struct drm_device *dev = fb_helper->dev;
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = client->dev;
struct drm_file *file = client->file;
struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
struct fb_info *info = fb_helper->info;
struct drm_framebuffer *fb;
struct drm_mode_fb_cmd2 mode_cmd = { };
int size;
int ret;
u32 fourcc, pitch;
u64 size;
const struct drm_format_info *format;
struct drm_client_buffer *buffer;
struct psb_gem_object *backing;
struct drm_gem_object *obj;
u32 bpp, depth;
u32 handle;
int ret;
/* No 24-bit packed mode */
if (sizes->surface_bpp == 24) {
sizes->surface_bpp = 32;
sizes->surface_depth = 24;
}
bpp = sizes->surface_bpp;
depth = sizes->surface_depth;
/*
* If the mode does not fit in 32 bit then switch to 16 bit to get
* a console on full resolution. The X mode setting server will
* allocate its own 32-bit GEM framebuffer.
*/
size = ALIGN(sizes->surface_width * DIV_ROUND_UP(bpp, 8), 64) *
sizes->surface_height;
size = ALIGN(size, PAGE_SIZE);
if (size > dev_priv->vram_stolen_size) {
sizes->surface_bpp = 16;
sizes->surface_depth = 16;
}
bpp = sizes->surface_bpp;
depth = sizes->surface_depth;
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
mode_cmd.pitches[0] = ALIGN(mode_cmd.width * DIV_ROUND_UP(bpp, 8), 64);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
size = mode_cmd.pitches[0] * mode_cmd.height;
size = ALIGN(size, PAGE_SIZE);
try_psb_gem_create:
fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
format = drm_get_format_info(dev, fourcc, DRM_FORMAT_MOD_LINEAR);
pitch = ALIGN(drm_format_info_min_pitch(format, 0, sizes->surface_width), SZ_64);
size = ALIGN(pitch * sizes->surface_height, PAGE_SIZE);
/* Allocate the framebuffer in the GTT with stolen page backing */
backing = psb_gem_create(dev, size, "fb", true, PAGE_SIZE);
if (IS_ERR(backing))
return PTR_ERR(backing);
if (IS_ERR(backing)) {
ret = PTR_ERR(backing);
if (ret == -EBUSY && sizes->surface_bpp > 16) {
/*
* If the mode does not fit in 32 bit then switch to 16 bit to
* get a console on full resolution. User-space compositors will
* allocate their own 32-bit framebuffers.
*/
sizes->surface_bpp = 16;
sizes->surface_depth = 16;
goto try_psb_gem_create;
}
return ret;
}
obj = &backing->base;
fb = psb_framebuffer_create(dev,
drm_get_format_info(dev, mode_cmd.pixel_format,
mode_cmd.modifier[0]),
&mode_cmd, obj);
if (IS_ERR(fb)) {
ret = PTR_ERR(fb);
ret = drm_gem_handle_create(file, obj, &handle);
if (ret)
goto err_drm_gem_object_put;
buffer = drm_client_buffer_create(client, sizes->surface_width, sizes->surface_height,
fourcc, handle, pitch);
if (IS_ERR(buffer)) {
ret = PTR_ERR(buffer);
goto err_drm_gem_handle_delete;
}
fb_helper->funcs = &psb_fbdev_fb_helper_funcs;
fb_helper->fb = fb;
fb_helper->buffer = buffer;
fb_helper->fb = buffer->fb;
info->fbops = &psb_fbdev_fb_ops;
/* Accessed stolen memory directly */
info->screen_base = dev_priv->vram_addr + backing->offset;
info->screen_size = size;
info->screen_size = obj->size;
drm_fb_helper_fill_info(info, fb_helper, sizes);
info->fix.smem_start = dev_priv->stolen_base + backing->offset;
info->fix.smem_len = size;
info->fix.smem_len = obj->size;
info->fix.ywrapstep = 0;
info->fix.ypanstep = 0;
info->fix.mmio_start = pci_resource_start(pdev, 0);
@ -186,10 +177,18 @@ int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height);
dev_dbg(dev->dev, "allocated %dx%d fb\n", buffer->fb->width, buffer->fb->height);
/* The handle is only needed for creating the framebuffer.*/
drm_gem_handle_delete(file, handle);
/* The framebuffer still holds a references on the GEM object. */
drm_gem_object_put(obj);
return 0;
err_drm_gem_handle_delete:
drm_gem_handle_delete(file, handle);
err_drm_gem_object_put:
drm_gem_object_put(obj);
return ret;

View File

@ -12,111 +12,25 @@
#include "framebuffer.h"
#include "psb_drv.h"
static const struct drm_framebuffer_funcs psb_fb_funcs = {
.destroy = drm_gem_fb_destroy,
.create_handle = drm_gem_fb_create_handle,
};
/**
* psb_framebuffer_init - initialize a framebuffer
* @dev: our DRM device
* @fb: framebuffer to set up
* @mode_cmd: mode description
* @obj: backing object
*
* Configure and fill in the boilerplate for our frame buffer. Return
* 0 on success or an error code if we fail.
*/
static int psb_framebuffer_init(struct drm_device *dev,
struct drm_framebuffer *fb,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
static struct drm_framebuffer *
psb_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *cmd)
{
int ret;
/*
* Reject unknown formats, YUV formats, and formats with more than
* 4 bytes per pixel.
*/
if (!info->depth || info->cpp[0] > 4)
return -EINVAL;
if (mode_cmd->pitches[0] & 63)
return -EINVAL;
drm_helper_mode_fill_fb_struct(dev, fb, info, mode_cmd);
fb->obj[0] = obj;
ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs);
if (ret) {
dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
return ret;
}
return 0;
}
/**
* psb_framebuffer_create - create a framebuffer backed by gt
* @dev: our DRM device
* @info: pixel format information
* @mode_cmd: the description of the requested mode
* @obj: the backing object
*
* Create a framebuffer object backed by the gt, and fill in the
* boilerplate required
*
* TODO: review object references
*/
struct drm_framebuffer *psb_framebuffer_create(struct drm_device *dev,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
struct drm_framebuffer *fb;
int ret;
fb = kzalloc_obj(*fb);
if (!fb)
return ERR_PTR(-ENOMEM);
ret = psb_framebuffer_init(dev, fb, info, mode_cmd, obj);
if (ret) {
kfree(fb);
return ERR_PTR(ret);
}
return fb;
}
/**
* psb_user_framebuffer_create - create framebuffer
* @dev: our DRM device
* @filp: client file
* @cmd: mode request
*
* Create a new framebuffer backed by a userspace GEM object
*/
static struct drm_framebuffer *psb_user_framebuffer_create
(struct drm_device *dev, struct drm_file *filp,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *cmd)
{
struct drm_gem_object *obj;
struct drm_framebuffer *fb;
return ERR_PTR(-EINVAL);
/*
* Find the GEM object and thus the gtt range object that is
* to back this space
* Pitch must be aligned to 64 bytes.
*/
obj = drm_gem_object_lookup(filp, cmd->handles[0]);
if (obj == NULL)
return ERR_PTR(-ENOENT);
if (cmd->pitches[0] & 63)
return ERR_PTR(-EINVAL);
/* Let the core code do all the work */
fb = psb_framebuffer_create(dev, info, cmd, obj);
if (IS_ERR(fb))
drm_gem_object_put(obj);
return fb;
return drm_gem_fb_create(dev, filp, info, cmd);
}
static const struct drm_mode_config_funcs psb_mode_funcs = {

View File

@ -592,12 +592,6 @@ struct psb_ops {
extern void psb_modeset_init(struct drm_device *dev);
extern void psb_modeset_cleanup(struct drm_device *dev);
/* framebuffer */
struct drm_framebuffer *psb_framebuffer_create(struct drm_device *dev,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
/* fbdev */
#if defined(CONFIG_DRM_FBDEV_EMULATION)
int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,

View File

@ -447,7 +447,7 @@ static void gud_fb_handle_damage(struct gud_device *gdrm, struct drm_framebuffer
}
/* Imported buffers are assumed to be WriteCombined with uncached reads */
gud_flush_damage(gdrm, fb, src, !fb->obj[0]->import_attach, damage);
gud_flush_damage(gdrm, fb, src, !drm_gem_is_imported(fb->obj[0]), damage);
}
int gud_plane_atomic_check(struct drm_plane *plane,

View File

@ -598,8 +598,8 @@ int pvr_power_domains_init(struct pvr_device *pvr_dev)
struct drm_device *drm_dev = from_pvr_device(pvr_dev);
struct device *dev = drm_dev->dev;
struct device_link **domain_links __free(kfree) = NULL;
struct dev_pm_domain_list *domains = NULL;
struct device_link **domain_links = NULL;
int domain_count;
int link_count;
@ -608,23 +608,30 @@ int pvr_power_domains_init(struct pvr_device *pvr_dev)
domain_count = of_count_phandle_with_args(dev->of_node, "power-domains",
"#power-domain-cells");
if (domain_count < 0)
return domain_count;
if (domain_count < 0) {
err = domain_count;
goto out;
}
if (domain_count <= 1)
return 0;
if (domain_count <= 1) {
err = 0;
goto out;
}
if (domain_count > ARRAY_SIZE(ROGUE_PD_NAMES)) {
drm_err(drm_dev, "%s() only supports %zu domains on Rogue",
__func__, ARRAY_SIZE(ROGUE_PD_NAMES));
return -EOPNOTSUPP;
err = -EOPNOTSUPP;
goto out;
}
link_count = domain_count - 1;
domain_links = kzalloc_objs(*domain_links, link_count);
if (!domain_links)
return -ENOMEM;
if (!domain_links) {
err = -ENOMEM;
goto out;
}
const struct dev_pm_domain_attach_data pd_attach_data = {
.pd_names = ROGUE_PD_NAMES,
@ -634,7 +641,7 @@ int pvr_power_domains_init(struct pvr_device *pvr_dev)
err = dev_pm_domain_attach_list(dev, &pd_attach_data, &domains);
if (err < 0)
return err;
goto err_free_links;
for (i = 0; i < link_count; i++) {
struct device_link *link;
@ -650,17 +657,26 @@ int pvr_power_domains_init(struct pvr_device *pvr_dev)
domain_links[i] = link;
}
pvr_dev->power = (struct pvr_device_power){
.domains = domains,
.domain_links = no_free_ptr(domain_links),
};
return 0;
err = 0;
goto out;
err_unlink:
while (--i >= 0)
device_link_del(domain_links[i]);
dev_pm_domain_detach_list(domains);
domains = NULL;
err_free_links:
kfree(domain_links);
domain_links = NULL;
out:
pvr_dev->power = (struct pvr_device_power){
.domains = domains,
.domain_links = domain_links,
};
return err;
}
@ -668,14 +684,16 @@ void pvr_power_domains_fini(struct pvr_device *pvr_dev)
{
struct pvr_device_power *pvr_power = &pvr_dev->power;
int i = (int)pvr_power->domains->num_pds - 1;
if (!pvr_power->domains)
goto out;
while (--i >= 0)
for (int i = (int)pvr_power->domains->num_pds - 2; i >= 0; --i)
device_link_del(pvr_power->domain_links[i]);
dev_pm_domain_detach_list(pvr_power->domains);
kfree(pvr_power->domain_links);
out:
*pvr_power = (struct pvr_device_power){ 0 };
}

View File

@ -144,7 +144,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
nouveau_bo_del_io_reserve_lru(bo);
nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
if (bo->base.import_attach)
if (drm_gem_is_imported(&bo->base))
drm_prime_gem_destroy(&bo->base, bo->sg);
/*

View File

@ -1814,6 +1814,13 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
};
static const struct panel_delay delay_200_500_e200_d100 = {
.hpd_absent = 200,
.unprepare = 500,
.enable = 200,
.disable = 100,
};
static const struct panel_delay delay_200_500_e200_d200 = {
.hpd_absent = 200,
.unprepare = 500,
@ -2014,7 +2021,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c93, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf2, &delay_200_500_e200, "NV156FHM-N4S"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf6, &delay_200_500_e200, "NV140WUM-N64"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf6, &delay_200_500_e200_d100, "NV140WUM-N64"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d45, &delay_200_500_e80, "NV116WHM-N4B"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d73, &delay_200_500_e80, "NE140WUM-N6S"),

View File

@ -702,7 +702,7 @@ static void panfrost_gem_debugfs_bo_print(struct panfrost_gem_object *bo,
resident_size,
drm_vma_node_start(&bo->base.base.vma_node));
if (bo->base.base.import_attach)
if (drm_gem_is_imported(&bo->base.base))
gem_state_flags |= PANFROST_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
if (bo->base.base.dma_buf)
gem_state_flags |= PANFROST_DEBUGFS_GEM_STATE_FLAG_EXPORTED;

View File

@ -666,7 +666,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
resident_size,
drm_vma_node_start(&bo->base.base.vma_node));
if (bo->base.base.import_attach)
if (drm_gem_is_imported(&bo->base.base))
gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
if (bo->base.base.dma_buf)
gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED;

View File

@ -1418,48 +1418,12 @@ static void drm_sched_cancel_remaining_jobs(struct drm_gpu_scheduler *sched)
*/
void drm_sched_fini(struct drm_gpu_scheduler *sched)
{
struct drm_sched_entity *s_entity;
int i;
drm_sched_wqueue_stop(sched);
for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) {
struct drm_sched_rq *rq = sched->sched_rq[i];
spin_lock(&rq->lock);
list_for_each_entry(s_entity, &rq->entities, list) {
/*
* Prevents reinsertion and marks job_queue as idle,
* it will be removed from the rq in drm_sched_entity_fini()
* eventually
*
* FIXME:
* This lacks the proper spin_lock(&s_entity->lock) and
* is, therefore, a race condition. Most notably, it
* can race with drm_sched_entity_push_job(). The lock
* cannot be taken here, however, because this would
* lead to lock inversion -> deadlock.
*
* The best solution probably is to enforce the life
* time rule of all entities having to be torn down
* before their scheduler. Then, however, locking could
* be dropped alltogether from this function.
*
* For now, this remains a potential race in all
* drivers that keep entities alive for longer than
* the scheduler.
*
* The READ_ONCE() is there to make the lockless read
* (warning about the lockless write below) slightly
* less broken...
*/
if (!READ_ONCE(s_entity->stopped))
dev_warn(sched->dev, "Tearing down scheduler with active entities!\n");
s_entity->stopped = true;
}
spin_unlock(&rq->lock);
for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++)
kfree(sched->sched_rq[i]);
}
/* Wakeup everyone stuck in drm_sched_entity_flush for this scheduler */
wake_up_all(&sched->job_scheduled);

View File

@ -421,7 +421,7 @@ static void drm_sched_change_priority(struct kunit *test)
static struct kunit_case drm_sched_priority_tests[] = {
KUNIT_CASE(drm_sched_priorities),
KUNIT_CASE(drm_sched_change_priority),
KUNIT_CASE_SLOW(drm_sched_change_priority),
{}
};
@ -546,7 +546,7 @@ static void drm_sched_test_credits(struct kunit *test)
}
static struct kunit_case drm_sched_credits_tests[] = {
KUNIT_CASE(drm_sched_test_credits),
KUNIT_CASE_SLOW(drm_sched_test_credits),
{}
};

View File

@ -556,7 +556,7 @@ static void vc4_free_object(struct drm_gem_object *gem_bo)
mutex_lock(&vc4->bo_lock);
/* If the object references someone else's memory, we can't cache it.
*/
if (gem_bo->import_attach) {
if (drm_gem_is_imported(gem_bo)) {
vc4_bo_destroy(bo);
goto out;
}

View File

@ -1250,7 +1250,7 @@ int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data,
/* Not sure it's safe to purge imported BOs. Let's just assume it's
* not until proven otherwise.
*/
if (gem_obj->import_attach) {
if (drm_gem_is_imported(gem_obj)) {
DRM_DEBUG("madvise not supported on imported BOs\n");
ret = -EINVAL;
goto out_put_gem;

View File

@ -910,7 +910,7 @@ static struct kunit_case gpu_buddy_tests[] = {
KUNIT_CASE(gpu_test_buddy_alloc_contiguous),
KUNIT_CASE(gpu_test_buddy_alloc_clear),
KUNIT_CASE(gpu_test_buddy_alloc_range_bias),
KUNIT_CASE(gpu_test_buddy_fragmentation_performance),
KUNIT_CASE_SLOW(gpu_test_buddy_fragmentation_performance),
KUNIT_CASE(gpu_test_buddy_alloc_exceeds_max_order),
{}
};

View File

@ -195,6 +195,9 @@ struct drm_client_buffer {
struct drm_framebuffer *fb;
};
struct drm_client_buffer *
drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
u32 format, u32 handle, u32 pitch);
struct drm_client_buffer *
drm_client_buffer_create_dumb(struct drm_client_dev *client, u32 width, u32 height, u32 format);
void drm_client_buffer_delete(struct drm_client_buffer *buffer);