7.1.6-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 357/744 bpf, sockmap: Fix cork use-after-free in tcp_bpf_sendmsg()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
[ Upstream commit 2d66a033864e27ab8d5e44cb36f31d9d2413bee4 ]
tcp_bpf_sendmsg() keeps msg_tx across sk_stream_wait_memory(), which drops and reacquires the socket lock. Its error path tries to decide whether msg_tx names the local temporary message by comparing it with the current value of psock->cork.
This comparison is unsafe when two threads send on the same socket:
Thread A Thread B
msg_tx = psock->cork
sk_msg_alloc() fails sk_stream_wait_memory()
releases the socket lock acquires the socket lock
completes the cork psock->cork = NULL frees the cork
reacquires the socket lock
msg_tx != psock->cork
sk_msg_free(msg_tx)
The stale cork is therefore mistaken for the local temporary message and freed again. KASAN reported:
BUG: KASAN: slab-use-after-free in sk_msg_free+0x49/0x50 Read of size 4 at addr ffff88810c908800 by task poc/90 Call Trace: sk_msg_free+0x49/0x50 tcp_bpf_sendmsg+0x14f5/0x1cc0 __sys_sendto+0x32c/0x3a0 __x64_sys_sendto+0xdb/0x1b0 Allocated by task 89: __kasan_kmalloc+0x8f/0xa0 tcp_bpf_sendmsg+0x16b3/0x1cc0 Freed by task 91: __kasan_slab_free+0x43/0x70 kfree+0x131/0x3c0 tcp_bpf_sendmsg+0xec3/0x1cc0
msg_tx can only name the stack-local tmp or the shared cork. Check for tmp directly so a changed psock->cork cannot turn a shared message into an apparent local one.
--- net/ipv4/tcp_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/tcp_bpf.c +1 -1
@@ -589,7 +589,7 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) wait_for_memory: err =sk_stream_wait_memory (sk, &timeo);if (err) { -if (msg_tx && msg_tx != psock->cork) +if (msg_tx == &tmp)sk_msg_free (sk, msg_tx); goto out_err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 358/744 tracing: Fix use-after-free freeing trigger private data
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
[ Upstream commit 79097812153b826fc156a2930ec8a90ed9edf4a2 ]
Commit 61d445af0a7c ("tracing: Add bulk garbage collection of freeing event_trigger_data") moved the kfree() of event_trigger_data to a kthread that runs tracepoint_synchronize_unregister() before freeing. That removed the synchronization the trigger .free callbacks used to get implicitly and inline from trigger_data_free().
event_hist_trigger_free(), event_hist_trigger_named_free() and event_enable_trigger_free() free their satellite data (hist_data, cmd_ops, enable_data) right after trigger_data_free() returns. With the synchronization now deferred to the kthread, a concurrent tracepoint handler can still reach that data through the list_del_rcu()'d trigger, causing a use-after-free.
The histogram teardown must stay synchronous: remove_hist_vars() and unregister_field_var_hists() have to detach a synthetic event from the histogram before the trigger-removal write returns, otherwise a following command races in and the synthetic-event removal fails with -EBUSY, as the trigger-synthetic-eprobe.tc selftest catches. Make those callbacks wait with the correct barrier - tracepoint_synchronize_unregister(), matching the free kthread - before freeing.
The enable trigger has no such synchronous requirement, and a blocking synchronize there would re-serialize the path that commit deliberately deferred. Give it an optional private_data_free() callback that the free kthread runs after its grace period, and free enable_data from there.
--- kernel/trace/trace.h | 1 + kernel/trace/trace_events_hist.c | 2 ++ kernel/trace/trace_events_trigger.c | 18 +++++++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-)
kernel/trace/trace.h +1 -0
@@ -1941,6 +1941,7 @@ struct event_trigger_data {struct list_head named_list;struct event_trigger_data *named_data;struct llist_node llist; +void (*private_data_free)(struct event_trigger_data *data); };/* Avoid typos */
kernel/trace/trace_events_hist.c +2 -0
@@ -6358,6 +6358,7 @@ static void event_hist_trigger_free(struct event_trigger_data *data)trigger_data_free (data); +tracepoint_synchronize_unregister ();remove_hist_vars (hist_data);unregister_field_var_hists (hist_data);
@@ -6397,6 +6398,7 @@ static void event_hist_trigger_named_free(struct event_trigger_data *data)del_named_trigger (data);trigger_data_free (data); +tracepoint_synchronize_unregister ();kfree (cmd_ops); } }
kernel/trace/trace_events_trigger.c +15 -3
@@ -38,6 +38,13 @@ static void trigger_create_kthread_locked(void) } } +static void trigger_data_free_one (struct event_trigger_data *data) +{ +if (data->private_data_free) + data->private_data_free (data); +kfree (data); +} +static void trigger_data_free_queued_locked (void ) {struct event_trigger_data *data, *tmp;
@@ -52,7 +59,7 @@ static void trigger_data_free_queued_locked(void)tracepoint_synchronize_unregister ();llist_for_each_entry_safe (data, tmp, llnodes, llist) -kfree (data); +trigger_data_free_one (data); }/* Bulk garbage collection of event_trigger_data elements */
@@ -75,7 +82,7 @@ static int trigger_kthread_fn(void *ignore)tracepoint_synchronize_unregister ();llist_for_each_entry_safe (data, tmp, llnodes, llist) -kfree (data); +trigger_data_free_one (data); }return 0 ;
@@ -1717,6 +1724,11 @@ int event_enable_trigger_print(struct seq_file *m,return 0 ; } +static void enable_trigger_private_data_free (struct event_trigger_data *data) +{ +kfree (data->private_data); +} +void event_enable_trigger_free (struct event_trigger_data *data) {struct enable_trigger_data *enable_data = data->private_data;
@@ -1728,9 +1740,9 @@ void event_enable_trigger_free(struct event_trigger_data *data)if (!data->ref) {/* Remove the SOFT_MODE flag */ trace_event_enable_disable (enable_data->file,0 ,1 ); + data->private_data_free = enable_trigger_private_data_free;trace_event_put_ref (enable_data->file->event_call);trigger_data_free (data); -kfree (enable_data); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 359/744 drm: renesas: rzg2l_mipi_dsi: Increase reset deassertion delay
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biju Das <[email protected]>
commit 7cbba8a8ba0219a267844d3116dbc77cecb4fcf8 upstream.
The RZ/G2L hardware manual (Rev. 1.50, May 2025), Section 34.4.2.1, requires waiting at least 1 msec after deasserting the CMN_RSTB signal before the DSI-Tx module is ready. Increase the delay from 1 usec to 1 msec by replacing udelay(1) with fsleep(1000) for RZ/G2L SoCs.
--- drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c +1 -1
@@ -528,7 +528,7 @@ static int rzg2l_mipi_dsi_dphy_init(struif (ret <0 )return ret; -udelay (1 ); +fsleep (1000 );return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 360/744 drm: renesas: rzg2l_mipi_dsi: Move rzg2l_mipi_dsi_set_display_timing()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biju Das <[email protected]>
commit 5bfa858d53bb252d7a012c2e0a97ae18182edfb1 upstream.
The RZ/G2L hardware manual (Rev. 1.50, May 2025), Section 34.4.2.1, requires display timings to be set after the HS clock is started. Move rzg2l_mipi_dsi_set_display_timing() from rzg2l_mipi_dsi_atomic_pre_enable() to rzg2l_mipi_dsi_atomic_enable(), placing it after rzg2l_mipi_dsi_start_hs_clock(). Drop the unused ret variable from rzg2l_mipi_dsi_atomic_pre_enable().
--- drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c +10 -6
@@ -1025,29 +1025,33 @@ static void rzg2l_mipi_dsi_atomic_pre_enconst struct drm_display_mode *mode;struct drm_connector *connector;struct drm_crtc *crtc; -int ret; connector =drm_atomic_get_new_connector_for_encoder (state, bridge->encoder); crtc =drm_atomic_get_new_connector_state (state, connector)->crtc; mode = &drm_atomic_get_new_crtc_state (state, crtc)->adjusted_mode; - ret =rzg2l_mipi_dsi_startup (dsi, mode); -if (ret <0 ) -return ; - -rzg2l_mipi_dsi_set_display_timing (dsi, mode); +rzg2l_mipi_dsi_startup (dsi, mode); }static void rzg2l_mipi_dsi_atomic_enable (struct drm_bridge *bridge,struct drm_atomic_state *state) {struct rzg2l_mipi_dsi *dsi =bridge_to_rzg2l_mipi_dsi (bridge); +const struct drm_display_mode *mode; +struct drm_connector *connector; +struct drm_crtc *crtc;int ret; ret =rzg2l_mipi_dsi_start_hs_clock (dsi);if (ret <0 ) goto err_stop; + connector =drm_atomic_get_new_connector_for_encoder (state, bridge->encoder); + crtc =drm_atomic_get_new_connector_state (state, connector)->crtc; + mode = &drm_atomic_get_new_crtc_state (state, crtc)->adjusted_mode; + +rzg2l_mipi_dsi_set_display_timing (dsi, mode); + ret =rzg2l_mipi_dsi_start_video (dsi);if (ret <0 ) goto err_stop_clock;
Greg Kroah-Hartman
maintainerPATCH 361/744 drm/tidss: Fix missing drm_bridge_add() call
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tomi Valkeinen <[email protected]>
commit 83084bb36847cbd2b13743f7333aaca12613a72b upstream.
tidss encoder-bridge is not added with drm_bridge_add() call, which leads to:
[drm] Missing drm_bridge_add() before attach
Add the missing call, using devm_drm_bridge_add() variant to get the drm_bridge_remove() handled automatically.
The commit marked with the Fixes tag (from v6.6) is the commit that added the encoder bridge without drm_bridge_add(). However, this fix is not directly applicable there as devm_drm_bridge_alloc() was not used to alloc the bridge, so using devm version for drm_bridge_add() wouldn't be safe. Instead, drm_bridge_add() and drm_bridge_remove() would be needed there, but that would require new plumbing code as we don't have a separate cleanup function in the tidss_encoder.c, not in the tidss_kms.c from which the encoder is created.
Also, there has been no reported bugs caused by the missing drm_bridge_add(). The drm_bridge_add() initializes the bridge's hpd_mutex, but HPD is not used for the encoder bridge. drm_bridge_add() also adds the bridge to the global bridge_list, which is only used in of_drm_find_bridge(), and again that is not used for the encoder bridge.
Thus, while the original commit is not right, there should be no bugs caused by it, and for the time being I'm not sending a patch for the stable kernels for the original commit.
This fix applies on top of commit 66cdf05f8548 ("drm/tidss: encoder:
convert to devm_drm_bridge_alloc()"), which changes the tidss_encoder.c to use the devm variant (added in v6.17). The warning print was added in v6.19, so applying this fix to v6.17+ gets rid of the warning for all kernel versions.
--- drivers/gpu/drm/tidss/tidss_encoder.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/tidss/tidss_encoder.c +2 -0
@@ -106,6 +106,8 @@ int tidss_encoder_create(struct tidss_de enc = &t_enc->encoder; enc->possible_crtcs = possible_crtcs; +devm_drm_bridge_add (tidss->dev, &t_enc->bridge); +/* Attaching first bridge to the encoder */ ret =drm_bridge_attach (enc, &t_enc->bridge,NULL ,DRM_BRIDGE_ATTACH_NO_CONNECTOR );
Greg Kroah-Hartman
maintainerPATCH 362/744 drm/rockchip: cdn-dp: add missing check in cdn_dp_config_video()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergey Shtylyov <[email protected]>
commit 46c31e1604d121221167cb09380de8c7d53290b9 upstream.
The result of cdn_dp_reg_write() is checked everywhere (with the error being logged by the callers) except one place in cdn_dp_config_video(). Add the missing result check, bailing out early on error...
Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool.
--- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/rockchip/cdn-dp-reg.c +2 -0
@@ -685,6 +685,8 @@ int cdn_dp_config_video(struct cdn_dp_de val =div_u64 (8 * (symbol +1 ), bit_per_pix) - val; val +=2 ; ret =cdn_dp_reg_write (dp,DP_VC_TABLE (15 ), val); +if (ret) + goto err_config_video;switch (video->color_depth) {case 6 :
Greg Kroah-Hartman
maintainerPATCH 363/744 drm/rockchip: analogix_dp: Add missing error check for platform_get_resource()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Ni <[email protected]>
commit 45895f4d4d5f222d07412f90664f88b059627859 upstream.
Add missing error check for platform_get_resource() return value to prevent NULL pointer dereference when memory resource is not available.
--- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +2 -0
@@ -461,6 +461,8 @@ static int rockchip_dp_probe(struct platreturn -ENOMEM ; res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -EINVAL ; i =0 ;while (dp_data[i].reg) {
Greg Kroah-Hartman
maintainerPATCH 364/744 drm/imagination: Count paired job fence as dependency in prepare_job()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alessio Belle <[email protected]>
commit 9cd74f935306cd857f46686975c43383e1d95f94 upstream.
The DRM scheduler's prepare_job() callback counts the remaining non-signaled native dependencies for a job, preventing job submission until those (plus job data and fence update) can fit in the job queue's CCCB.
This means checking which dependencies can be waited upon in the firmware, i.e. whether they are backed by a UFO object, i.e. whether their drm_sched_fence::parent has been assigned to a pvr_queue_fence::base fence. That happens when the job owning the fence is submitted to the firmware.
Paired geometry and fragment jobs are submitted at the same time, which means the dependency between them can't be checked this way before submission.
Update job_count_remaining_native_deps() to take into account the dependency between paired jobs.
This fixes cases where prepare_job() underestimated the space left in an almost full fragment CCCB, wrongly unblocking run_job(), which then returned early without writing the full sequence of commands to the CCCB.
The above lead to kernel warnings such as the following and potentially job timeouts (depending on waiters on the missing commands):
[ 375.702979] WARNING: drivers/gpu/drm/imagination/pvr_cccb.c:178 at pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr], CPU#1: kworker/u16:3/47 [ 375.703160] Modules linked in: [ 375.703571] CPU: 1 UID: 0 PID: 47 Comm: kworker/u16:3 Tainted: G W 7.0.0-rc2-g817eb6b11ad5 #40 PREEMPT [ 375.703613] Tainted: [W]=WARN [ 375.703627] Hardware name: Texas Instruments AM625 SK (DT) [ 375.703645] Workqueue: powervr-sched drm_sched_run_job_work [gpu_sched] [ 375.703741] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 375.703764] pc : pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] [ 375.703847] lr : pvr_queue_submit_job_to_cccb+0x578/0xa70 [powervr] [ 375.703921] sp : ffff800084a97650 [ 375.703934] x29: ffff800084a97740 x28: 0000000000000958 x27: ffff80008565d000 [ 375.703979] x26: 0000000000000030 x25: ffff800084a97680 x24: 0000000000001000 [ 375.704017] x23: ffff800084a97820 x22: 1ffff00010952ecc x21: 0000000000000008 [ 375.704056] x20: 00000000000006a8 x19: ffff00002ff7da88 x18: 0000000000000000 [ 375.704093] x17: 0000000020020000 x16: 0000000000020000 x15: 0000000000000000 [ 375.704132] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 [ 375.704168] x11: 000000000000f2f2 x10: 00000000f3000000 x9 : 00000000f3f3f3f3 [ 375.704206] x8 : 00000000f2f2f200 x7 : ffff700010952ecc x6 : 0000000000000008 [ 375.704243] x5 : 0000000000000000 x4 : 1ffff00010acba00 x3 : 0000000000000000 [ 375.704279] x2 : 0000000000000007 x1 : 0000000000000fff x0 : 000000000000002f [ 375.704317] Call trace: [ 375.704331] pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] (P) [ 375.704411] pvr_queue_submit_job_to_cccb+0x578/0xa70 [powervr] [ 375.704487] pvr_queue_run_job+0x3a4/0x990 [powervr] [ 375.704562] drm_sched_run_job_work+0x580/0xd48 [gpu_sched] [ 375.704623] process_one_work+0x520/0x1288 [ 375.704658] worker_thread+0x3f0/0xb3c [ 375.704680] kthread+0x334/0x3d8 [ 375.704706] ret_from_fork+0x10/0x20 [ 375.704736] ---[ end trace 0000000000000000 ]---
--- drivers/gpu/drm/imagination/pvr_queue.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
drivers/gpu/drm/imagination/pvr_queue.c +23 -4
@@ -179,7 +179,7 @@ static const struct dma_fence_ops pvr_qu/** * to_pvr_queue_job_fence() - Return a pvr_queue_fence object if the fence is -* backed by a UFO. +* already backed by a UFO. * @f: The dma_fence to turn into a pvr_queue_fence. * * Return:
@@ -356,6 +356,15 @@ static u32 job_cmds_size(struct pvr_jobpvr_cccb_get_size_of_cmd_with_hdr (job->cmd_len); } +static bool +is_paired_job_fence (struct dma_fence *fence,struct pvr_job *job) +{ +/* This assumes "fence" is one of "job"'s drm_sched_job::dependencies */ +return job->type ==DRM_PVR_JOB_TYPE_FRAGMENT && + job->paired_job && + &job->paired_job->base.s_fence->scheduled == fence; +} +/** * job_count_remaining_native_deps() - Count the number of non-signaled native dependencies. * @job: Job to operate on.
@@ -371,6 +380,17 @@ static unsigned long job_count_remainingxa_for_each (&job->base.dependencies, index, fence) {struct pvr_queue_fence *jfence; +if (is_paired_job_fence (fence, job)) { +/* +* A fence between paired jobs won't resolve to a pvr_queue_fence (i.e. +* be backed by a UFO) until the jobs have been submitted, together. +* The submitting code will insert a partial render fence command for this. +*/ +WARN_ON (dma_fence_is_signaled (fence)); + remaining_count++; +continue ; + } + jfence =to_pvr_queue_job_fence (fence);if (!jfence)continue ;
@@ -630,9 +650,8 @@ static void pvr_queue_submit_job_to_cccbif (!jfence)continue ; -/* Skip the partial render fence, we will place it at the end. */ -if (job->type ==DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job && - &job->paired_job->base.s_fence->scheduled == fence) +/* This fence will be placed last, as partial render fence. */ +if (is_paired_job_fence (fence, job))continue ;if (dma_fence_is_signaled (&jfence->base))
Greg Kroah-Hartman
maintainerPATCH 365/744 drm/bridge: cdns-dsi: Replace deprecated UNIVERSAL_DEV_PM_OPS()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vitor Soares <[email protected]>
commit 2d8b08844c0ecc6f2002fa68711e779aa18c8585 upstream.
The deprecated UNIVERSAL_DEV_PM_OPS() macro uses the provided callbacks for both runtime PM and system sleep. This causes the DSI clocks to be disabled twice: once during runtime suspend and again during system suspend, resulting in a WARN message from the clock framework when attempting to disable already-disabled clocks.
[ 84.384540] clk:231:5 already disabled [ 84.388314] WARNING: CPU: 2 PID: 531 at /drivers/clk/clk.c:1181 clk_core_disable+0xa4/0xac ... [ 84.579183] Call trace: [ 84.581624] clk_core_disable+0xa4/0xac [ 84.585457] clk_disable+0x30/0x4c [ 84.588857] cdns_dsi_suspend+0x20/0x58 [cdns_dsi] [ 84.593651] pm_generic_suspend+0x2c/0x44 [ 84.597661] ti_sci_pd_suspend+0xbc/0x15c [ 84.601670] dpm_run_callback+0x8c/0x14c [ 84.605588] __device_suspend+0x1a0/0x56c [ 84.609594] dpm_suspend+0x17c/0x21c [ 84.613165] dpm_suspend_start+0xa0/0xa8 [ 84.617083] suspend_devices_and_enter+0x12c/0x634 [ 84.621872] pm_suspend+0x1fc/0x368
To address this issue, replace UNIVERSAL_DEV_PM_OPS() with RUNTIME_PM_OPS(). Bridge and panel drivers should only deal with runtime PM, as the DRM framework manages system-wide power transitions through the bridge enable() and disable() hooks.
--- drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +6 -5
@@ -1230,7 +1230,7 @@ static const struct mipi_dsi_host_ops cd .transfer = cdns_dsi_transfer, }; -static int __maybe_unused cdns_dsi_resume (struct device *dev) +static int cdns_dsi_resume (struct device *dev) {struct cdns_dsi *dsi =dev_get_drvdata (dev);
@@ -1241,7 +1241,7 @@ static int __maybe_unused cdns_dsi_resumreturn 0 ; } -static int __maybe_unused cdns_dsi_suspend (struct device *dev) +static int cdns_dsi_suspend (struct device *dev) {struct cdns_dsi *dsi =dev_get_drvdata (dev);
@@ -1251,8 +1251,9 @@ static int __maybe_unused cdns_dsi_suspereturn 0 ; } -static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, - NULL); +static const struct dev_pm_ops cdns_dsi_pm_ops = { +RUNTIME_PM_OPS (cdns_dsi_suspend, cdns_dsi_resume,NULL ) +};static int cdns_dsi_drm_probe (struct platform_device *pdev) {
@@ -1399,7 +1400,7 @@ static struct platform_driver cdns_dsi_p .driver = { .name = "cdns-dsi", .of_match_table = cdns_dsi_of_match, - .pm = &cdns_dsi_pm_ops, + .pm = pm_ptr(&cdns_dsi_pm_ops), }, };module_platform_driver (cdns_dsi_platform_driver);
Greg Kroah-Hartman
maintainerPATCH 366/744 drm/exynos: fbdev: Remove offset into screen_buffer
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit 760bbc58c2c833dec0ee38dd959f4f2f4084fc57 upstream.
The screen_buffer field in struct fb_info contains the kernel address of the first byte of framebuffer memory. Do not add the display offset. This offset only describes scrolling during scanout.
--- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/gpu/drm/exynos/exynos_drm_fbdev.c +1 -5
@@ -61,17 +61,13 @@ static int exynos_drm_fbdev_update(strucstruct fb_info *fbi = helper->info;struct drm_framebuffer *fb = helper->fb;unsigned int size = fb->width * fb->height * fb->format->cpp[0 ]; -unsigned long offset; fbi->fbops = &exynos_drm_fb_ops;drm_fb_helper_fill_info (fbi, helper, sizes); - offset = fbi->var.xoffset * fb->format->cpp[0 ]; - offset += fbi->var.yoffset * fb->pitches[0 ]; - fbi->flags |=FBINFO_VIRTFB ; - fbi->screen_buffer = exynos_gem->kvaddr + offset; + fbi->screen_buffer = exynos_gem->kvaddr; fbi->screen_size = size; fbi->fix.smem_len = size;
Greg Kroah-Hartman
maintainerPATCH 367/744 drm/dp/mst: fix OOB reads in remote DPCD/I2C sideband reply parsers
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ashutosh Desai <[email protected]>
commit 1a8f537f5a1eeac941f262fe73078d6b08ba83c0 upstream.
drm_dp_sideband_parse_remote_dpcd_read() reads num_bytes from the raw message and then unconditionally does:
memcpy(bytes, &raw->msg[idx], num_bytes);
without checking that idx + num_bytes <= raw->curlen. raw->msg[] is 256 bytes; if a malicious or misbehaving MST hub sets num_bytes larger than the remaining payload, the memcpy reads past the received data into whatever follows in raw->msg[].
drm_dp_sideband_parse_remote_i2c_read_ack() has the same flaw (noted with a /* TODO check */ comment since the code was introduced).
Fix both functions by using a single combined check
(idx + num_bytes > curlen) before each memcpy. Since num_bytes is u8, it is always >= 0, so this strictly subsumes the simpler idx > curlen form and no separate step is needed.
--- drivers/gpu/drm/display/drm_dp_mst_topology.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/display/drm_dp_mst_topology.c +4 -2
@@ -871,7 +871,7 @@ static bool drm_dp_sideband_parse_remote goto fail_len; repmsg->u.remote_dpcd_read_ack.num_bytes = raw->msg[idx]; idx++; -if (idx > raw->curlen) +if (idx + repmsg->u.remote_dpcd_read_ack.num_bytes > raw->curlen) goto fail_len;memcpy (repmsg->u.remote_dpcd_read_ack.bytes, &raw->msg[idx], repmsg->u.remote_dpcd_read_ack.num_bytes);
@@ -907,7 +907,9 @@ static bool drm_dp_sideband_parse_remote goto fail_len; repmsg->u.remote_i2c_read_ack.num_bytes = raw->msg[idx]; idx++; -/* TODO check */ +if (idx + repmsg->u.remote_i2c_read_ack.num_bytes > raw->curlen) + goto fail_len; +memcpy (repmsg->u.remote_i2c_read_ack.bytes, &raw->msg[idx], repmsg->u.remote_i2c_read_ack.num_bytes);return true; fail_len:
Greg Kroah-Hartman
maintainerPATCH 368/744 drm/dp/mst: fix buffer overflows in sideband chunk accumulation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ashutosh Desai <[email protected]>
commit 55bd5e685bda455b9b50c835f8c8442d52a344a3 upstream.
drm_dp_sideband_append_payload() has three related bugs when processing device-provided sideband reply data:
1. Zero-length curchunk_len underflow: msg_len is a 6-bit field taken directly from the DP sideband header. If a device sends msg_len=0, curchunk_len is set to zero. The condition (curchunk_idx >= curchunk_len) is immediately true, and curchunk_len-1 wraps to 255 (u8 underflow). drm_dp_msg_data_crc4() reads 255 bytes from chunk[48], then memcpy() writes 255 bytes into msg[], both far out of bounds.
2. chunk[48] overflow: curchunk_len can reach 63 (6-bit field). chunk[] is only 48 bytes. Multi-iteration payload assembly appends 16-byte blocks until curchunk_idx reaches curchunk_len, writing up to 15 bytes past the end of chunk[] into msg[].
3. msg[256] overflow: each chunk contributes (curchunk_len-1) bytes to msg[]. No check ensures curlen + (curchunk_len-1) stays within msg[256], so the memcpy can spill into adjacent struct fields.
All three are reachable from any DP MST device that can forge sideband reply messages on a physical connection.
--- drivers/gpu/drm/display/drm_dp_mst_topology.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/gpu/drm/display/drm_dp_mst_topology.c +9 -0
@@ -789,6 +789,12 @@ static bool drm_dp_sideband_append_paylo {u8 crc4; +/* curchunk_len must be >= 1 (min 1 CRC byte) and fit in chunk[] */ +if (!msg->curchunk_len || + msg->curchunk_len >ARRAY_SIZE (msg->chunk) || + msg->curchunk_idx + replybuflen >ARRAY_SIZE (msg->chunk)) +return false; +memcpy (&msg->chunk[msg->curchunk_idx], replybuf, replybuflen); msg->curchunk_idx += replybuflen;
@@ -799,6 +805,9 @@ static bool drm_dp_sideband_append_payloprint_hex_dump (KERN_DEBUG ,"wrong crc" ,DUMP_PREFIX_NONE ,16 ,1 , msg->chunk, msg->curchunk_len, false); +/* Guard against accumulated msg[] overflow */ +if (msg->curlen + msg->curchunk_len -1 >ARRAY_SIZE (msg->msg)) +return false;/* copy chunk into bigger msg */ memcpy (&msg->msg[msg->curlen], msg->chunk, msg->curchunk_len -1 ); msg->curlen += msg->curchunk_len -1 ;
Greg Kroah-Hartman
maintainerPATCH 369/744 drm/tegra: fbdev: Remove offset into framebuffer memory
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit a18b6e30ecd69096beda4a0c96d2570900c3879a upstream.
The screen_buffer field in struct fb_info contains the kernel address of the first byte of framebuffer memory. Do not add the display offset. This offset only describes scrolling during scanout.
--- drivers/gpu/drm/tegra/fbdev.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/gpu/drm/tegra/fbdev.c +2 -6
@@ -76,7 +76,6 @@ int tegra_fbdev_driver_fbdev_probe(strucstruct fb_info *info = helper->info;unsigned int bytes_per_pixel;struct drm_framebuffer *fb; -unsigned long offset;struct tegra_bo *bo;size_t size;int err;
@@ -115,9 +114,6 @@ int tegra_fbdev_driver_fbdev_probe(strucdrm_fb_helper_fill_info (info, helper, sizes); - offset = info->var.xoffset * bytes_per_pixel + - info->var.yoffset * fb->pitches[0 ]; -if (bo->pages) { bo->vaddr =vmap (bo->pages, bo->num_pages,VM_MAP ,pgprot_writecombine (PAGE_KERNEL ));
@@ -129,9 +125,9 @@ int tegra_fbdev_driver_fbdev_probe(struc } info->flags |=FBINFO_VIRTFB ; - info->screen_buffer = bo->vaddr + offset; + info->screen_buffer = bo->vaddr; info->screen_size = size; - info->fix.smem_start = (unsigned long )(bo->iova + offset); + info->fix.smem_start = (unsigned long )(bo->iova); info->fix.smem_len = size;return 0 ;
Greg Kroah-Hartman
maintainerPATCH 370/744 drm/imagination: Fit paired fragment job in the correct CCCB
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alessio Belle <[email protected]>
commit 4baf9e70cb756d78dd56419f8baee2978a72d0c3 upstream.
For geometry jobs with a paired fragment job, at the moment, the DRM scheduler's prepare_job() callback:
- checks for internal (driver) dependencies for the geometry job;
- calls into pvr_queue_get_paired_frag_job_dep() to check for external dependencies for the fragment job (the two jobs are submitted together but the common scheduler code doesn't know about it, so this needs to be done at this point in time);
- calls into the prepare_job() callback again, but for the fragment job, to check its internal dependencies as well, passing the fragment job's drm_sched_job and the geometry job's drm_sched_entity / pvr_queue.
The problem with the last step is that pvr_queue_prepare_job() doesn't always take the mismatched fragment job and geometry queue into account, in particular when checking whether there is space for the fragment command to be submitted, so the code ends up checking for space in the geometry (i.e. wrong) CCCB.
The rest of the nested prepare_job() callback happens to work fine at the moment as the other internal dependencies are not relevant for a paired fragment job.
Move the initialisation of a paired fragment job's done fence and CCCB fence to pvr_queue_get_paired_frag_job_dep(), inferring the correct queue from the fragment job itself.
This fixes cases where prepare_job() wrongly assumed that there was enough space for a paired fragment job in its own CCCB, unblocking run_job(), which then returned early without writing the full sequence of commands to the CCCB.
The above lead to kernel warnings such as the following and potentially job timeouts (depending on waiters on the missing commands):
[ 552.421075] WARNING: drivers/gpu/drm/imagination/pvr_cccb.c:178 at pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr], CPU#2: kworker/u16:5/63 [ 552.421230] Modules linked in: [ 552.421592] CPU: 2 UID: 0 PID: 63 Comm: kworker/u16:5 Tainted: G W 7.0.0-rc2-gc5d053e4dccb #39 PREEMPT [ 552.421625] Tainted: [W]=WARN [ 552.421637] Hardware name: Texas Instruments AM625 SK (DT) [ 552.421655] Workqueue: powervr-sched drm_sched_run_job_work [gpu_sched] [ 552.421744] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 552.421766] pc : pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] [ 552.421850] lr : pvr_queue_submit_job_to_cccb+0x57c/0xa74 [powervr] [ 552.421923] sp : ffff800084c47650 [ 552.421936] x29: ffff800084c47740 x28: 0000000000000df8 x27: ffff800088a77000 [ 552.421979] x26: 0000000000000030 x25: ffff800084c47680 x24: 0000000000001000 [ 552.422017] x23: ffff800084c47820 x22: 1ffff00010988ecc x21: 0000000000000008 [ 552.422055] x20: 0000000000000208 x19: ffff000006ad5a88 x18: 0000000000000000 [ 552.422093] x17: 0000000020020000 x16: 0000000000020000 x15: 0000000000000000 [ 552.422130] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 [ 552.422167] x11: 000000000000f2f2 x10: 00000000f3000000 x9 : 00000000f3f3f3f3 [ 552.422204] x8 : 00000000f2f2f200 x7 : ffff700010988ecc x6 : 0000000000000008 [ 552.422241] x5 : 0000000000000000 x4 : 1ffff0001114ee00 x3 : 0000000000000000 [ 552.422278] x2 : 0000000000000007 x1 : 0000000000000fff x0 : 000000000000002f [ 552.422316] Call trace: [ 552.422330] pvr_cccb_write_command_with_header+0x2c4/0x330 [powervr] (P) [ 552.422411] pvr_queue_submit_job_to_cccb+0x57c/0xa74 [powervr] [ 552.422486] pvr_queue_run_job+0x3a4/0x990 [powervr] [ 552.422562] drm_sched_run_job_work+0x580/0xd48 [gpu_sched] [ 552.422623] process_one_work+0x520/0x1288 [ 552.422657] worker_thread+0x3f0/0xb3c [ 552.422679] kthread+0x334/0x3d8 [ 552.422706] ret_from_fork+0x10/0x20
--- drivers/gpu/drm/imagination/pvr_queue.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-)
drivers/gpu/drm/imagination/pvr_queue.c +14 -18
@@ -488,10 +488,11 @@ pvr_queue_get_job_kccb_fence(struct pvr_ }static struct dma_fence * -pvr_queue_get_paired_frag_job_dep (struct pvr_queue *queue,struct pvr_job *job) +pvr_queue_get_paired_frag_job_dep (struct pvr_job *job) {struct pvr_job *frag_job = job->type ==DRM_PVR_JOB_TYPE_GEOMETRY ? job->paired_job :NULL ; +struct pvr_queue *frag_queue = frag_job ? frag_job->ctx->queues.fragment :NULL ;struct dma_fence *f;unsigned long index;
@@ -510,7 +511,10 @@ pvr_queue_get_paired_frag_job_dep(structreturn dma_fence_get (f); } -return frag_job->base.sched->ops->prepare_job (&frag_job->base, &queue->entity); +/* Initialize the paired fragment job's done_fence, so we can signal it. */ +pvr_queue_job_fence_init (frag_job->done_fence, frag_queue); + +return pvr_queue_get_job_cccb_fence (frag_queue, frag_job); }/**
@@ -529,11 +533,6 @@ pvr_queue_prepare_job(struct drm_sched_j struct pvr_queue *queue = container_of(s_entity, struct pvr_queue, entity);struct dma_fence *internal_dep =NULL ; -/* -* Initialize the done_fence, so we can signal it. This must be done -* here because otherwise by the time of run_job() the job will end up -* in the pending list without a valid fence. -*/ if (job->type ==DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) {/* * This will be called on a paired fragment job after being
@@ -543,18 +542,15 @@ pvr_queue_prepare_job(struct drm_sched_j*/ if (job->paired_job->has_pm_ref)return NULL ; - -/* -* In this case we need to use the job's own ctx to initialise -* the done_fence. The other steps are done in the ctx of the -* paired geometry job. -*/ -pvr_queue_job_fence_init (job->done_fence, - job->ctx->queues.fragment); - }else { -pvr_queue_job_fence_init (job->done_fence, queue); } +/* +* Initialize the done_fence, so we can signal it. This must be done +* here because otherwise by the time of run_job() the job will end up +* in the pending list without a valid fence. +*/ +pvr_queue_job_fence_init (job->done_fence, queue); +/* CCCB fence is used to make sure we have enough space in the CCCB to * submit our commands. */
@@ -575,7 +571,7 @@ pvr_queue_prepare_job(struct drm_sched_j/* The paired job fence should come last, when everything else is ready. */ if (!internal_dep) - internal_dep =pvr_queue_get_paired_frag_job_dep (queue, job); + internal_dep =pvr_queue_get_paired_frag_job_dep (job);return internal_dep; }
Greg Kroah-Hartman
maintainerPATCH 371/744 drm/dp/mst: fix OOB reads on 2-byte fields in sideband reply parsers
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ashutosh Desai <[email protected]>
commit 6b89ba3dba2f583626fb693e47e951ffb8bf591f upstream.
Three sideband reply parsers read 16-bit fields as:
val = (raw->msg[idx] << 8) | (raw->msg[idx+1]);
and check bounds only after the fact. When idx == raw->curlen, raw->msg[idx+1] reads one byte past the received message data into the following struct fields (curchunk_len, curchunk_idx, curlen).
Affected functions:
- drm_dp_sideband_parse_enum_path_resources_ack() full_payload_bw_number and avail_payload_bw_number fields
- drm_dp_sideband_parse_allocate_payload_ack() allocated_pbn field
- drm_dp_sideband_parse_query_payload_ack() allocated_pbn field
Fix by using a single combined check (idx + 2 > curlen) before each 2-byte read. Since the check is strictly tighter than idx > curlen, no separate step is needed.
--- drivers/gpu/drm/display/drm_dp_mst_topology.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-)
drivers/gpu/drm/display/drm_dp_mst_topology.c +4 -13
@@ -934,16 +934,13 @@ static bool drm_dp_sideband_parse_enum_p repmsg->u.path_resources.port_number = (raw->msg[idx] >>4 ) &0xf ; repmsg->u.path_resources.fec_capable = raw->msg[idx] &0x1 ; idx++; -if (idx > raw->curlen) +if (idx +2 > raw->curlen) goto fail_len; repmsg->u.path_resources.full_payload_bw_number = (raw->msg[idx] <<8 ) | (raw->msg[idx+1 ]); idx +=2 ; -if (idx > raw->curlen) +if (idx +2 > raw->curlen) goto fail_len; repmsg->u.path_resources.avail_payload_bw_number = (raw->msg[idx] <<8 ) | (raw->msg[idx+1 ]); - idx +=2 ; -if (idx > raw->curlen) - goto fail_len;return true; fail_len:DRM_DEBUG_KMS ("enum resource parse length fail %d %d\n" , idx, raw->curlen);
@@ -961,12 +958,9 @@ static bool drm_dp_sideband_parse_alloca goto fail_len; repmsg->u.allocate_payload.vcpi = raw->msg[idx]; idx++; -if (idx > raw->curlen) +if (idx +2 > raw->curlen) goto fail_len; repmsg->u.allocate_payload.allocated_pbn = (raw->msg[idx] <<8 ) | (raw->msg[idx+1 ]); - idx +=2 ; -if (idx > raw->curlen) - goto fail_len;return true; fail_len:DRM_DEBUG_KMS ("allocate payload parse length fail %d %d\n" , idx, raw->curlen);
@@ -980,12 +974,9 @@ static bool drm_dp_sideband_parse_query_ repmsg->u.query_payload.port_number = (raw->msg[idx] >>4 ) &0xf ; idx++; -if (idx > raw->curlen) +if (idx +2 > raw->curlen) goto fail_len; repmsg->u.query_payload.allocated_pbn = (raw->msg[idx] <<8 ) | (raw->msg[idx +1 ]); - idx +=2 ; -if (idx > raw->curlen) - goto fail_len;return true; fail_len:DRM_DEBUG_KMS ("query payload parse length fail %d %d\n" , idx, raw->curlen);
Greg Kroah-Hartman
maintainerPATCH 372/744 drm/i915/cdclk: Fix up CDCLK_FREQ_DECIMAL without a full PLL re-enable
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ville Syrjälä <[email protected]>
commit 2ee8dbd880b14fb0b5115bf2353c7900aa33b95b upstream.
The GOP (and even Bspec on some platforms) is a bit inconsistent on what the CDCLK_FREQ_DECIMAL divider should be. Currently any mismatch there causes a full CDCLK PLL disable+re-enable, which we really don't want to do if any displays are currently active. Let's instead just reprogram CDCLK_FREQ_DECIMAL when that is the only thing amiss. For any other (more serious) mismatch we still punt to the full PLL reprogramming.
We also need to tweak the bxt_cdclk_cd2x_pipe() stuff a bit to consistently select pipe==NONE since we have no idea which pipes are enabled at this point. Since we're not actually changing the CDCLK frequency here we don't need to sync the update to any pipe.
--- drivers/gpu/drm/i915/display/intel_cdclk.c | 41 ++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-)
drivers/gpu/drm/i915/display/intel_cdclk.c +34 -7
@@ -1256,9 +1256,22 @@ static void skl_sanitize_cdclk(struct in cdctl =intel_de_read (display,CDCLK_CTL ); expected = (cdctl &CDCLK_FREQ_SEL_MASK ) |skl_cdclk_decimal (display->cdclk.hw.cdclk); -if (cdctl == expected) -/* All well; nothing to sanitize */ -return ; + +if (cdctl != expected) { + cdctl &= ~CDCLK_FREQ_DECIMAL_MASK ; + cdctl |= expected &CDCLK_FREQ_DECIMAL_MASK ; + +if (cdctl != expected) + goto sanitize; + +drm_dbg_kms (display->drm,"Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n" , +intel_de_read (display,CDCLK_CTL ), expected); + +intel_de_write (display,CDCLK_CTL , expected); + } + +/* All well; nothing to sanitize */ +return ; sanitize:drm_dbg_kms (display->drm,"Sanitizing cdclk programmed by pre-os\n" );
@@ -2354,11 +2367,25 @@ static void bxt_sanitize_cdclk(struct in* (PIPE_NONE). */ cdctl &= ~bxt_cdclk_cd2x_pipe (display,INVALID_PIPE ); - expected &= ~bxt_cdclk_cd2x_pipe (display,INVALID_PIPE ); + cdctl |=bxt_cdclk_cd2x_pipe (display,INVALID_PIPE ); -if (cdctl == expected) -/* All well; nothing to sanitize */ -return ; +if (cdctl != expected) { +if (DISPLAY_VER (display) <20 ) { + cdctl &= ~CDCLK_FREQ_DECIMAL_MASK ; + cdctl |= expected &CDCLK_FREQ_DECIMAL_MASK ; + } + +if (cdctl != expected) + goto sanitize; + +drm_dbg_kms (display->drm,"Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n" , +intel_de_read (display,CDCLK_CTL ), expected); + +intel_de_write (display,CDCLK_CTL , expected); + } + +/* All well; nothing to sanitize */ +return ; sanitize:drm_dbg_kms (display->drm,"Sanitizing cdclk programmed by pre-os\n" );
Greg Kroah-Hartman
maintainerPATCH 373/744 drm/amd/pm: re-enable MC access after PrepareMp1ForUnload on SMU V15 APUs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shubhankar Milind Sardeshpande <[email protected]>
commit 76589bcc73f477ef2b3b90e4fae6a7a4dfd925af upstream.
During smu_v15_0_0_system_features_control(), the driver sends a PrepareMp1ForUnload message to PMFW. PMFW then performs nBIF and SYSHUB function-level resets (FLR), disabling PCIe CFG space reset, which clears the framebuffer enable bit to zero and disables MC (memory controller) access from the host.
Re-enable MC access via the nbio mc_access_enable callback right after PrepareMp1ForUnload completes in smu_v15_0_0_system_features_control().
--- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c +6 -1
@@ -227,9 +227,14 @@ static int smu_v15_0_0_system_features_cstruct amdgpu_device *adev = smu->adev;int ret =0 ; -if (!en && !adev->in_s0ix) +if (!en && !adev->in_s0ix) { ret =smu_cmn_send_smc_msg (smu, SMU_MSG_PrepareMp1ForUnload,NULL ); +/* SMU resets BIF_FB_EN to zero, re-enable MC access on APUs with SMU V15 */ +if (!ret && adev->nbio.funcs && adev->nbio.funcs->mc_access_enable) + adev->nbio.funcs->mc_access_enable (adev, true); + } +return ret; }
Greg Kroah-Hartman
maintainerPATCH 374/744 drm/amdgpu/gfx: fix cleaner shader IB buffer overflow
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
commit 3e864bf2a32a1cbdf1e0f9c5a5a4176e8575f4a3 upstream.
The cleaner shader sysfs path allocates a 16-dword (64 byte) IB but incorrectly fills (align_mask + 1) dwords. On GFX rings align_mask is 0xff, so the loop wrote 256 dwords into a 64-byte buffer, causing a kernel page fault.
The IB only needs to be a minimal NOP shell to schedule the job; the cleaner shader itself is emitted on the ring via emit_cleaner_shader(). Fill 16 dwords to match the allocation.
v2: Use ib_size_dw variable (Lijo)
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +5 -5
@@ -1646,12 +1646,13 @@ static int amdgpu_gfx_run_cleaner_shaderstruct amdgpu_device *adev = ring->adev;struct drm_gpu_scheduler *sched = &ring->sched;struct drm_sched_entity entity; +unsigned int ib_size_dw =16 ;static atomic_t counter;struct dma_fence *f;struct amdgpu_job *job;struct amdgpu_ib *ib;void *owner; -int i, r; +int r;/* Initialize the scheduler entity */ r = drm_sched_entity_init(&entity, DRM_SCHED_PRIORITY_NORMAL,
@@ -1669,7 +1670,7 @@ static int amdgpu_gfx_run_cleaner_shader owner = (void *)(unsigned long )atomic_inc_return (&counter); r =amdgpu_job_alloc_with_ib (ring->adev, &entity, owner, -64 ,0 , &job, + ib_size_dw *sizeof (uint32_t ),0 , &job,AMDGPU_KERNEL_JOB_ID_CLEANER_SHADER );if (r) goto err;
@@ -1679,9 +1680,8 @@ static int amdgpu_gfx_run_cleaner_shader job->run_cleaner_shader = true; ib = &job->ibs[0 ]; -for (i =0 ; i <= ring->funcs->align_mask; ++i) - ib->ptr[i] = ring->funcs->nop; - ib->length_dw = ring->funcs->align_mask +1 ; +memset32 (ib->ptr, ring->funcs->nop, ib_size_dw); + ib->length_dw = ib_size_dw; f =amdgpu_job_submit (job);
Greg Kroah-Hartman
maintainerPATCH 375/744 drm/amdgpu/uvd: Fix forcing MSG, FB BOs into VCPU segment when it isnt at 0 (v2)
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit 32bd35f068a3507a1b3922cd12ea2985fc58c85b upstream.
UVD 4.x and older can only access MSG, FEEDBACK buffers from a specific 256M VRAM segment that the VCPU BO is also located in. We already modify all placements of the given BO to ensure the BO is placed within this segment.
Previously, it always assumed that the VCPU segment is the first 256M of VRAM, even though under some conditions the VCPU BO could be allocated outside this segment, which made UVD non-functional as the BOs were not inside the same segment as the UVD VCPU BO.
Solve that by using the segment where the VCPU BO actually is.
This fixes an issue with UVD failing to initialize on SI/CIK when resizable BAR is enabled and the VCPU BO is allocated in a different segment.
v2:
- For other BOs, keep using the same UVD segment as before.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 33 +++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +24 -9
@@ -135,7 +135,7 @@ MODULE_FIRMWARE(FIRMWARE_VEGA12);MODULE_FIRMWARE (FIRMWARE_VEGA20 );static void amdgpu_uvd_idle_work_handler (struct work_struct *work); -static void amdgpu_uvd_force_into_uvd_segment (struct amdgpu_bo *abo); +static void amdgpu_uvd_force_into_vcpu_segment (struct amdgpu_bo *abo); static int amdgpu_uvd_create_msg_bo_helper(struct amdgpu_device *adev, uint32_t size,
@@ -158,7 +158,7 @@ static int amdgpu_uvd_create_msg_bo_helpamdgpu_bo_kunmap (bo);amdgpu_bo_unpin (bo);amdgpu_bo_placement_from_domain (bo,AMDGPU_GEM_DOMAIN_VRAM ); -amdgpu_uvd_force_into_uvd_segment (bo); +amdgpu_uvd_force_into_vcpu_segment (bo); r =ttm_bo_validate (&bo->tbo, &bo->placement, &ctx);if (r) goto err;
@@ -545,6 +545,24 @@ void amdgpu_uvd_free_handles(struct amdg } } +static void amdgpu_uvd_force_into_vcpu_segment (struct amdgpu_bo *bo) +{ +struct amdgpu_device *adev =amdgpu_ttm_adev (bo->tbo.bdev); +struct amdgpu_bo *vcpu_bo = adev->uvd.inst[0 ].vcpu_bo; +struct amdgpu_res_cursor vcpu_cur; + +amdgpu_res_first (vcpu_bo->tbo.resource,0 , +amdgpu_bo_size (vcpu_bo), &vcpu_cur); + + bo->placement.num_placement =1 ; + bo->placement.placement = &bo->placements[0 ]; + bo->placements[0 ].fpfn =ALIGN_DOWN (vcpu_cur.start,SZ_256M ) >>PAGE_SHIFT ; + bo->placements[0 ].lpfn = bo->placements[0 ].fpfn + (SZ_256M >>PAGE_SHIFT ); + bo->placements[0 ].mem_type = vcpu_bo->tbo.resource->mem_type; +if (bo->placements[0 ].mem_type ==TTM_PL_VRAM ) + bo->placements[0 ].flags |=TTM_PL_FLAG_CONTIGUOUS ; +} +static void amdgpu_uvd_force_into_uvd_segment (struct amdgpu_bo *abo) {int i;
@@ -595,13 +613,10 @@ static int amdgpu_uvd_cs_pass1(struct amif (!ctx->parser->adev->uvd.address_64_bit) {/* check if it's a message or feedback command */ cmd =amdgpu_ib_get_value (ctx->ib, ctx->idx) >>1 ; -if (cmd ==0x0 || cmd ==0x3 ) { -/* yes, force it into VRAM */ -uint32_t domain =AMDGPU_GEM_DOMAIN_VRAM ; - -amdgpu_bo_placement_from_domain (bo, domain); - } -amdgpu_uvd_force_into_uvd_segment (bo); +if (cmd ==0x0 || cmd ==0x3 ) +amdgpu_uvd_force_into_vcpu_segment (bo); +else +amdgpu_uvd_force_into_uvd_segment (bo); r =ttm_bo_validate (&bo->tbo, &bo->placement, &tctx); }
Greg Kroah-Hartman
maintainerPATCH 376/744 drm/amdgpu/uvd: Place VCPU BO only in VRAM for UVD 4.x and older
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit 8002b744ad70055ef11ff7d0a7d685bfe8ffe6e4 upstream.
These UVD versions don't fully support GPUVM and are only validated to work when their VCPU BO is placed in VRAM.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +11 -6
@@ -188,6 +188,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_devconst struct common_firmware_header *hdr;unsigned int family_id;int i, j, r; +u32 vcpu_bo_domain;INIT_DELAYED_WORK (&adev->uvd.idle_work, amdgpu_uvd_idle_work_handler);
@@ -319,12 +320,20 @@ int amdgpu_uvd_sw_init(struct amdgpu_devif (adev->firmware.load_type !=AMDGPU_FW_LOAD_PSP ) bo_size +=AMDGPU_GPU_PAGE_ALIGN (le32_to_cpu (hdr->ucode_size_bytes) +8 ); +/* UVD 5.0 and newer HW can use 64 bit addressing. */ + adev->uvd.address_64_bit = + !amdgpu_device_ip_block_version_cmp (adev,AMD_IP_BLOCK_TYPE_UVD ,5 ,0 ); + + vcpu_bo_domain =AMDGPU_GEM_DOMAIN_VRAM ; +if (adev->uvd.address_64_bit) + vcpu_bo_domain |=AMDGPU_GEM_DOMAIN_GTT ; +for (j =0 ; j < adev->uvd.num_uvd_inst; j++) {if (adev->uvd.harvest_config & (1 << j))continue ; + r =amdgpu_bo_create_kernel (adev, bo_size,PAGE_SIZE , -AMDGPU_GEM_DOMAIN_VRAM | -AMDGPU_GEM_DOMAIN_GTT , + vcpu_bo_domain, &adev->uvd.inst[j].vcpu_bo, &adev->uvd.inst[j].gpu_addr, &adev->uvd.inst[j].cpu_addr);
@@ -339,10 +348,6 @@ int amdgpu_uvd_sw_init(struct amdgpu_dev adev->uvd.filp[i] =NULL ; } -/* from uvd v5.0 HW addressing capacity increased to 64 bits */ -if (!amdgpu_device_ip_block_version_cmp (adev,AMD_IP_BLOCK_TYPE_UVD ,5 ,0 )) - adev->uvd.address_64_bit = true; - r =amdgpu_uvd_create_msg_bo_helper (adev,128 <<10 , &adev->uvd.ib_bo);if (r)return r;
Greg Kroah-Hartman
maintainerPATCH 377/744 drm/amdgpu: check amdgpu_vm_bo_find() result in GET_MAPPING_INFO
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit 93475c34111916df71c63e510fc52db01351f809 upstream.
The AMDGPU_GEM_OP_GET_MAPPING_INFO path of amdgpu_gem_op_ioctl() looks up the bo_va for the buffer object in the caller's VM via amdgpu_vm_bo_find(), but uses the returned pointer without checking it.
amdgpu_vm_bo_find() returns NULL when the BO has no bo_va in that VM, which is the normal case for a BO that has never been mapped. The result is fed straight into amdgpu_vm_bo_va_for_each_valid_mapping(), which expands to list_for_each_entry(mapping, &(bo_va)->valids, list) and dereferences bo_va, causing a NULL pointer dereference.
This is reachable by any process able to issue the ioctl (render group) simply by requesting mapping info for an unmapped BO.
Return -ENOENT when no bo_va is found, jumping to out_exec so the drm_exec context and GEM object reference are released.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +5 -0
@@ -1094,6 +1094,11 @@ int amdgpu_gem_op_ioctl(struct drm_devic* If that number is larger than the size of the array, the ioctl must * be retried. */ +if (!bo_va) { + r = -ENOENT ; + goto out_exec; + } +if (args->num_entries >INT_MAX /sizeof (*vm_entries)) { r = -EINVAL ; goto out_exec;
Greg Kroah-Hartman
maintainerPATCH 378/744 drm/sysfb: Do not page-align visible size of the framebuffer
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit 134844856c399bfa9462a159dcf860bfdb748055 upstream.
Only return the actually visible size of the system framebuffer in drm_sysfb_get_visible_size_si(). Drivers use this size value for reserving access to framebuffer memory. Increasing the value can make later attempts to do so fail.
--- drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c +1 -1
@@ -67,7 +67,7 @@ EXPORT_SYMBOL(drm_sysfb_get_stride_si);u64 drm_sysfb_get_visible_size_si (struct drm_device *dev,const struct screen_info *si,unsigned int height,unsigned int stride,u64 size) { -u64 vsize =PAGE_ALIGN (height * stride); +u64 vsize = height * stride;return drm_sysfb_get_validated_size0 (dev,"visible size" , vsize, size); }
Greg Kroah-Hartman
maintainerPATCH 379/744 drm/sysfb: Avoid truncating maximum stride
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit 9206b22fb959f4a9cf1921f34aed0df1dcb1ab04 upstream.
Passing a maximum as 64-bit type to drm_sysfb_get_validated_int0() can truncate the value to 32 bits. Use drm_sysfb_get_validated_size0(), which uses 64-bit arithmetics. Then test the returned stride against the limits of int to avoid truncations in the returned value. A valid stride is in the range of [1, INT_MAX] inclusive.
--- drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c +7 -1
@@ -56,11 +56,17 @@ int drm_sysfb_get_stride_si(struct drm_d unsigned int width, unsigned int height, u64 size) { u64 lfb_linelength = si->lfb_linelength; +s64 stride;if (!lfb_linelength) lfb_linelength =drm_format_info_min_pitch (format,0 , width); -return drm_sysfb_get_validated_int0 (dev,"stride" , lfb_linelength,div64_u64 (size, height)); + stride =drm_sysfb_get_validated_size0 (dev,"stride" , lfb_linelength, +div64_u64 (size, height)); +if (stride <INT_MIN || stride >INT_MAX ) +return -EINVAL ; + +return (int )stride;/* stride or negative errno code */ }EXPORT_SYMBOL (drm_sysfb_get_stride_si);
Greg Kroah-Hartman
maintainerPATCH 380/744 drm/xe/guc: Fix buffer overflow in steered register list allocation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejas Upadhyay <[email protected]>
commit 632ecc90e1ca5d3b6822bb4d08f84a175b6c42c0 upstream.
The size calculation for the steered register extarray uses only the geometry DSS mask (g_dss_mask) to determine the number of entries to allocate:
total = bitmap_weight(gt->fuse_topo.g_dss_mask, ...) * steer_reg_num;
However, the filling loop uses for_each_dss_steering(), which iterates over for_each_dss(), defined as the union of g_dss_mask and c_dss_mask (geometry + compute DSS). On platforms with compute-only DSS bits, the loop writes past the allocated buffer, corrupting adjacent slab objects.
This manifests as list_del corruption and SLUB redzone overwrites during drm_managed_release on device unbind, since the overflow corrupts the drmres list_head of neighboring allocations.
Fix by computing the allocation size using the union of both DSS masks, matching the iteration pattern of for_each_dss_steering().
--
v2:
- use bitmap_weighted_or() (Zhanjun)
--- drivers/gpu/drm/xe/xe_guc_capture.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_guc_capture.c +8 -2
@@ -461,8 +461,14 @@ static void guc_capture_alloc_steered_liif (!list || guc->capture->extlists)return ; - total =bitmap_weight (gt->fuse_topo.g_dss_mask,sizeof (gt->fuse_topo.g_dss_mask) *8 ) * -guc_capture_get_steer_reg_num (guc_to_xe (guc)); + { +xe_dss_mask_t all_dss; + + total =bitmap_weighted_or (all_dss, gt->fuse_topo.g_dss_mask, + gt->fuse_topo.c_dss_mask, +XE_MAX_DSS_FUSE_BITS ) * +guc_capture_get_steer_reg_num (guc_to_xe (guc)); + }if (!total)return ;
Greg Kroah-Hartman
maintainerPATCH 381/744 drm/xe: Add compact-PT and addr mask handling for page reclaim
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Nguyen <[email protected]>
commit 0b5ed2756d45b04669502a1f13b1657ec7664571 upstream.
Current implementation of generate_reclaim_entry() overlooks some differences between the different page implementations: address masking and compact 64K page handling.
Address masking of each leaf varies depending on the leaf entry size. generate_reclaim_entry() is using XE_PTE_ADDR_MASK [51:12] for all leaf entries. For 2MB PTEs, bit 12 (PAT) is part of the flags so the old mask corrupts the physical address extraction.
64K pages can be represented as PS64 and a compact PT, which the latter was not handled. Compact pages aren't walked by the unbind walker, so we separately walk through the compact PT to ensure none of the leaf 64K PTEs are dropped. Previously, compact PT were causing an abort since it was considered covered and not descended into.
v2:
- Update 64K entry/unbind walker for 64K compact PT handling. (Matthew)
- Rework calculations of reclamation and address mask size.
- Add new func abstracting the error handling before generating the reclaim entry.
v3:
- Report finer addr granularity in abort debug print for compact. (Zongyao)
- Add comments for ADDR_MASK usage. (Zongyao)
- Drop existing phys_addr asserts, the new XE_PAGE_ADDR_MASK clears bits checked, so redundant asserts. (Sashiko)
- WARN_ON to verify compact pt and edge pt won't be possible.
--- drivers/gpu/drm/xe/regs/xe_gtt_defs.h | 6 + drivers/gpu/drm/xe/xe_pt.c | 133 +++++++++++++++++++--------------- 2 files changed, 83 insertions(+), 56 deletions(-)
drivers/gpu/drm/xe/regs/xe_gtt_defs.h +5 -1
@@ -9,7 +9,11 @@#define XELPG_GGTT_PTE_PAT0 BIT_ULL(52)#define XELPG_GGTT_PTE_PAT1 BIT_ULL(53) -#define XE_PTE_ADDR_MASK GENMASK_ULL(51, 12) +/* +* Mask for PTE address bits [51:shift]. +* shift is the lower address boundary of page. +*/ +#define XE_PAGE_ADDR_MASK (shift) GENMASK_ULL(51, (shift))#define GGTT_PTE_VFID GENMASK_ULL(11, 2)#define GUC_GGTT_TOP 0xFEE00000
drivers/gpu/drm/xe/xe_pt.c +78 -55
207 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 382/744 drm/amd/display: Restore periodic detection for DCN35
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Lipski <[email protected]>
commit 5cc0f35d83e2c72f70edaf7478db350af3082a17 upstream.
[Why&How]
Periodic detection callbacks from DCN35 was removed for higher IPS residency causing some displays to fail to recover after DPMS sleep. The monitors bounces HPD ~1.2s after link training, and without periodic detection the system enters IPS with no mechanism to wake and rediscover the display.
Restore the periodic detection calls in dcn35_clk_mgr for now. It should be replaced with a proper IPS-aware solution long term using DMUB.
Also remove it from dcn31 and dcn314_clk_mgr.c since they do not have IPS, thus should not affect them.
--- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c | 2 -- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c | 2 -- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 2 ++ 3 files changed, 2 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +0 -2
@@ -155,7 +155,6 @@ void dcn31_update_clocks(struct clk_mgrif (new_clocks->zstate_support !=DCN_ZSTATE_SUPPORT_DISALLOW && new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {dcn31_smu_set_zstate_support (clk_mgr, new_clocks->zstate_support); -dm_helpers_enable_periodic_detection (clk_mgr_base->ctx, true); clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; }
@@ -181,7 +180,6 @@ void dcn31_update_clocks(struct clk_mgrif (new_clocks->zstate_support ==DCN_ZSTATE_SUPPORT_DISALLOW && new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {dcn31_smu_set_zstate_support (clk_mgr,DCN_ZSTATE_SUPPORT_DISALLOW ); -dm_helpers_enable_periodic_detection (clk_mgr_base->ctx, false); clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; }
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c +0 -2
@@ -227,7 +227,6 @@ void dcn314_update_clocks(struct clk_mgrif (new_clocks->zstate_support !=DCN_ZSTATE_SUPPORT_DISALLOW && new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {dcn314_smu_set_zstate_support (clk_mgr, new_clocks->zstate_support); -dm_helpers_enable_periodic_detection (clk_mgr_base->ctx, true); clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; }
@@ -252,7 +251,6 @@ void dcn314_update_clocks(struct clk_mgrif (new_clocks->zstate_support ==DCN_ZSTATE_SUPPORT_DISALLOW && new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {dcn314_smu_set_zstate_support (clk_mgr,DCN_ZSTATE_SUPPORT_DISALLOW ); -dm_helpers_enable_periodic_detection (clk_mgr_base->ctx, false); clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; }
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +2 -0
@@ -405,6 +405,7 @@ void dcn35_update_clocks(struct clk_mgrif (new_clocks->zstate_support !=DCN_ZSTATE_SUPPORT_DISALLOW && new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {dcn35_smu_set_zstate_support (clk_mgr, new_clocks->zstate_support); +dm_helpers_enable_periodic_detection (clk_mgr_base->ctx, true); clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; }
@@ -424,6 +425,7 @@ void dcn35_update_clocks(struct clk_mgrif (new_clocks->zstate_support ==DCN_ZSTATE_SUPPORT_DISALLOW && new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {dcn35_smu_set_zstate_support (clk_mgr,DCN_ZSTATE_SUPPORT_DISALLOW ); +dm_helpers_enable_periodic_detection (clk_mgr_base->ctx, false); clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; }
Greg Kroah-Hartman
maintainerPATCH 383/744 drm/amdgpu/gfx9: Fix Ring and IB test fail after mode2
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiqian Chen <[email protected]>
commit 85ed06d990ff73212b5a91a406671cabd962e521 upstream.
For Renior APU with gfx9, in some test scenarios with disabling ring_reset, like accessing an unmapped invalid address, it can trigger a gpu job timeout event, then driver uses Mode2 reset to reset GPU, but after Mode2 compute Ring test and IB test fail randomly. It because the HQDs of MECs are always active before or after Mode2, that causes MECs use stale HQDs when MECs are unhalted before driver restore MQDs, and causes CPC and CPF are still stuck after Mode2, then causes compute Ring and IB tests fail.
So, add sequences to deactivate HQDs of MECs in suspend IP function of the resetting process.
v2: Move all sequences into a new function gfx_v9_0_cp_mode2_clear_state (Ray Huang)
To check reset Mode2 method in the if condition (Ray Huang)
v3: Move all sequences before Mode2 instead of after Mode2 (Timur Kristóf)
v4: Call amdgpu_gfx_rlc_enter/exit_safe_mode int the begin and end of
gfx_v9_0_deactivate_kcq_hqd (Alex Deucher)
--- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +39 -0
@@ -4049,6 +4049,41 @@ static int gfx_v9_0_hw_init(struct amdgpreturn r; } +static void gfx_v9_0_deactivate_kcq_hqd (struct amdgpu_device *adev) +{ +amdgpu_gfx_rlc_enter_safe_mode (adev,0 ); +for (int i =0 ; i < adev->gfx.num_compute_rings; i++) { +u32 tmp; +struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; + +mutex_lock (&adev->srbm_mutex); +soc15_grbm_select (adev, ring->me, ring->pipe, ring->queue,0 ,0 ); + tmp =RREG32_SOC15 (GC ,0 , mmCP_HQD_ACTIVE); +/* disable the queue if it's active */ +if (tmp &CP_HQD_ACTIVE__ACTIVE_MASK ) { +int j; + +WREG32_SOC15 (GC ,0 , mmCP_HQD_DEQUEUE_REQUEST,1 ); +for (j =0 ; j < adev->usec_timeout; j++) { + tmp =RREG32_SOC15 (GC ,0 , mmCP_HQD_ACTIVE); +if (!(tmp &CP_HQD_ACTIVE__ACTIVE_MASK )) +break ; +udelay (1 ); + } +if (j ==AMDGPU_MAX_USEC_TIMEOUT ) { +DRM_DEBUG ("comp_%u_%u_%u dequeue request failed.\n" , + ring->me, ring->pipe, ring->queue); +/* Manual disable if dequeue request times out */ +WREG32_SOC15 (GC ,0 , mmCP_HQD_ACTIVE,0 ); + } +WREG32_SOC15 (GC ,0 , mmCP_HQD_DEQUEUE_REQUEST,0 ); + } +soc15_grbm_select (adev,0 ,0 ,0 ,0 ,0 ); +mutex_unlock (&adev->srbm_mutex); + } +amdgpu_gfx_rlc_exit_safe_mode (adev,0 ); +} +static int gfx_v9_0_hw_fini (struct amdgpu_ip_block *ip_block) {struct amdgpu_device *adev = ip_block->adev;
@@ -4075,6 +4110,10 @@ static int gfx_v9_0_hw_fini(struct amdgpreturn 0 ; } +if ((adev->flags &AMD_IS_APU ) &&amdgpu_in_reset (adev) && +amdgpu_asic_reset_method (adev) ==AMD_RESET_METHOD_MODE2 ) +gfx_v9_0_deactivate_kcq_hqd (adev); +/* Use deinitialize sequence from CAIL when unbinding device from driver, * otherwise KIQ is hanging when binding back */
Greg Kroah-Hartman
maintainerPATCH 384/744 drm/amdgpu: Fix amdgpu_bo_move() when old_mem and new_mem are both GTT
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit ee94a65f192c05c543b4d3ad7137cd696b5c18fc upstream.
The UVD code relies on GTT to GTT moves in order to ensure that its BOs don't cross 256M segments.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +18 -0
@@ -515,6 +515,15 @@ static int amdgpu_bo_move(struct ttm_bufif (new_mem->mem_type ==TTM_PL_TT || new_mem->mem_type ==AMDGPU_PL_PREEMPT ) { +if (old_mem && (old_mem->mem_type ==TTM_PL_TT || + old_mem->mem_type ==AMDGPU_PL_PREEMPT )) { + r =ttm_bo_wait_ctx (bo, ctx); +if (r) +return r; + +amdgpu_ttm_backend_unbind (bo->bdev, bo->ttm); + } + r =amdgpu_ttm_backend_bind (bo->bdev, bo->ttm, new_mem);if (r)return r;
@@ -547,6 +556,15 @@ static int amdgpu_bo_move(struct ttm_bufamdgpu_bo_move_notify (bo, evict, new_mem);ttm_resource_free (bo, &bo->resource);ttm_bo_assign_mem (bo, new_mem); +return 0 ; + } +if ((old_mem->mem_type ==TTM_PL_TT || + old_mem->mem_type ==AMDGPU_PL_PREEMPT ) && + (new_mem->mem_type ==TTM_PL_TT || + new_mem->mem_type ==AMDGPU_PL_PREEMPT )) { +amdgpu_bo_move_notify (bo, evict, new_mem); +ttm_resource_free (bo, &bo->resource); +ttm_bo_assign_mem (bo, new_mem);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 385/744 drm/amdgpu: Fix context pstate override handling
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tvrtko Ursulin <[email protected]>
commit c1dc4ccb82c9e56325d8e7514ca4c90bd1efb351 upstream.
There are several problems in the context pstate handling code.
The most serious ones are potential use-after-free and NULL pointer dereferences at context initialization time. Both are due amdgpu_ctx_init() not holding the adev->pm.stable_pstate_ctx_lock, which is otherwise used from both sysfs and the context code itself for modifying and clearing the stored context pointer.
Second issue is that context fini can trample over the pstate configuration set via sysfs. This is due the restore state (ctx->stable_pstate) being saved at context init time, and not if, or when the context actually changes the pstate. As the context exits it will therefore incorrectly restore to what was set before the sysfs override was requested.
The simplest fix is to drastically simplify how the state is tracked, by clearly defining the points at which pstate ownership is taken and released, and to handle all transitions under the correct lock.
Instead of at context init time, the previous state is saved only at the point the context overrides the current state, and is restored on context exit only if the context is still the owner of the current override state.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 71 ++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 29 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +42 -29
@@ -326,7 +326,6 @@ static int amdgpu_ctx_init(struct amdgpu struct drm_file *filp, struct amdgpu_ctx *ctx) { struct amdgpu_fpriv *fpriv = filp->driver_priv; -u32 current_stable_pstate;int r; r =amdgpu_ctx_priority_permit (filp, priority);
@@ -344,36 +343,21 @@ static int amdgpu_ctx_init(struct amdgpu ctx->generation =amdgpu_vm_generation (mgr->adev, &fpriv->vm); ctx->init_priority = priority; ctx->override_priority =AMDGPU_CTX_PRIORITY_UNSET ; - - r =amdgpu_ctx_get_stable_pstate (ctx, ¤t_stable_pstate); -if (r) -return r; - -if (mgr->adev->pm.stable_pstate_ctx) - ctx->stable_pstate = mgr->adev->pm.stable_pstate_ctx->stable_pstate; -else - ctx->stable_pstate = current_stable_pstate; + ctx->stable_pstate =AMDGPU_CTX_STABLE_PSTATE_NONE ;return 0 ; } -static int amdgpu_ctx_set_stable_pstate (struct amdgpu_ctx *ctx, -u32 stable_pstate) +static int __amdgpu_ctx_set_stable_pstate (struct amdgpu_ctx *ctx, +u32 stable_pstate) {struct amdgpu_device *adev = ctx->mgr->adev;enum amd_dpm_forced_level level; +struct amdgpu_ctx *current_ctx;u32 current_stable_pstate; -int r; - -mutex_lock (&adev->pm.stable_pstate_ctx_lock); -if (adev->pm.stable_pstate_ctx && adev->pm.stable_pstate_ctx != ctx) { - r = -EBUSY ; - goto done; - } +int r =0 ; - r =amdgpu_ctx_get_stable_pstate (ctx, ¤t_stable_pstate); -if (r || (stable_pstate == current_stable_pstate)) - goto done; +lockdep_assert_held (&adev->pm.stable_pstate_ctx_lock);switch (stable_pstate) {case AMDGPU_CTX_STABLE_PSTATE_NONE :
@@ -392,17 +376,41 @@ static int amdgpu_ctx_set_stable_pstate( level =AMD_DPM_FORCED_LEVEL_PROFILE_PEAK ;break ;default : - r = -EINVAL ; - goto done; +return -EINVAL ; } + current_ctx = adev->pm.stable_pstate_ctx; +if (current_ctx && current_ctx != ctx) +return -EBUSY ; + + r =amdgpu_ctx_get_stable_pstate (ctx, ¤t_stable_pstate); +if (r || current_stable_pstate == stable_pstate) +return r; + r =amdgpu_dpm_force_performance_level (adev, level); +if (r) +return r; -if (level ==AMD_DPM_FORCED_LEVEL_AUTO ) - adev->pm.stable_pstate_ctx =NULL ; -else +if (!current_ctx) { adev->pm.stable_pstate_ctx = ctx; -done: +/* +* Serialized by context taking ownership for the first time +* while holding adev->pm.stable_pstate_ctx_lock). +*/ +WRITE_ONCE (ctx->stable_pstate, current_stable_pstate); + } + +return 0 ; +} + +static int amdgpu_ctx_set_stable_pstate (struct amdgpu_ctx *ctx, +u32 stable_pstate) +{ +struct amdgpu_device *adev = ctx->mgr->adev; +int r; + +mutex_lock (&adev->pm.stable_pstate_ctx_lock); + r =__amdgpu_ctx_set_stable_pstate (ctx, stable_pstate);mutex_unlock (&adev->pm.stable_pstate_ctx_lock);return r;
@@ -428,7 +436,12 @@ static void amdgpu_ctx_fini(struct kref }if (drm_dev_enter (adev_to_drm (adev), &idx)) { -amdgpu_ctx_set_stable_pstate (ctx, ctx->stable_pstate); +mutex_lock (&adev->pm.stable_pstate_ctx_lock); +if (adev->pm.stable_pstate_ctx == ctx) { +__amdgpu_ctx_set_stable_pstate (ctx, ctx->stable_pstate); + adev->pm.stable_pstate_ctx =NULL ; + } +mutex_unlock (&adev->pm.stable_pstate_ctx_lock);drm_dev_exit (idx); }
Greg Kroah-Hartman
maintainerPATCH 386/744 drm/amdgpu: validate CP_GFX_SHADOW chunk size in CS pass1
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit 84c4c36acd5c4b2558b5069f869a165b2c655c84 upstream.
Add a minimum-length check for the AMDGPU_CHUNK_ID_CP_GFX_SHADOW chunk in amdgpu_cs_pass1(), matching the gate already present for the IB, FENCE and BO_HANDLES chunk types.
The CP_GFX_SHADOW case previously shared a bare break with the dependency and syncobj chunk types, which do not dereference a fixed-size struct. When userspace submits this chunk with length_dw == 0, vmemdup_array_user() is called with size 0 and returns ZERO_SIZE_PTR, which passes the IS_ERR() check. amdgpu_cs_p2_shadow() then dereferences chunk->kdata as a struct drm_amdgpu_cs_chunk_cp_gfx_shadow (reading shadow->flags), faulting on the ZERO_SIZE_PTR and causing a NULL-pointer dereference.
This is reachable by an unprivileged process in the render group. Reject undersized chunks with -EINVAL during pass1 so the bad submission is rejected before pass2 ever dereferences the data.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +5 -1
@@ -252,13 +252,17 @@ static int amdgpu_cs_pass1(struct amdgpu goto free_partial_kdata;break ; +case AMDGPU_CHUNK_ID_CP_GFX_SHADOW : +if (size <sizeof (struct drm_amdgpu_cs_chunk_cp_gfx_shadow )) + goto free_partial_kdata; +break ; +case AMDGPU_CHUNK_ID_DEPENDENCIES :case AMDGPU_CHUNK_ID_SYNCOBJ_IN :case AMDGPU_CHUNK_ID_SYNCOBJ_OUT :case AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES :case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT :case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL : -case AMDGPU_CHUNK_ID_CP_GFX_SHADOW :break ;default :
Greg Kroah-Hartman
maintainerPATCH 387/744 drm/nouveau: fix reversed error cleanup order in ucopy functions
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
commit ab99ead646b1b833ecd57fe577a2816f2e848167 upstream.
nouveau_uvmm_vm_bind_ucopy() and nouveau_exec_ucopy() place their error cleanup labels in allocation order rather than reverse allocation order. On a u_memcpya() failure for in_sync.s, the goto to err_free_ops (or err_free_pushs) frees the first allocation and then falls through to err_free_ins, which calls u_free() on args->in_sync.s.
Since args->in_sync.s still holds the ERR_PTR returned by the failed u_memcpya(), and ERR_PTR values are not caught by ZERO_OR_NULL_PTR(), kvfree() proceeds to dereference it, which can result in a kernel oops. A failure for out_sync.s instead jumps to err_free_ins and skips freeing the first allocation, leading to a memory leak.
Fix by swapping the cleanup label order so resources are freed in the correct reverse allocation sequence.
--- drivers/gpu/drm/nouveau/nouveau_exec.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/nouveau/nouveau_exec.c +2 -2
@@ -331,10 +331,10 @@ nouveau_exec_ucopy(struct nouveau_exec_jreturn 0 ; -err_free_pushs: -u_free (args->push.s); err_free_ins:u_free (args->in_sync.s); +err_free_pushs: +u_free (args->push.s);return ret; }
drivers/gpu/drm/nouveau/nouveau_uvmm.c +2 -2
@@ -1779,10 +1779,10 @@ nouveau_uvmm_vm_bind_ucopy(struct nouveareturn 0 ; -err_free_ops: -u_free (args->op.s); err_free_ins:u_free (args->in_sync.s); +err_free_ops: +u_free (args->op.s);return ret; }
Greg Kroah-Hartman
maintainerPATCH 388/744 drm/sysfb: Avoid possible truncation with calculating visible size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit b771974988ec7ce077a7246fa0fa588c246fe581 upstream.
Calculating the visible size of the system framebuffer can result in truncation of the result. The calculation uses 32-bit arithmetics, which can overflow if the values for height and stride are large. Fix the issue by multiplying with mul_u32_u32().
--- drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c +2 -1
@@ -2,6 +2,7 @@#include <linux/export.h> #include <linux/limits.h> +#include <linux/math64.h> #include <linux/minmax.h> #include <linux/screen_info.h>
@@ -73,7 +74,7 @@ EXPORT_SYMBOL(drm_sysfb_get_stride_si);u64 drm_sysfb_get_visible_size_si (struct drm_device *dev,const struct screen_info *si,unsigned int height,unsigned int stride,u64 size) { -u64 vsize = height * stride; +u64 vsize =mul_u32_u32 (height, stride);return drm_sysfb_get_validated_size0 (dev,"visible size" , vsize, size); }
Greg Kroah-Hartman
maintainerPATCH 389/744 drm/sysfb: Return errno code from drm_sysfb_get_visible_size()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit 7bab0f09d753f098977bbba3955d694c2e2c25da upstream.
Change the return type of drm_sysfb_get_visible_size() to s64 so that it returns a possible errno code from _get_validated_size0(). Fix callers to handle the errno code.
The currently returned unsigned type converts an errno code to a very large size value, which drivers interpret as visible size of the system framebuffer. Later efforts to reserve the framebuffer resource fail.
The bug has been present since efidrm and vesadrm got merged. It was then part of each driver.
--- drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 2 +- drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c | 2 +- drivers/gpu/drm/sysfb/efidrm.c | 7 ++++--- drivers/gpu/drm/sysfb/vesadrm.c | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-)
drivers/gpu/drm/sysfb/drm_sysfb_helper.h +1 -1
@@ -50,7 +50,7 @@ struct resource *drm_sysfb_get_memory_siint drm_sysfb_get_stride_si (struct drm_device *dev,const struct screen_info *si,const struct drm_format_info *format,unsigned int width,unsigned int height,u64 size); -u64 drm_sysfb_get_visible_size_si (struct drm_device *dev,const struct screen_info *si, +s64 drm_sysfb_get_visible_size_si (struct drm_device *dev,const struct screen_info *si,unsigned int height,unsigned int stride,u64 size);#endif
drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c +1 -1
@@ -71,7 +71,7 @@ int drm_sysfb_get_stride_si(struct drm_d }EXPORT_SYMBOL (drm_sysfb_get_stride_si); -u64 drm_sysfb_get_visible_size_si (struct drm_device *dev,const struct screen_info *si, +s64 drm_sysfb_get_visible_size_si (struct drm_device *dev,const struct screen_info *si,unsigned int height,unsigned int stride,u64 size) {u64 vsize =mul_u32_u32 (height, stride);
drivers/gpu/drm/sysfb/efidrm.c +4 -3
@@ -150,7 +150,8 @@ static struct efidrm_device *efidrm_deviconst struct screen_info *si;const struct drm_format_info *format;int width, height, stride; -u64 vsize, mem_flags; +s64 vsize; +u64 mem_flags;struct resource resbuf;struct resource *res;struct efidrm_device *efi;
@@ -204,8 +205,8 @@ static struct efidrm_device *efidrm_deviif (stride <0 )return ERR_PTR (stride); vsize =drm_sysfb_get_visible_size_si (dev, si, height, stride,resource_size (res)); -if (!vsize) -return ERR_PTR (-EINVAL ); +if (vsize <0 ) +return ERR_PTR (vsize);drm_dbg (dev,"framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n" , &format->format, width, height, stride);
drivers/gpu/drm/sysfb/vesadrm.c +3 -3
@@ -400,7 +400,7 @@ static struct vesadrm_device *vesadrm_deconst struct screen_info *si;const struct drm_format_info *format;int width, height, stride; -u64 vsize; +s64 vsize;struct resource resbuf;struct resource *res;struct vesadrm_device *vesa;
@@ -455,8 +455,8 @@ static struct vesadrm_device *vesadrm_deif (stride <0 )return ERR_PTR (stride); vsize =drm_sysfb_get_visible_size_si (dev, si, height, stride,resource_size (res)); -if (!vsize) -return ERR_PTR (-EINVAL ); +if (vsize <0 ) +return ERR_PTR (vsize);drm_dbg (dev,"framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n" , &format->format, width, height, stride);
Greg Kroah-Hartman
maintainerPATCH 390/744 drm/amdgpu: Respect placement requirements in amdgpu_gtt_mgr functions
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit 8882f8897e554053af9e72f4c2da8b1e2cce56c7 upstream.
When testing intersection and compatibility, respect the actual placement requirements. This is a pre-requisite for ensuring that UVD CS BOs do not cross 256M segments.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | 30 ++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +28 -2
@@ -272,7 +272,20 @@ static bool amdgpu_gtt_mgr_intersects(st const struct ttm_place *place, size_t size) { -return !place->lpfn ||amdgpu_gtt_mgr_has_gart_addr (res); +const struct drm_mm_node *const node = &to_ttm_range_mgr_node (res)->mm_nodes[0 ]; +const u32 num_pages =PFN_UP (size); + +if (!place->lpfn) +return true; + +if (!amdgpu_gtt_mgr_has_gart_addr (res)) +return false; + +if (place->fpfn >= (node->start + num_pages) || + (place->lpfn && place->lpfn <= node->start)) +return false; + +return true; }/**
@@ -290,7 +303,20 @@ static bool amdgpu_gtt_mgr_compatible(st const struct ttm_place *place, size_t size) { -return !place->lpfn ||amdgpu_gtt_mgr_has_gart_addr (res); +const struct drm_mm_node *const node = &to_ttm_range_mgr_node (res)->mm_nodes[0 ]; +const u32 num_pages =PFN_UP (size); + +if (!place->lpfn) +return true; + +if (!amdgpu_gtt_mgr_has_gart_addr (res)) +return false; + +if (node->start < place->fpfn || + (place->lpfn && (node->start + num_pages) > place->lpfn)) +return false; + +return true; }/**
Greg Kroah-Hartman
maintainerPATCH 391/744 drm/amdkfd: Use exclusive bounds for SVM split alignment checks
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gerhard Schwanzer <[email protected]>
commit b89d58b6595d79dc3fe75e213e1f4c5efd0251d4 upstream.
SVM ranges use inclusive page indices: prange->last is the last page in the range. The split-remap logic introduced by commit 448ee45353ef ("drm/amdkfd: Use huge page size to check split svm range alignment") uses ALIGN_DOWN(prange->last, 512) to determine whether the original range can contain a 2MB huge-page mapping.
That aligns the last page itself down. Thus a range ending one page before the next 2MB boundary is classified as if the final 2MB block did not exist. When such a range is split inside that final block, the split head or tail can be left off the remap list even though it was derived from an original range that may have PMD mappings.
Use prange->last + 1 as the exclusive upper bound when computing the original range's last 2MB-aligned boundary. Then use the actual split boundary for the head and tail alignment checks: tail->start for a tail split, and new_start for a head split. new_start is equivalent to head->last + 1 and directly names the exclusive end of the split head.
Using head->last for the head-side check can both remap a head that ends exactly one page before a 2MB boundary and miss a head whose split boundary is one page after such a boundary. Philip Yang pointed out in the review of the original change that this condition should use head->last + 1 or new_start.
Xiaogang Chen identified the inclusive-last cause and posted the candidate fix in the regression thread. With the culprit change active and the local revert not applied, the unchanged C/HSA reproducer completes 10/10 runs with this change on an RX 7600 XT.
--- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_svm.c +4 -4
@@ -1144,7 +1144,7 @@ static int svm_range_split_tail(struct svm_range *prange, uint64_t new_last, struct list_head *insert_list, struct list_head *remap_list) { - unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long last_align_down = ALIGN_DOWN(prange->last + 1, 512);unsigned long start_align =ALIGN (prange->start,512 );bool huge_page_mapping = last_align_down > start_align;struct svm_range *tail =NULL ;
@@ -1168,7 +1168,7 @@ static int svm_range_split_head(struct svm_range *prange, uint64_t new_start, struct list_head *insert_list, struct list_head *remap_list) { - unsigned long last_align_down = ALIGN_DOWN(prange->last, 512); + unsigned long last_align_down = ALIGN_DOWN(prange->last + 1, 512);unsigned long start_align =ALIGN (prange->start,512 );bool huge_page_mapping = last_align_down > start_align;struct svm_range *head =NULL ;
@@ -1181,8 +1181,8 @@ svm_range_split_head(struct svm_range *plist_add (&head->list, insert_list); -if (huge_page_mapping && head->last +1 > start_align && - head->last +1 < last_align_down && (!IS_ALIGNED (head->last,512 ))) +if (huge_page_mapping && new_start > start_align && + new_start < last_align_down && !IS_ALIGNED (new_start,512 ))list_add (&head->update_list, remap_list);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 392/744 drm/displayid: fix Tiled Display Topology ID size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
commit 90c0486a82e27393f9eaf3bb350f51a0bd38cb6b upstream.
The Tiled Display Topology ID of a DisplayID Tiled Display Topology Data Block consists of three fields:
- Tiled Display Manufacturer/Vendor ID Field (3 bytes)
- Tiled Display Product ID Code Field (2 bytes)
- Tiled Display Serial Number Field (4 bytes)
i.e. a total of 9 bytes, not 8.
The DisplayID Tiled Display Topology ID is used as the tile group identifier.
Update both struct displayid_tiled_block topology_id member and struct drm_tile_group group_data member to full 9 bytes.
The group data was missing the last byte of the serial number. I don't know whether there are known bug reports that might be linked to this, but it's plausible the last byte could be the differentiating part for the tile groups, and fewer tile groups might have been created than intended.
--- drivers/gpu/drm/drm_connector.c | 12 ++++++------ drivers/gpu/drm/drm_displayid_internal.h | 2 +- include/drm/drm_connector.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-)
drivers/gpu/drm/drm_connector.c +6 -6
@@ -3576,7 +3576,7 @@ EXPORT_SYMBOL(drm_mode_put_tile_group);/** * drm_mode_get_tile_group - get a reference to an existing tile group * @dev: DRM device -* @topology: 8-bytes unique per monitor. +* @topology_id: 9-byte unique ID per monitor. * * Use the unique bytes to get a reference to an existing tile group. *
@@ -3584,14 +3584,14 @@ EXPORT_SYMBOL(drm_mode_put_tile_group);* tile group or NULL if not found. */ struct drm_tile_group *drm_mode_get_tile_group (struct drm_device *dev, -const char topology[8 ]) +const char topology_id[9 ]) {struct drm_tile_group *tg;int id;mutex_lock (&dev->mode_config.idr_mutex);idr_for_each_entry (&dev->mode_config.tile_idr, tg, id) { -if (!memcmp (tg->group_data, topology,8 )) { +if (!memcmp (tg->group_data, topology_id,sizeof (tg->group_data))) {if (!kref_get_unless_zero (&tg->refcount)) tg =NULL ;mutex_unlock (&dev->mode_config.idr_mutex);
@@ -3606,7 +3606,7 @@ EXPORT_SYMBOL(drm_mode_get_tile_group);/** * drm_mode_create_tile_group - create a tile group from a displayid description * @dev: DRM device -* @topology: 8-bytes unique per monitor. +* @topology_id: 9-byte unique ID per monitor. * * Create a tile group for the unique monitor, and get a unique * identifier for the tile group.
@@ -3615,7 +3615,7 @@ EXPORT_SYMBOL(drm_mode_get_tile_group);* new tile group or NULL. */ struct drm_tile_group *drm_mode_create_tile_group (struct drm_device *dev, -const char topology[8 ]) +const char topology_id[9 ]) {struct drm_tile_group *tg;int ret;
@@ -3625,7 +3625,7 @@ struct drm_tile_group *drm_mode_create_treturn NULL ;kref_init (&tg->refcount); -memcpy (tg->group_data, topology,8 ); +memcpy (tg->group_data, topology_id,sizeof (tg->group_data)); tg->dev = dev;mutex_lock (&dev->mode_config.idr_mutex);
drivers/gpu/drm/drm_displayid_internal.h +1 -1
@@ -109,7 +109,7 @@ struct displayid_tiled_block {u8 topo[3 ];u8 tile_size[4 ];u8 tile_pixel_bezel[5 ]; -u8 topology_id[8 ]; +u8 topology_id[9 ]; } __packed;struct displayid_detailed_timings_1 {
include/drm/drm_connector.h +3 -3
@@ -2608,13 +2608,13 @@ struct drm_tile_group {struct kref refcount;struct drm_device *dev;int id; -u8 group_data[8 ]; +u8 group_data[9 ]; };struct drm_tile_group *drm_mode_create_tile_group (struct drm_device *dev, -const char topology[8 ]); +const char topology_id[9 ]);struct drm_tile_group *drm_mode_get_tile_group (struct drm_device *dev, -const char topology[8 ]); +const char topology_id[9 ]);void drm_mode_put_tile_group (struct drm_device *dev,struct drm_tile_group *tg);
Greg Kroah-Hartman
maintainerPATCH 393/744 drm/i915/gem: Add missing nospec on parallel submit slot
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <[email protected]>
commit 914a76a9f08366434bf595700f62026b7a19a9cc upstream.
Add missing Spectre mitigation for userspace controlled parallel submission slot.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/gem/i915_gem_context.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/i915/gem/i915_gem_context.c +1 -0
@@ -613,6 +613,7 @@ set_proto_ctx_engines_parallel_submit(streturn -EINVAL ; } + slot =array_index_nospec (slot, set->num_engines);if (set->engines[slot].type !=I915_GEM_ENGINE_TYPE_INVALID ) {drm_dbg (&i915->drm,"Invalid placement[%d], already occupied\n" , slot);
Greg Kroah-Hartman
maintainerPATCH 394/744 drm/i915/mtl+: Enable PPS before PLL
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Imre Deak <[email protected]>
commit 062499cc4813b5a3cbed5dd4fbe0177265858450 upstream.
Enabling PPS after a display port's PLL is enabled leads to PLL / DDI BUF timeouts during system resuming after a long (> 45 mins) suspended state, at least on some ARL and MTL laptops, either all or some of them also containing an Nvidia GPU. Enabling PPS first and then the PLL fixes the problem for all the reporters.
A similar issue is seen when enabling an external DP output on PHY B (vs. PHY A in the above eDP cases), where this change will not have any effect (since no PPS is used in that case). There isn't any direct connection between PPS and PLL, so the fix for eDP works by some side-effect only. However Bspec does seem to require enabling PPS first, so let's do that. Further investigation continues on the actual root cause and a cure for external panels.
--- drivers/gpu/drm/i915/display/intel_ddi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/display/intel_ddi.c +8 -3
@@ -2652,9 +2652,6 @@ static void mtl_ddi_pre_enable_dp(struct/* 3. Select Thunderbolt */ mtl_port_buf_ctl_io_selection (encoder); -/* 4. Enable Panel Power if PPS is required */ -intel_pps_on (intel_dp); -/* 5. Enable the port PLL */ intel_ddi_enable_clock (encoder, crtc_state);
@@ -3710,6 +3707,14 @@ intel_ddi_pre_pll_enable(struct intel_atelse if (display->platform.geminilake || display->platform.broxton)bxt_dpio_phy_set_lane_optim_mask (encoder, crtc_state->lane_lat_optim_mask); + +/* +* There is no direct connection between the PLL and PPS, however +* enabling PPS before PLL is required to avoid PLL/DDI BUF timeouts +* during system resume. Do that matching the Bspec order as well. +*/ +if (DISPLAY_VER (display) >=14 ) +intel_pps_on (&dig_port->dp); }static void adlp_tbt_to_dp_alt_switch_wa (struct intel_encoder *encoder)
Greg Kroah-Hartman
maintainerPATCH 395/744 drm/nouveau/acr: fix missing nvkm_done() in error path of nvkm_acr_oneinit()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit c3027973f692077a1b66a9fb26d6a7c46c0dc72c upstream.
In nvkm_acr_oneinit(), nvkm_kmap(acr->wpr) is invoked unconditionally at line 309 to obtain a mapping reference. Additionally, when both acr->wpr_fw and acr->wpr_comp are present, a second nvkm_kmap() is called inside the conditional block. Both mappings are expected to be released by nvkm_done(acr->wpr) at line 320 before the function returns successfully.
However, when a mismatch is detected during the loop within the conditional block, the function returns -EINVAL at line 318 without calling nvkm_done(). This results in a leak of the kmap reference(s) acquired earlier.
Fix the issue by invoking nvkm_done(acr->wpr) prior to the early return to ensure proper release of the mapping references.
--- drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c +1 -0
@@ -315,6 +315,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *sub i, us, fw); } } +nvkm_done (acr->wpr);return -EINVAL ; }nvkm_done (acr->wpr);
Greg Kroah-Hartman
maintainerPATCH 396/744 drm/radeon: fix r100_copy_blit for large BOs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Ondračka <[email protected]>
commit f896e86273dbbebb5eac966b4a201b5c62a02e9a upstream.
r100_copy_blit() copies BOs as 1024-pixel-wide ARGB8888 blits, so one GPU page becomes one blit row. Large copies are split into chunks of at most 8191 rows.
The kernel register header names the packet coordinate dwords SRC_Y_X and DST_Y_X. In the BITBLT_MULTI description in R5xx_Acceleration_v1.5.pdf docs, these correspond to [SRC_X1 | SRC_Y1] and [DST_X1 | DST_Y1], which are signed 13-bit coordinates in the -8192..8191 range. The old code kept SRC/DST_PITCH_OFFSET at the BO base and used SRC_Y_X/DST_Y_X as the chunk address, so large BO moves could exceed that coordinate range.
Compute per-chunk SRC/DST_PITCH_OFFSET bases and emit zero source and destination coordinates. r100_copy_blit() already packs SRC/DST_PITCH_OFFSET as pitch plus base offset, so large chunk addresses belong there rather than in the coordinate fields.
This fixes Prison Architect corruption with 4096x4096 mipped textures after they are evicted to GTT under memory pressure on RV530.
--- drivers/gpu/drm/radeon/r100.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/gpu/drm/radeon/r100.c +9 -4
@@ -906,6 +906,7 @@ struct radeon_fence *r100_copy_blit(stru {struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX ];struct radeon_fence *fence; +uint64_t cur_src_offset, cur_dst_offset;uint32_t cur_pages;uint32_t stride_bytes =RADEON_GPU_PAGE_SIZE ;uint32_t pitch;
@@ -934,6 +935,10 @@ struct radeon_fence *r100_copy_blit(stru cur_pages =8191 ; } num_gpu_pages -= cur_pages; + cur_src_offset = src_offset + + (uint64_t )num_gpu_pages *RADEON_GPU_PAGE_SIZE ; + cur_dst_offset = dst_offset + + (uint64_t )num_gpu_pages *RADEON_GPU_PAGE_SIZE ;/* pages are in Y direction - height page width in X direction - width */
@@ -950,13 +955,13 @@ struct radeon_fence *r100_copy_blit(struRADEON_DP_SRC_SOURCE_MEMORY |RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); -radeon_ring_write (ring, (pitch <<22 ) | (src_offset >>10 )); -radeon_ring_write (ring, (pitch <<22 ) | (dst_offset >>10 )); +radeon_ring_write (ring, (pitch <<22 ) | (cur_src_offset >>10 )); +radeon_ring_write (ring, (pitch <<22 ) | (cur_dst_offset >>10 ));radeon_ring_write (ring, (0x1fff ) | (0x1fff <<16 ));radeon_ring_write (ring,0 );radeon_ring_write (ring, (0x1fff ) | (0x1fff <<16 )); -radeon_ring_write (ring, num_gpu_pages); -radeon_ring_write (ring, num_gpu_pages); +radeon_ring_write (ring,0 ); +radeon_ring_write (ring,0 );radeon_ring_write (ring, cur_pages | (stride_pixels <<16 )); }radeon_ring_write (ring,PACKET0 (RADEON_DSTCACHE_CTLSTAT ,0 ));
Greg Kroah-Hartman
maintainerPATCH 397/744 drm/xe/display: skip FORCE_WC and vm_bound check for external dma-bufs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Auld <[email protected]>
commit d472497265374e895e31cf2af8a2c5f650019889 upstream.
Currently, xe_display_bo_framebuffer_init() unconditionally attempts to apply XE_BO_FLAG_FORCE_WC to the buffer and rejects the FB creation with -EINVAL if the BO is already VM_BINDed.
However, for imported dma-bufs (ttm_bo_type_sg), this check doesn't seem to make much sense since CPU caching policy is entirely controlled by the exporter. Plus there is no place to set this flag, in the first place. Also this is not rejected if not yet vm_binded, but that seems arbitrary since setting or not setting FORCE_WC should a noop either way, at this stage, and whether it is currently VM_BINDed makes no difference.
Currently if we run an app and offload rendering to an external dGPU, like NV or another xe device, the dma-buf passed back to the compositor (igpu) will be an actual external import from xe pov, and it will be missing FORCE_WC, and if the compositor side did a VM_BIND before turning into it into an fb the whole thing gets rejected.
So it looks like we either need to reject outright, no matter what, or this usecase is valid and we need to loosen the restriction for sg buffers. Proposing here to loosen the restriction.
--- drivers/gpu/drm/xe/display/xe_display_bo.c | 3 ++- drivers/gpu/drm/xe/display/xe_fb_pin.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/display/xe_display_bo.c +2 -1
@@ -42,7 +42,8 @@ static int xe_display_bo_framebuffer_iniif (ret) goto err; -if (!(bo->flags &XE_BO_FLAG_FORCE_WC )) { +if (!(bo->flags &XE_BO_FLAG_FORCE_WC ) && + bo->ttm.type != ttm_bo_type_sg) {/* * XE_BO_FLAG_FORCE_WC should ideally be set at creation, or is * automatically set when creating FB. We cannot change caching
drivers/gpu/drm/xe/display/xe_fb_pin.c +2 -1
@@ -481,7 +481,8 @@ int intel_plane_pin_fb(struct intel_planreturn 0 ;/* We reject creating !SCANOUT fb's, so this is weird.. */ -drm_WARN_ON (bo->ttm.base.dev, !(bo->flags &XE_BO_FLAG_FORCE_WC )); +drm_WARN_ON (bo->ttm.base.dev, !(bo->flags &XE_BO_FLAG_FORCE_WC ) && + bo->ttm.type != ttm_bo_type_sg); vma =__xe_pin_fb_vma (intel_fb, &new_plane_state->view.gtt, alignment);
Greg Kroah-Hartman
maintainerPATCH 398/744 drm/xe: Return error on non-migratable faults requiring devmem
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit 136fb61ba8571076dc5d49350a0e6d002d740b74 upstream.
Non-migratable faults that require devmem incorrectly jump to the 'out' label, which squashes the error code intended to be returned to the upper layers. Fix this by returning -EACCES instead.
--- drivers/gpu/drm/xe/xe_svm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/gpu/drm/xe/xe_svm.c +2 -4
@@ -1255,10 +1255,8 @@ retry:xe_svm_range_fault_count_stats_incr (gt, range); -if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) { - err = -EACCES ; - goto out; - } +if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) +return -EACCES ;if (xe_svm_range_is_valid (range, tile, ctx.devmem_only, dpagemap)) {xe_svm_range_valid_fault_count_stats_incr (gt, range);
Greg Kroah-Hartman
maintainerPATCH 399/744 drm/xe/oa: Fix offset alignment for MERT WHITELIST_OA_MERT_MMIO_TRG
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ashutosh Dixit <[email protected]>
commit 959b5016e4646b55fd2fd0438932e4c4e9ce171f upstream.
'head' argument for WHITELIST_OA_MERT_MMIO_TRG was previously wrong (not multiple of 16). Fix this.
--- drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_reg_whitelist.c +1 -1
@@ -110,7 +110,7 @@ static const struct xe_rtp_entry_sr regi OAM_HEAD_POINTER(XE_OAM_SCMI_1_BASE_ADJ))#define WHITELIST_OA_MERT_MMIO_TRG \ - WHITELIST_OA_MMIO_TRG(OAMERT_MMIO_TRG, OAMERT_STATUS, OAMERT_HEAD_POINTER) + WHITELIST_OA_MMIO_TRG(OAMERT_MMIO_TRG, OAMERT_STATUS, OAMERT_TAIL_POINTER) {XE_RTP_NAME ("oag_mmio_trg_rcs" ), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, XE_RTP_END_VERSION_UNDEFINED),
Greg Kroah-Hartman
maintainerPATCH 400/744 drm/xe/rtp: Add RING_FORCE_TO_NONPRIV_DENY to OA whitelists
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ashutosh Dixit <[email protected]>
commit e70086a3a06d276b4a5d9a2c51c9330c6cf72780 upstream.
Unconditionally whitelisting OA registers is a security violation. Set RING_FORCE_TO_NONPRIV_DENY bit in OA nonpriv slots, so that OA registers don't get whitelisted by default after probe, gt reset, resume and engine reset.
--- drivers/gpu/drm/xe/xe_reg_whitelist.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/gpu/drm/xe/xe_reg_whitelist.c +5 -3
@@ -90,10 +90,12 @@ static const struct xe_rtp_entry_sr regi RING_FORCE_TO_NONPRIV_ACCESS_RW)) }, +#define WHITELIST_DENY (r, f) WHITELIST(r, (f) | RING_FORCE_TO_NONPRIV_DENY) +#define WHITELIST_OA_MMIO_TRG (trg, status, head) \ - WHITELIST(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \ - WHITELIST(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \ - WHITELIST(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4) + WHITELIST_DENY(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \ + WHITELIST_DENY(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \ + WHITELIST_DENY(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4)#define WHITELIST_OAG_MMIO_TRG \ WHITELIST_OA_MMIO_TRG(OAG_MMIOTRIGGER, OAG_OASTATUS, OAG_OAHEADPTR)
Greg Kroah-Hartman
maintainerPATCH 401/744 drm/xe: Fix PTE index in xe_vm_populate_pgtable() for chunked binds
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit 34a4dd45cf210c04fee773b0dbc350aec285f03c upstream.
xe_vm_populate_pgtable() indexed the source PTE array (update->pt_entries) by the per-call loop counter, assuming each call starts at the first entry of the update. That holds for the CPU bind path (xe_migrate_update_pgtables_cpu), which populates a whole update in a single call, but not for the GPU bind path: write_pgtable() splits an update into MAX_PTE_PER_SDI (510) sized MI_STORE_DATA_IMM chunks, invoking the populate callback once per chunk with an advancing qword_ofs but a fresh command- buffer destination pointer.
As a result, every chunk after the first re-read pt_entries from index 0 instead of from its true offset, so PTEs beyond the first 510 entries of a single update were programmed with the wrong physical pages, shifting the mapping by exactly MAX_PTE_PER_SDI pages.
This stayed latent because a single update only exceeds 510 qwords when a large (e.g. 2M) region is bound as individual 4K PTEs rather than a single huge-page entry, which happens when the backing store is sufficiently fragmented. It was surfaced by the BO defrag path, which deliberately rebinds such fragmented ranges via the GPU bind path, producing deterministic data corruption offset by 510 pages.
Index pt_entries by the chunk's absolute offset relative to update->ofs so both the CPU and GPU paths pick the correct entries.
--- drivers/gpu/drm/xe/xe_pt.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_pt.c +12 -2
@@ -1025,12 +1025,22 @@ xe_vm_populate_pgtable(struct xe_migrateu64 *ptr = data;u32 i; +/* +* @qword_ofs is the absolute entry offset within the page table, while +* @ptes is indexed relative to @update->ofs (its first entry). The GPU +* path (write_pgtable) splits a single update into MAX_PTE_PER_SDI-sized +* chunks, calling this with an advancing @qword_ofs but a fresh @data +* pointer per chunk, so translate back into a @ptes index rather than +* assuming the chunk starts at ptes[0]. +*/ for (i =0 ; i < num_qwords; i++) { +u32 idx = qword_ofs - update->ofs + i; +if (map)xe_map_wr (tile_to_xe (tile), map, (qword_ofs + i) * -sizeof (u64), u64, ptes[i].pte); +sizeof (u64), u64, ptes[idx].pte);else - ptr[i] = ptes[i].pte; + ptr[i] = ptes[idx].pte; } }
Greg Kroah-Hartman
maintainerPATCH 402/744 drm/xe: Hold a dma-buf reference for imported BOs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nitin Gote <[email protected]>
commit 62775525a27c3b0d56382e08ba81ee2d322058b6 upstream.
An imported dma-buf BO is created as a ttm_bo_type_sg BO whose reservation object is the exporter's dma_buf->resv. The importer, however, only takes a dma-buf reference after a successful dma_buf_dynamic_attach(). Until then nothing keeps the exporter alive, so if the exporter is freed while the BO still references its resv, a later access to that resv is a use-after-free:
Oops: general protection fault, probably for non-canonical address
0x6b6b6b6b6b6b6b9c
Workqueue: ttm ttm_bo_delayed_delete [ttm]
RIP: 0010:mutex_can_spin_on_owner+0x3f/0xc0This can be reached on two paths:
- dma_buf_dynamic_attach() fails, or
- ttm_bo_init_reserved() fails during BO creation.
In both cases the BO already has bo->base.resv pointing at the exporter resv, and sg BOs are always torn down via ttm_bo_delayed_delete(), which locks bo->base.resv asynchronously - potentially after the exporter has been freed.
Take the dma-buf reference in xe_bo_init_locked(), before ttm_bo_init_reserved(), so it also covers a creation failure there, and release it in xe_ttm_bo_destroy(). The reference is held for the whole BO lifetime, keeping the shared resv alive on every path.
v2:
- Reworked the fix to avoid creating the imported sg BO before dma_buf_dynamic_attach() succeeds.
- Attach with importer_priv == NULL and make invalidate_mappings ignore incomplete imports.
v3:
- Dropped the xe-side reordering approach since importer_priv must be valid when dma_buf_dynamic_attach() publishes the attachment.
- Per Christian's suggestion on the v1 thread, keyed the check on import_attach rather than removing the sg guard entirely.
- Fixes both xe and amdgpu in a single TTM patch.
v4:
- Moved import_attach check to after dma_resv_copy_fences() so fences are copied before returning for successful imports (Thomas).
- Removed exporter-alive claim from commit message (Thomas).
v5:
- Add drm/xe patch to keep imported sg BOs off the LRU before attach succeeds; the TTM fix alone is not sufficient for xe if the BO is already LRU-visible. (Thomas)
v4 patch:
https://patchwork.freedesktop.org/patch/736663/?series=169129&rev=2
- Patch 1 (drm/ttm) carries Christian's Reviewed-by from v4.
v6:
- Reworked the fix based on Thomas' suggestion. Instead of the TTM resv individualization (v1-v5) plus the xe off-LRU/placement handling (v5), just hold a dma-buf reference for the imported BO lifetime so the shared resv can never be freed while the BO still references it. Single xe patch, no TTM change. (Thomas)
- Take the reference in xe_bo_init_locked() before ttm_bo_init_reserved() so a TTM creation failure is covered too (Thomas).
- Dropped the v5 series (drm/ttm + drm/xe off-LRU); the off-LRU approach also regressed in CI BAT via ttm_bo_pipeline_gutting() creating a ghost BO that outlived the exporter.
Link to v5: https://patchwork.freedesktop.org/series/169984/
v7:
- Move changelog above --- so it stays in the commit message.
- Reorder changelog entries oldest-to-newest. (Thomas)
--- drivers/gpu/drm/xe/xe_bo.c | 24 ++++++++++++++++++++---- drivers/gpu/drm/xe/xe_bo.h | 3 ++- drivers/gpu/drm/xe/xe_bo_types.h | 2 ++ drivers/gpu/drm/xe/xe_dma_buf.c | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +20 -4
@@ -1368,7 +1368,7 @@ int xe_bo_notifier_prepare_pinned(struct backup =xe_bo_init_locked (xe,NULL ,NULL , bo->ttm.base.resv,NULL ,xe_bo_size (bo),DRM_XE_GEM_CPU_CACHING_WB , ttm_bo_type_kernel,XE_BO_FLAG_SYSTEM |XE_BO_FLAG_NEEDS_CPU_ACCESS | -XE_BO_FLAG_PINNED , &exec); +XE_BO_FLAG_PINNED ,NULL , &exec);if (IS_ERR (backup)) {drm_exec_retry_on_contention (&exec); ret =PTR_ERR (backup);
@@ -1509,7 +1509,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)xe_bo_size (bo),DRM_XE_GEM_CPU_CACHING_WB , ttm_bo_type_kernel,XE_BO_FLAG_SYSTEM |XE_BO_FLAG_NEEDS_CPU_ACCESS | - XE_BO_FLAG_PINNED, &exec); + XE_BO_FLAG_PINNED, NULL, &exec);if (IS_ERR (backup)) {drm_exec_retry_on_contention (&exec); ret =PTR_ERR (backup);
@@ -1845,6 +1845,8 @@ static void xe_ttm_bo_destroy(struct ttmif (bo->ttm.base.import_attach)drm_prime_gem_destroy (&bo->ttm.base,NULL ); +if (bo->dma_buf) +dma_buf_put (bo->dma_buf);drm_gem_object_release (&bo->ttm.base);xe_assert (xe,list_empty (&ttm_bo->base.gpuva.list));
@@ -2302,6 +2304,8 @@ void xe_bo_free(struct xe_bo *bo)* @cpu_caching: The cpu caching used for system memory backing store. * @type: The TTM buffer object type. * @flags: XE_BO_FLAG_ flags. +* @dma_buf: The dma-buf to reference for the BO lifetime (imported BOs), +* or NULL. * @exec: The drm_exec transaction to use for exhaustive eviction. * * Initialize or create an xe buffer object. On failure, any allocated buffer
@@ -2313,7 +2317,8 @@ struct xe_bo *xe_bo_init_locked(struct x struct xe_tile *tile, struct dma_resv *resv, struct ttm_lru_bulk_move *bulk, size_t size, u16 cpu_caching, enum ttm_bo_type type, - u32 flags, struct drm_exec *exec) + u32 flags, struct dma_buf *dma_buf, + struct drm_exec *exec) { struct ttm_operation_ctx ctx = { .interruptible = true,
@@ -2402,6 +2407,17 @@ struct xe_bo *xe_bo_init_locked(struct x placement = (type == ttm_bo_type_sg || bo->flags &XE_BO_FLAG_DEFER_BACKING ) ? &sys_placement : &bo->placement; + +/* +* For imported BOs, keep the exporter dma-buf alive for the BO +* lifetime. Taken before ttm_bo_init_reserved() to also cover a +* creation failure there. Released in xe_ttm_bo_destroy(). +*/ +if (dma_buf) { +get_dma_buf (dma_buf); + bo->dma_buf = dma_buf; + } + err =ttm_bo_init_reserved (&xe->ttm, &bo->ttm, type, placement, alignment, &ctx,NULL , resv, xe_ttm_bo_destroy);
@@ -2519,7 +2535,7 @@ __xe_bo_create_locked(struct xe_device * vm && !xe_vm_in_fault_mode (vm) && flags &XE_BO_FLAG_USER ? &vm->lru_bulk_move :NULL , size, - cpu_caching, type, flags, exec); + cpu_caching, type, flags, NULL, exec);if (IS_ERR (bo))return bo;
drivers/gpu/drm/xe/xe_bo.h +2 -1
@@ -118,7 +118,8 @@ struct xe_bo *xe_bo_init_locked(struct x struct xe_tile *tile, struct dma_resv *resv, struct ttm_lru_bulk_move *bulk, size_t size, u16 cpu_caching, enum ttm_bo_type type, - u32 flags, struct drm_exec *exec); + u32 flags, struct dma_buf *dma_buf, + struct drm_exec *exec); struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile, struct xe_vm *vm, size_t size, enum ttm_bo_type type, u32 flags,
drivers/gpu/drm/xe/xe_bo_types.h +2 -0
@@ -36,6 +36,8 @@ struct xe_bo {struct xe_bo *backup_obj;/** @parent_obj: Ref to parent bo if this a backup_obj */ struct xe_bo *parent_obj; +/** @dma_buf: Imported dma-buf ref to keep its resv alive. */ +struct dma_buf *dma_buf;/** @flags: flags for this buffer object */ u32 flags;/** @vm: VM this BO is attached to, for extobj this will be NULL */
drivers/gpu/drm/xe/xe_dma_buf.c +1 -1
@@ -302,7 +302,7 @@ xe_dma_buf_create_obj(struct drm_device bo =xe_bo_init_locked (xe,NULL ,NULL , resv,NULL , dma_buf->size,0 ,/* Will require 1way or 2way for vm_bind */ - ttm_bo_type_sg,XE_BO_FLAG_SYSTEM , &exec); + ttm_bo_type_sg,XE_BO_FLAG_SYSTEM , dma_buf, &exec);drm_exec_retry_on_contention (&exec);if (IS_ERR (bo)) { ret =PTR_ERR (bo);
Greg Kroah-Hartman
maintainerPATCH 403/744 drm/xe/vm: Fix BO prefetch with CONSULT_MEM_ADVISE_PREF_LOC
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Himal Prasad Ghimiray <[email protected]>
commit 7bc597ce74bab4153b2009c92eccf889e9d74044 upstream.
When prefetch region is DRM_XE_CONSULT_MEM_ADVISE_PREF_LOC for a BO VMA, the code used it as an index into region_to_mem_type[], causing an out-of-bounds access since the value is -1.
Resolve the preferred location for BO VMAs directly: local VRAM on dGFX (using the BO's tile placement) or system memory on iGPU.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
v2:
-Fix null dereference
--- drivers/gpu/drm/xe/xe_vm.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
drivers/gpu/drm/xe/xe_vm.c +20 -5
@@ -3256,11 +3256,26 @@ static int op_lock_and_prep(struct drm_e .request_decompress = false, .check_purged = true, }); -if (!err && !xe_vma_has_no_bo (vma)) - err =xe_bo_migrate (xe_vma_bo (vma), - region_to_mem_type[region], -NULL , - exec); +if (!err && !xe_vma_has_no_bo (vma)) { +struct xe_bo *bo =xe_vma_bo (vma); +u32 mem_type; + +if (region ==DRM_XE_CONSULT_MEM_ADVISE_PREF_LOC ) { +unsigned int i; + + mem_type =XE_PL_TT ; +for (i =0 ; i < bo->placement.num_placement; i++) { +if (mem_type_is_vram (bo->placements[i].mem_type)) { + mem_type = bo->placements[i].mem_type; +break ; + } + } + }else { + mem_type = region_to_mem_type[region]; + } + + err =xe_bo_migrate (bo, mem_type,NULL , exec); + }break ; }default :
Greg Kroah-Hartman
maintainerPATCH 404/744 drm/xe/pt: Reset current_op in xe_pt_update_ops_init()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zongyao Bai <[email protected]>
commit 6384271ac1ac0099198d15df79212a19ebdb929d upstream.
xe_pt_update_ops_init() fails to reset current_op to 0. On the vm_bind path, ops_execute() calls xe_pt_update_ops_prepare() inside the xe_validation_guard() / drm_exec_until_all_locked() loop. When that loop retries due to lock contention or OOM eviction (drm_exec_retry_on_contention() / xe_validation_retry_on_oom()), xe_pt_update_ops_prepare() runs again on the same vops, and each call to bind_op_prepare() increments current_op without resetting it.
After N retries current_op exceeds the array size allocated by xe_vma_ops_alloc(), causing an out-of-bounds write into SLUB-poisoned memory and a subsequent UAF crash in xe_migrate_update_pgtables_cpu() when reading the corrupted pt_op->bind.
Also reset needs_svm_lock and needs_invalidation which are derived in the same prepare pass and would otherwise cause wrong migrate ops selection and redundant TLB invalidation on retry.
Fix this by resetting current_op, needs_svm_lock and needs_invalidation in xe_pt_update_ops_init().
v2 (Matt):
- Add details in commit message.
- Add Fixes tag and Cc to [email protected]
--- drivers/gpu/drm/xe/xe_pt.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/xe/xe_pt.c +3 -0
@@ -2364,8 +2364,11 @@ static void xe_pt_update_ops_init(struct xe_vm_pgtable_update_ops *pt_update_ops) {init_llist_head (&pt_update_ops->deferred); + pt_update_ops->current_op =0 ; pt_update_ops->start = ~0x0ull ; pt_update_ops->last =0x0ull ; + pt_update_ops->needs_svm_lock = false; + pt_update_ops->needs_invalidation = false;xe_page_reclaim_list_init (&pt_update_ops->prl); }
Greg Kroah-Hartman
maintainerPATCH 405/744 drm/xe/nvm: fix writable override for CRI
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Usyskin <[email protected]>
commit c473761f8178760b915633332908409c73bfdb9e upstream.
The witable override should be set when FDO_MODE bit is enabled. Fix the comparison to distingush this case from legacy systems where bit should be disabled to have override.
--- drivers/gpu/drm/xe/xe_nvm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_nvm.c +7 -2
@@ -60,35 +60,40 @@ static bool xe_nvm_writable_override(struct xe_device *xe)struct xe_mmio *mmio =xe_root_tile_mmio (xe);bool writable_override;struct xe_reg reg; -u32 test_bit; +u32 test_bit, test_val;switch (xe->info.platform) {case XE_CRESCENTISLAND : reg =PCODE_SCRATCH (0 ); test_bit =FDO_MODE ; + test_val =FDO_MODE ;break ;case XE_BATTLEMAGE : reg =HECI_FWSTS2 (DG2_GSC_HECI2_BASE ); test_bit =HECI_FW_STATUS_2_NVM_ACCESS_MODE ; + test_val =0 ;break ;case XE_PVC : reg =HECI_FWSTS2 (PVC_GSC_HECI2_BASE ); test_bit =HECI_FW_STATUS_2_NVM_ACCESS_MODE ; + test_val =0 ;break ;case XE_DG2 : reg =HECI_FWSTS2 (DG2_GSC_HECI2_BASE ); test_bit =HECI_FW_STATUS_2_NVM_ACCESS_MODE ; + test_val =0 ;break ;case XE_DG1 : reg =HECI_FWSTS2 (DG1_GSC_HECI2_BASE ); test_bit =HECI_FW_STATUS_2_NVM_ACCESS_MODE ; + test_val =0 ;break ;default :drm_err (&xe->drm,"Unknown platform\n" );return true; } - writable_override = !(xe_mmio_read32 (mmio, reg) & test_bit); + writable_override = (xe_mmio_read32 (mmio, reg) & test_bit) == test_val;if (writable_override)drm_info (&xe->drm,"NVM access overridden by jumper\n" );return writable_override;
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 406/744 drm/xe/madvise: Skip invalidation for purgeable state updates
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arvind Yadav <[email protected]>
commit 57441577bac3637473da2c9644336eaa0ac5732f upstream.
Purgeable state updates only change VMA/BO metadata. They do not zap PTEs when switching between DONTNEED and WILLNEED. PTEs are zapped later if the BO is actually purged.
xe_vm_invalidate_madvise_range() waits on the VM dma-resv before checking vma->skip_invalidation. Since purgeable madvise marks all affected VMAs to skip invalidation, this wait is unnecessary and can stall on unrelated in-flight work.
Skip the invalidate path entirely for purgeable state updates.
v2:
- Replace inline 'args->type != DRM_XE_VMA_ATTR_PURGEABLE_STATE' check with a small helper madvise_range_needs_invalidation(). (Himal)
--- drivers/gpu/drm/xe/xe_vm_madvise.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_vm_madvise.c +17 -2
@@ -332,6 +332,20 @@ static int xe_vm_invalidate_madvise_rangreturn err; } +/** +* madvise_range_needs_invalidation() - Check whether madvise needs invalidation +* @args: madvise ioctl arguments +* +* Purgeable state updates only touch VMA/BO metadata. PTEs stay valid and are +* zapped only if the BO is later purged. +* +* Return: true when the update needs PTE invalidation. +*/ +static bool madvise_range_needs_invalidation (const struct drm_xe_madvise *args) +{ +return args->type !=DRM_XE_VMA_ATTR_PURGEABLE_STATE ; +} +static bool madvise_args_are_sane (struct xe_device *xe,const struct drm_xe_madvise *args) {if (XE_IOCTL_DBG (xe, !args))
@@ -708,8 +722,9 @@ int xe_vm_madvise_ioctl(struct drm_devic madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args, &details); - err =xe_vm_invalidate_madvise_range (vm, madvise_range.addr, - madvise_range.addr + args->range); +if (madvise_range_needs_invalidation (args)) + err =xe_vm_invalidate_madvise_range (vm, madvise_range.addr, + madvise_range.addr + args->range);if (madvise_range.has_svm_userptr_vmas)xe_svm_notifier_unlock (vm);
Greg Kroah-Hartman
maintainerPATCH 407/744 drm/imagination: Fix double call to drm_sched_entity_fini()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brajesh Gupta <[email protected]>
commit 4af24c27a39ba147a613a09e10b9e0f7294524c0 upstream.
Call sequence of double call:pvr_context_destroy
pvr_context_kill_queues
pvr_queue_kill
drm_sched_entity_destroy
drm_sched_entity_fini // here
pvr_context_put
kref_put(..., pvr_context_release)
pvr_context_destroy_queues
pvr_queue_destroy
drm_sched_entity_fini // here
Call to drm_sched_entity_destroy() from pvr_context_kill_queues() calls drm_sched_entity_flush() + drm_sched_entity_fini(). drm_sched_entity_flush() ensures all pending jobs are completed and drm_sched_entity_fini() ensures no further submission is allowed as per expectation from pvr_context_kill_queues(). Double call to drm_sched_entity_fini() is misuse of the API so keep call only in pvr_context_create() failure path.
Stack trace for issue with addition of refcounting for DRM entity stats in commit fd177135f0e6 ("drm/sched: Account entity GPU time"):
[ 789.490527] ------------[ cut here ]------------ [ 789.490559] refcount_t: underflow; use-after-free. [ 789.490657] WARNING: lib/refcount.c:28 at refcount_warn_saturate+0xf4/0x144, CPU#0: kworker/u16:1/440 [ 789.490695] Modules linked in: powervr drm_gpuvm drm_exec gpu_sched drm_shmem_helper xhci_plat_hcd xhci_hcd dwc3 usbcore usb_common snd_soc_simple_card snd_soc_simple_card_utils sa2ul sha512 sha256 dwc3_am62 sha1 authenc rti_wdt libsha512 at24 sch_fq_codel fuse dm_mod ipv6 [ 789.490798] CPU: 0 UID: 0 PID: 440 Comm: kworker/u16:1 Not tainted 7.0.0-rc7-02049-g5e2c0700091b #22 PREEMPT [ 789.490809] Hardware name: Texas Instruments AM625 SK (DT) [ 789.490815] Workqueue: powervr-sched pvr_queue_fence_release_work [powervr] [ 789.490868] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 789.490876] pc : refcount_warn_saturate+0xf4/0x144 [ 789.490884] lr : refcount_warn_saturate+0xf4/0x144 [ 789.490892] sp : ffff8000822cbcc0 [ 789.490895] x29: ffff8000822cbcc0 x28: 0000000000000000 x27: 0000000000000000 [ 789.490909] x26: 0000000000000000 x25: ffff800081b1e338 x24: ffff000004541405 [ 789.490922] x23: ffff000004bea950 x22: ffff00000042e400 x21: ffff000007123e30 [ 789.490935] x20: ffff000007123000 x19: ffff000007a80d50 x18: fffffffffffe7768 [ 789.490948] x17: 74736574202c6e6f x16: 697461746e656d65 x15: ffff800081b269f0 [ 789.490962] x14: 0000000000000030 x13: ffff800081b26a70 x12: 0000000000000211 [ 789.490975] x11: 00000000000000c0 x10: 0000000000000b50 x9 : ffff8000822cbb30 [ 789.490988] x8 : ffff0000014e7bb0 x7 : ffff00007725e780 x6 : 0000000372a05f49 [ 789.491001] x5 : 0000000000000000 x4 : 0000000000000001 x3 : 0000000000000010 [ 789.491013] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0000014e7000 [ 789.491027] Call trace: [ 789.491032] refcount_warn_saturate+0xf4/0x144 (P) [ 789.491043] drm_sched_entity_fini+0x164/0x18c [gpu_sched] [ 789.491081] pvr_queue_destroy+0x64/0x134 [powervr] [ 789.491110] pvr_context_destroy_queues+0x34/0x64 [powervr] [ 789.491138] pvr_context_release+0x70/0xac [powervr] [ 789.491166] pvr_context_put.part.0+0x5c/0x7c [powervr] [ 789.491193] pvr_context_put+0x14/0x24 [powervr] [ 789.491221] pvr_queue_fence_release_work+0x20/0x38 [powervr] [ 789.491249] process_one_work+0x160/0x4c4 [ 789.491264] worker_thread+0x188/0x310 [ 789.491276] kthread+0x130/0x13c [ 789.491287] ret_from_fork+0x10/0x20 [ 789.491300] ---[ end trace 0000000000000000 ]---
--- drivers/gpu/drm/imagination/pvr_context.c | 18 ++++++++++-------- drivers/gpu/drm/imagination/pvr_queue.c | 6 ++++-- drivers/gpu/drm/imagination/pvr_queue.h | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-)
drivers/gpu/drm/imagination/pvr_context.c +10 -8
@@ -161,22 +161,24 @@ ctx_fw_data_init(void *cpu_ptr, void *pr/** * pvr_context_destroy_queues() - Destroy all queues attached to a context. * @ctx: Context to destroy queues on. +* @cleanup_queue_entity: Whether to cleanup the queue entity e.g. context +* creation failure path. * * Should be called when the last reference to a context object is dropped. * It releases all resources attached to the queues bound to this context. */ -static void pvr_context_destroy_queues (struct pvr_context *ctx) +static void pvr_context_destroy_queues (struct pvr_context *ctx,bool cleanup_queue_entity) {switch (ctx->type) {case DRM_PVR_CTX_TYPE_RENDER : -pvr_queue_destroy (ctx->queues.fragment); -pvr_queue_destroy (ctx->queues.geometry); +pvr_queue_destroy (ctx->queues.fragment, cleanup_queue_entity); +pvr_queue_destroy (ctx->queues.geometry, cleanup_queue_entity);break ;case DRM_PVR_CTX_TYPE_COMPUTE : -pvr_queue_destroy (ctx->queues.compute); +pvr_queue_destroy (ctx->queues.compute, cleanup_queue_entity);break ;case DRM_PVR_CTX_TYPE_TRANSFER_FRAG : -pvr_queue_destroy (ctx->queues.transfer); +pvr_queue_destroy (ctx->queues.transfer, cleanup_queue_entity);break ; } }
@@ -240,7 +242,7 @@ static int pvr_context_create_queues(strreturn -EINVAL ; err_destroy_queues: -pvr_context_destroy_queues (ctx); +pvr_context_destroy_queues (ctx, true);return err; }
@@ -356,7 +358,7 @@ err_destroy_fw_obj:pvr_fw_object_destroy (ctx->fw_obj); err_destroy_queues: -pvr_context_destroy_queues (ctx); +pvr_context_destroy_queues (ctx, true); err_free_ctx_data:kfree (ctx->data);
@@ -382,7 +384,7 @@ pvr_context_release(struct kref *ref_couspin_unlock (&pvr_dev->ctx_list_lock);xa_erase (&pvr_dev->ctx_ids, ctx->ctx_id); -pvr_context_destroy_queues (ctx); +pvr_context_destroy_queues (ctx, false);pvr_fw_object_destroy (ctx->fw_obj);kfree (ctx->data);pvr_vm_context_put (ctx->vm_ctx);
drivers/gpu/drm/imagination/pvr_queue.c +4 -2
@@ -1401,11 +1401,12 @@ void pvr_queue_kill(struct pvr_queue *qu/** * pvr_queue_destroy() - Destroy a queue. * @queue: The queue to destroy. +* @cleanup_queue_entity: Whether to cleanup the queue entity. * * Cleanup the queue and free the resources attached to it. Should be * called from the context release function. */ -void pvr_queue_destroy (struct pvr_queue *queue) +void pvr_queue_destroy (struct pvr_queue *queue,bool cleanup_queue_entity) {if (!queue)return ;
@@ -1415,7 +1416,8 @@ void pvr_queue_destroy(struct pvr_queuemutex_unlock (&queue->ctx->pvr_dev->queues.lock);drm_sched_fini (&queue->scheduler); -drm_sched_entity_fini (&queue->entity); +if (cleanup_queue_entity) +drm_sched_entity_fini (&queue->entity);if (WARN_ON (queue->last_queued_job_scheduled_fence))dma_fence_put (queue->last_queued_job_scheduled_fence);
drivers/gpu/drm/imagination/pvr_queue.h +1 -1
@@ -158,7 +158,7 @@ struct pvr_queue *pvr_queue_create(strucvoid pvr_queue_kill (struct pvr_queue *queue); -void pvr_queue_destroy (struct pvr_queue *queue); +void pvr_queue_destroy (struct pvr_queue *queue,bool cleanup_queue_entity);void pvr_queue_process (struct pvr_queue *queue);
Greg Kroah-Hartman
maintainerPATCH 408/744 drm/imagination: Fix user array stride in pvr_set_uobj_array()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuvam Pandey <[email protected]>
commit 8dc8f3f4c2382fb7d1b1986ba8f33a2466cd3d7a upstream.
pvr_set_uobj_array() copies an array of kernel objects to a userspace array whose element size is described by out->stride. When out->stride is different from the kernel object size, the slow path advances the userspace pointer by the kernel object size and the kernel pointer by the userspace stride.
This reverses the intended layout. For larger userspace strides, later copies read from the wrong kernel addresses. For smaller userspace strides, later copies are written at the wrong userspace offsets. The padding clear is also done only for the first element instead of the padding area for each element.
Advance the userspace pointer by out->stride and the kernel pointer by obj_size, and clear per-element padding while the current userspace pointer is still available.
--- drivers/gpu/drm/imagination/pvr_drv.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
drivers/gpu/drm/imagination/pvr_drv.c +6 -7
@@ -1254,14 +1254,13 @@ pvr_set_uobj_array(const struct drm_pvr_if (copy_to_user (out_ptr, in_ptr, cpy_elem_size))return -EFAULT ; - out_ptr += obj_size; - in_ptr += out->stride; - } +if (out->stride > obj_size && +clear_user (out_ptr + cpy_elem_size, out->stride - obj_size)) { +return -EFAULT ; + } -if (out->stride > obj_size && -clear_user (u64_to_user_ptr (out->array + obj_size), - out->stride - obj_size)) { -return -EFAULT ; + out_ptr += out->stride; + in_ptr += obj_size; } }
Greg Kroah-Hartman
maintainerPATCH 409/744 drm/imagination: fix error checking of pvr_vm_context_lookup()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luigi Santivetti <[email protected]>
commit cf385cf6e713eba0720651174dac0b2d2f5bb8f8 upstream.
Since pvr_vm_context_lookup() returns either NULL or a pointer, then stop using IS_ERR() for checking the return value.
Using IS_ERR() leads to the kernel oops reported below. It can be reproduced by passing an invalid VM context handle from userspace to the DRM_IOCTL_PVR_CREATE_CONTEXT ioctl.
[ 92.733119] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000148 [ 92.742042] Mem abort info: [ 92.744890] ESR = 0x0000000096000004 [ 92.748686] EC = 0x25: DABT (current EL), IL = 32 bits [ 92.754020] SET = 0, FnV = 0 [ 92.757154] EA = 0, S1PTW = 0 [ 92.760337] FSC = 0x04: level 0 translation fault [ 92.765243] Data abort info: [ 92.768129] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 92.773626] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 92.778763] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 92.784098] user pgtable: 4k pages, 48-bit VAs, pgdp=000000088ed23000 [ 92.790550] [0000000000000148] pgd=0000000000000000, p4d=0000000000000000 [ 92.797381] Internal error: Oops: 0000000096000004 [#1] SMP [ 92.803027] Modules linked in: powervr [ 92.852533] CPU: 0 UID: 0 PID: 409 Comm: triangle Not tainted 7.1.0-rc5-g98b46e693b91 #1 PREEMPT [ 92.861385] Hardware name: Texas Instruments AM68 SK (DT) [ 92.866766] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 92.873709] pc : pvr_vm_get_fw_mem_context+0x0/0xc [powervr] [ 92.879376] lr : pvr_queue_create+0x26c/0x440 [powervr] [ 92.884595] sp : ffff8000837fbb00 [ 92.887895] x29: ffff8000837fbb60 x28: 0000000000000000 x27: ffff8000837fbce8 [ 92.895015] x26: ffff000807f61a40 x25: ffff000807f61a00 x24: ffff000807f64400 [ 92.902135] x23: ffff00080a5ab000 x22: ffff800079b24730 x21: ffff000807f61800 [ 92.909254] x20: ffff00080999e680 x19: 0000000000000000 x18: 0000000000000000 [ 92.916373] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000001 [ 92.923492] x14: 0000000000000000 x13: 0000000000000002 x12: ffff80008145b298 [ 92.930611] x11: ffff8000844e5000 x10: ffff80008165a130 x9 : 0000000000000100 [ 92.937730] x8 : 0000000000000001 x7 : ffff0008076b27e0 x6 : ffff00080ec43b7c [ 92.944850] x5 : ffff00080ec43b78 x4 : 0000000000000000 x3 : ffff00080999e680 [ 92.951968] x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000 [ 92.959088] Call trace: [ 92.961521] pvr_vm_get_fw_mem_context+0x0/0xc [powervr] (P) [ 92.967173] pvr_context_create+0x190/0x410 [powervr] [ 92.972218] pvr_ioctl_create_context+0x44/0x8c [powervr] [ 92.977608] drm_ioctl_kernel+0xbc/0x124 [drm] [ 92.982127] drm_ioctl+0x1f8/0x4dc [drm] [ 92.986098] __arm64_sys_ioctl+0xac/0x104 [ 92.990102] invoke_syscall+0x54/0x10c [ 92.993842] el0_svc_common.constprop.0+0x40/0xe0 [ 92.998532] do_el0_svc+0x1c/0x28 [ 93.001835] el0_svc+0x38/0x11c [ 93.004969] el0t_64_sync_handler+0xa0/0xe4 [ 93.009139] el0t_64_sync+0x198/0x19c [ 93.012792] Code: aa1703e0 d2800014 95cb0ba4 17ffffe8 (f940a400) [ 93.018869] ---[ end trace 0000000000000000 ]---
--- drivers/gpu/drm/imagination/pvr_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/imagination/pvr_context.c +2 -2
@@ -309,8 +309,8 @@ int pvr_context_create(struct pvr_file * goto err_free_ctx; ctx->vm_ctx =pvr_vm_context_lookup (pvr_file, args->vm_context_handle); -if (IS_ERR (ctx->vm_ctx)) { - err =PTR_ERR (ctx->vm_ctx); +if (!ctx->vm_ctx) { + err = -EINVAL ; goto err_free_ctx; }
Greg Kroah-Hartman
maintainerPATCH 410/744 drm/imagination: acquire vm_ctx->lock before mapping memory to GPU VM
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Icenowy Zheng <[email protected]>
commit 17e2030f37600994440f875dc410615d5c66ee6d upstream.
The drm gpuvm code doesn't protect find operation against map operation, and the driver needs to ensure a map operation shouldn't happen when a find operation is in progress.
In some cases a find operation will be in progress when doing map/unmap operations, and the find operation will do a NULL pointer dereference.
An example of the stack trace of such NULL dereference is shown below:
``` Unable to handle kernel access to user memory without uaccess routines at virtual address 0000000000000010 [<ffffffff01e989d4>] drm_gpuva_find+0x28/0x6c [drm_gpuvm] [<ffffffff01ed3a40>] pvr_vm_unmap+0x34/0x68 [powervr] [<ffffffff01ec69da>] pvr_ioctl_vm_unmap+0x2e/0x50 [powervr] [<ffffffff8080ce0a>] drm_ioctl_kernel+0x8e/0xdc [<ffffffff8080d016>] drm_ioctl+0x1be/0x3e0 [<ffffffff802bec3e>] __riscv_sys_ioctl+0xba/0xc4 [<ffffffff80d858b2>] do_trap_ecall_u+0x23e/0x3f4 [<ffffffff80d92288>] handle_exception+0x168/0x174 ```
As all occurences of drm_gpuva_find*() are already guarded by vm_ctx->lock, make pvr_vm_map() to acquire this lock to prevent disturbing any find operation. This fixes the NULL deference problem in drm_gpuva_find*().
--- drivers/gpu/drm/imagination/pvr_vm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/imagination/pvr_vm.c +2 -0
@@ -747,6 +747,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctxpvr_gem_object_get (pvr_obj); +mutex_lock (&vm_ctx->lock); err =drm_gpuvm_exec_lock (&vm_exec);if (err) goto err_cleanup;
@@ -756,6 +757,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctxdrm_gpuvm_exec_unlock (&vm_exec); err_cleanup: +mutex_unlock (&vm_ctx->lock);pvr_vm_bind_op_fini (&bind_op);return err;
Greg Kroah-Hartman
maintainerPATCH 411/744 drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongqiang Sun <[email protected]>
commit 426ffae6ecc7ec77d32bf8be065c21a1b881b084 upstream.
CRIU checkpoint copies the MQD control stack using cp_hqd_cntl_stack_size from hardware without bounding it to the allocated BO region. If the HW field is larger than the queue's control stack allocation, memcpy reads past the BO into adjacent GTT memory and can leak kernel data to userspace.
Store the page-aligned control stack BO size in mqd_manager and clamp checkpoint copies and reported checkpoint sizes to min(cp_hqd_cntl_stack_size, mm->ctl_stack_size). Apply the same bound for multi-XCC v9.4.3 checkpoint layout.
--- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h | 1 drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 25 +++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +1 -0
@@ -127,6 +127,7 @@ struct mqd_manager {struct mutex mqd_mutex;struct kfd_node *dev;uint32_t mqd_size; +uint32_t ctl_stack_size; };struct mqd_user_context_save_area_header {
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +22 -3
@@ -27,6 +27,7 @@#include <linux/uaccess.h> #include "kfd_priv.h" #include "kfd_mqd_manager.h" +#include "kfd_topology.h" #include "v9_structs.h" #include "gc/gc_9_0_offset.h" #include "gc/gc_9_0_sh_mask.h"
@@ -400,8 +401,11 @@ static int get_wave_state(struct mqd_manstatic int get_checkpoint_info (struct mqd_manager *mm,void *mqd,u32 *ctl_stack_size) {struct v9_mqd *m =get_mqd (mqd); +u32 per_xcc_size; -if (check_mul_overflow (m->cp_hqd_cntl_stack_size,NUM_XCC (mm->dev->xcc_mask), ctl_stack_size)) + per_xcc_size =min_t (u32, m->cp_hqd_cntl_stack_size, mm->ctl_stack_size); + +if (check_mul_overflow (per_xcc_size,NUM_XCC (mm->dev->xcc_mask), ctl_stack_size))return -EINVAL ;return 0 ;
@@ -410,13 +414,15 @@ static int get_checkpoint_info(struct mqstatic void checkpoint_mqd (struct mqd_manager *mm,void *mqd,void *mqd_dst,void *ctl_stack_dst) {struct v9_mqd *m; +u32 ctl_stack_copy_size;/* Control stack is located one page after MQD. */ void *ctl_stack = (void *)((uintptr_t )mqd +AMDGPU_GPU_PAGE_SIZE ); m =get_mqd (mqd); + ctl_stack_copy_size =min_t (u32, m->cp_hqd_cntl_stack_size, mm->ctl_stack_size);memcpy (mqd_dst, m,sizeof (struct v9_mqd )); -memcpy (ctl_stack_dst, ctl_stack, m->cp_hqd_cntl_stack_size); +memcpy (ctl_stack_dst, ctl_stack, ctl_stack_copy_size); } static void checkpoint_mqd_v9_4_3(struct mqd_manager *mm,
@@ -425,15 +431,19 @@ static void checkpoint_mqd_v9_4_3(struct void *ctl_stack_dst) {struct v9_mqd *m; +u32 ctl_stack_stride;int xcc;uint64_t size =get_mqd (mqd)->cp_mqd_stride_size; + ctl_stack_stride =min_t (u32,get_mqd (mqd)->cp_hqd_cntl_stack_size, + mm->ctl_stack_size); +for (xcc =0 ; xcc <NUM_XCC (mm->dev->xcc_mask); xcc++) { m =get_mqd (mqd + size * xcc);checkpoint_mqd (mm, m, (uint8_t *)mqd_dst +sizeof (*m) * xcc, - (uint8_t *)ctl_stack_dst + m->cp_hqd_cntl_stack_size * xcc); + (uint8_t *)ctl_stack_dst + ctl_stack_stride * xcc); } }
@@ -987,6 +997,15 @@ struct mqd_manager *mqd_manager_init_v9( mqd->is_occupied = kfd_is_occupied_cp; mqd->get_checkpoint_info = get_checkpoint_info; mqd->mqd_size =sizeof (struct v9_mqd ); +if (dev->kfd->cwsr_enabled) { +struct kfd_topology_device *topo_dev; + + topo_dev =kfd_topology_device_by_id (dev->id); +if (topo_dev) + mqd->ctl_stack_size = +ALIGN (topo_dev->node_props.ctl_stack_size, +AMDGPU_GPU_PAGE_SIZE ); + } mqd->mqd_stride = mqd_stride_v9;#if defined(CONFIG_DEBUG_FS ) mqd->debugfs_show_mqd = debugfs_show_mqd;
Greg Kroah-Hartman
maintainerPATCH 412/744 drm/amdkfd: Guard m->cp_hqd_eop_control setting by q->eop_ring_buffer_size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaogang Chen <[email protected]>
commit 8cd2ea7bab77b7aa087b1a6cc26d2df03c2a6ed9 upstream.
To avoid wraparound if the value is 0.
--- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +2 -2
@@ -198,8 +198,8 @@ static void update_mqd(struct mqd_manage* more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control =min (0xA , -ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ?min (0xA , +ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ) :0 ; m->cp_hqd_eop_base_addr_lo =lower_32_bits (q->eop_ring_buffer_address >>8 ); m->cp_hqd_eop_base_addr_hi =
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +2 -2
@@ -237,8 +237,8 @@ static void update_mqd(struct mqd_manage* more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control =min (0xA , -ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ?min (0xA , +ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ) :0 ; m->cp_hqd_eop_base_addr_lo =lower_32_bits (q->eop_ring_buffer_address >>8 ); m->cp_hqd_eop_base_addr_hi =
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +2 -2
@@ -212,8 +212,8 @@ static void update_mqd(struct mqd_manage* more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control =min (0xA , -ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ?min (0xA , +ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ) :0 ; m->cp_hqd_eop_base_addr_lo =lower_32_bits (q->eop_ring_buffer_address >>8 ); m->cp_hqd_eop_base_addr_hi =
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +2 -2
@@ -294,8 +294,8 @@ static void update_mqd(struct mqd_manage* more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control =min (0xA , -ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ?min (0xA , +ffs (q->eop_ring_buffer_size /sizeof (unsigned int )) -1 -1 ) :0 ; m->cp_hqd_eop_base_addr_lo =lower_32_bits (q->eop_ring_buffer_address >>8 ); m->cp_hqd_eop_base_addr_hi =
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +2 -2
@@ -209,8 +209,8 @@ static void __update_mqd(struct mqd_mana* more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control |=min (0xA , -order_base_2 (q->eop_ring_buffer_size /4 ) -1 ); + m->cp_hqd_eop_control |= q->eop_ring_buffer_size ?min (0xA , +order_base_2 (q->eop_ring_buffer_size /4 ) -1 ) :0 ; m->cp_hqd_eop_base_addr_lo =lower_32_bits (q->eop_ring_buffer_address >>8 ); m->cp_hqd_eop_base_addr_hi =
Greg Kroah-Hartman
maintainerPATCH 413/744 drm/amdkfd: Use kvcalloc to allocate arrays
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Francis <[email protected]>
commit 9c8b85f95c1d4736b967e17b8eb4a463c055bea3 upstream.
There were a few instances in kfd_chardev.c of kvzalloc being used to allocate memory for an array.
Switch those to kvcalloc, which
- is the standard way of allocating a zero-initialized array
- does a check for the mul overflowing
--- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +6 -6
@@ -1837,13 +1837,13 @@ static int criu_checkpoint_devices(strucstruct kfd_criu_device_bucket *device_buckets =NULL ;int ret =0 , i; - device_buckets =kvzalloc (num_devices *sizeof (*device_buckets),GFP_KERNEL ); + device_buckets =kvcalloc (num_devices,sizeof (*device_buckets),GFP_KERNEL );if (!device_buckets) { ret = -ENOMEM ; goto exit; } - device_priv =kvzalloc (num_devices *sizeof (*device_priv),GFP_KERNEL ); + device_priv =kvcalloc (num_devices,sizeof (*device_priv),GFP_KERNEL );if (!device_priv) { ret = -ENOMEM ; goto exit;
@@ -1963,17 +1963,17 @@ static int criu_checkpoint_bos(struct kfint ret =0 , pdd_index, bo_index =0 , id;void *mem; - bo_buckets =kvzalloc (num_bos *sizeof (*bo_buckets),GFP_KERNEL ); + bo_buckets =kvcalloc (num_bos,sizeof (*bo_buckets),GFP_KERNEL );if (!bo_buckets)return -ENOMEM ; - bo_privs =kvzalloc (num_bos *sizeof (*bo_privs),GFP_KERNEL ); + bo_privs =kvcalloc (num_bos,sizeof (*bo_privs),GFP_KERNEL );if (!bo_privs) { ret = -ENOMEM ; goto exit; } - files =kvzalloc (num_bos *sizeof (struct file *),GFP_KERNEL ); + files =kvcalloc (num_bos,sizeof (struct file *),GFP_KERNEL );if (!files) { ret = -ENOMEM ; goto exit;
@@ -2510,7 +2510,7 @@ static int criu_restore_bos(struct kfd_pif (!bo_buckets)return -ENOMEM ; - files =kvzalloc (args->num_bos *sizeof (struct file *),GFP_KERNEL ); + files =kvcalloc (args->num_bos,sizeof (struct file *),GFP_KERNEL );if (!files) { ret = -ENOMEM ; goto exit;
Greg Kroah-Hartman
maintainerPATCH 414/744 drm/amdkfd: Check bounds in allocate_event_notification_slot
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Francis <[email protected]>
commit bb52249fbbe948875155ccd45cd8d74bf4ae747b upstream.
The valid event ids go from 0 to KFD_SIGNAL_EVENT_LIMIT
allocate_event_notification_slot has an option to specify an event id to allocate at, used by CRIU. We weren't checking the bounds on that value.
Check them.
v2: Lower bounds check is unecessary because of idr_alloc already rejecting negative numbers. Upper bounds check should be KFD_SIGNAL_EVENT_LIMIT since the signal mode mappings might not yet exist
--- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_events.c +3 -0
@@ -107,6 +107,9 @@ static int allocate_event_notification_s }if (restore_id) { +if (*restore_id >=KFD_SIGNAL_EVENT_LIMIT ) +return -EINVAL ; + id =idr_alloc (&p->event_idr, ev, *restore_id, *restore_id +1 ,GFP_KERNEL ); }else {
Greg Kroah-Hartman
maintainerPATCH 415/744 drm/amdkfd: Check bounds on CRIU restore queue type and mqd size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Francis <[email protected]>
commit 47ea05f246bebc81c7796f56265cffd812cf0601 upstream.
We weren't checking whether the values provided in the private data in kfd CRIU restore were within bounds.
For queue type, add a KFD_QUEUE_TYPE_MAX and ensure the provided type is less than it.
For mqd_size, add new function mqd_size_from_queue_type and confirm that the provided mqd_size matches expectations.
--- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 6 ++++ drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 2 + drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 3 +- drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 24 ++++++++++++----- 4 files changed, 27 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +6 -0
@@ -3649,6 +3649,12 @@ out:dqm_unlock (dqm);return r; } + +size_t mqd_size_from_queue_type (struct device_queue_manager *dqm,enum kfd_queue_type type) +{ +return dqm->mqd_mgrs[get_mqd_type_from_queue_type (type)]->mqd_size; +} +#if defined(CONFIG_DEBUG_FS ) static void seq_reg_dump(struct seq_file *m,
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +2 -0
@@ -329,6 +329,8 @@ int debug_refresh_runlist(struct device_bool kfd_dqm_is_queue_in_process (struct device_queue_manager *dqm,struct qcm_process_device *qpd,int doorbell_off,u32 *queue_format); +size_t mqd_size_from_queue_type (struct device_queue_manager *dqm, +enum kfd_queue_type type);static inline unsigned int get_sh_mem_bases_32 (struct kfd_process_device *pdd) {
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +2 -1
@@ -436,7 +436,8 @@ enum kfd_queue_type {KFD_QUEUE_TYPE_SDMA ,KFD_QUEUE_TYPE_HIQ ,KFD_QUEUE_TYPE_SDMA_XGMI , -KFD_QUEUE_TYPE_SDMA_BY_ENG_ID +KFD_QUEUE_TYPE_SDMA_BY_ENG_ID , + KFD_QUEUE_TYPE_MAX, }; enum kfd_queue_format {
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +17 -7
@@ -1003,6 +1003,23 @@ int kfd_criu_restore_queue(struct kfd_pr goto exit; } + pdd =kfd_process_device_data_by_id (p, q_data->gpu_id); +if (!pdd) { +pr_err ("Failed to get pdd\n" ); + ret = -EINVAL ; + goto exit; + } + +if (q_data->type >=KFD_QUEUE_TYPE_MAX ) { + ret = -EINVAL ; + goto exit; + } + +if (q_data->mqd_size !=mqd_size_from_queue_type (pdd->dev->dqm, q_data->type)) { + ret = -EINVAL ; + goto exit; + } + *priv_data_offset +=sizeof (*q_data); q_extra_data_size = (uint64_t )q_data->ctl_stack_size + q_data->mqd_size;
@@ -1025,13 +1042,6 @@ int kfd_criu_restore_queue(struct kfd_pr *priv_data_offset += q_extra_data_size; - pdd =kfd_process_device_data_by_id (p, q_data->gpu_id); -if (!pdd) { -pr_err ("Failed to get pdd\n" ); - ret = -EINVAL ; - goto exit; - } -/* * data stored in this order: * mqd[xcc0], mqd[xcc1],..., ctl_stack[xcc0], ctl_stack[xcc1]...
Greg Kroah-Hartman
maintainerPATCH 416/744 drm/amdkfd: fix 32-bit overflow in CWSR total size calculation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongqiang Sun <[email protected]>
commit 2b0386d4293920e690c0e017708f999b93cc729b upstream.
total_cwsr_size was computed in 32-bit before being used as a BO/SVM allocation size.
With large ctx_save_restore_area_size and debug_memory_size multiplied by the XCC count, the product can wrap, yielding an undersized CWSR save area that firmware later overruns.
Promote total_cwsr_size to u64 and use check_add_overflow()/ check_mul_overflow() in both kfd_queue_acquire_buffers() and kfd_queue_release_buffers().
--- drivers/gpu/drm/amd/amdkfd/kfd_queue.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_queue.c +17 -6
@@ -23,6 +23,7 @@*/ #include <linux/slab.h> +#include <linux/overflow.h> #include "kfd_priv.h" #include "kfd_topology.h" #include "kfd_svm.h"
@@ -235,7 +236,7 @@ int kfd_queue_acquire_buffers(struct kfdstruct kfd_topology_device *topo_dev;u64 expected_queue_size;struct amdgpu_vm *vm; -u32 total_cwsr_size; +u64 total_cwsr_size;int err; topo_dev =kfd_topology_device_by_id (pdd->dev->id);
@@ -308,8 +309,14 @@ int kfd_queue_acquire_buffers(struct kfd goto out_err_unreserve; } - total_cwsr_size = (properties->ctx_save_restore_area_size + - topo_dev->node_props.debug_memory_size) *NUM_XCC (pdd->dev->xcc_mask); + total_cwsr_size = (u64 )properties->ctx_save_restore_area_size + + topo_dev->node_props.debug_memory_size; +if (check_mul_overflow (total_cwsr_size, +NUM_XCC (pdd->dev->xcc_mask), + &total_cwsr_size)) { + err = -EINVAL ; + goto out_err_unreserve; + } total_cwsr_size =ALIGN (total_cwsr_size,PAGE_SIZE ); err = kfd_queue_buffer_get(vm, (void *)properties->ctx_save_restore_area_address,
@@ -344,7 +351,7 @@ out_err_release:int kfd_queue_release_buffers (struct kfd_process_device *pdd,struct queue_properties *properties) {struct kfd_topology_device *topo_dev; -u32 total_cwsr_size; +u64 total_cwsr_size;kfd_queue_buffer_put (&properties->wptr_bo);kfd_queue_buffer_put (&properties->rptr_bo);
@@ -355,8 +362,12 @@ int kfd_queue_release_buffers(struct kfd topo_dev =kfd_topology_device_by_id (pdd->dev->id);if (!topo_dev)return -EINVAL ; - total_cwsr_size = (properties->ctx_save_restore_area_size + - topo_dev->node_props.debug_memory_size) *NUM_XCC (pdd->dev->xcc_mask); + total_cwsr_size = (u64 )properties->ctx_save_restore_area_size + + topo_dev->node_props.debug_memory_size; +if (check_mul_overflow (total_cwsr_size, +NUM_XCC (pdd->dev->xcc_mask), + &total_cwsr_size)) +return -EINVAL ; total_cwsr_size =ALIGN (total_cwsr_size,PAGE_SIZE );kfd_queue_buffer_svm_put (pdd, properties->ctx_save_restore_area_address, total_cwsr_size);
Greg Kroah-Hartman
maintainerPATCH 417/744 drm/amdkfd: free MQD managers on DQM init failures
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit b240f792ae02e9b687eafff934a39e57d1e45365 upstream.
The change referenced by the Fixes tag releases the HIQ SDMA MQD trunk buffer when device_queue_manager_init() fails after it has been allocated.
However, the same failure path can also be reached after init_mqd_managers() has succeeded. At that point dqm->mqd_mgrs[] contains per-type MQD manager objects owned by the device queue manager. The normal teardown path frees those objects from uninitialize(), but the initialization error path only frees dqm itself.
Free the MQD managers from the initialization error path as well. This is safe for earlier failures because dqm is zeroed when allocated and init_mqd_managers() clears the entries it rolls back internally.
--- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +4 -0
@@ -2936,6 +2936,7 @@ static void deallocate_hiq_sdma_mqd(strustruct device_queue_manager *device_queue_manager_init (struct kfd_node *dev) {struct device_queue_manager *dqm; +int i;pr_debug ("Loading device queue manager\n" );
@@ -3062,6 +3063,9 @@ struct device_queue_manager *device_queudeallocate_hiq_sdma_mqd (dev, &dqm->hiq_sdma_mqd); out_free: +for (i =0 ; i <KFD_MQD_TYPE_MAX ; i++) +kfree (dqm->mqd_mgrs[i]); +kfree (dqm);return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 418/744 drm/amd/display: set MSA MISC1 bit 6 when using VSC SDP for DCE 11.x
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leorize <[email protected]>
commit da353a6b30086674c77bdbbfd86e9e0c7416ba99 upstream.
When BT.2020 colorimetry is selected, the driver sends information using VSC SDP but does not set "ignore MSA colorimetry" bit on older GPUs with DCE-based IPs. This causes certain sinks to prefer colorimetry information in DP MSA, resulting in terrible color rendering ("dull" colors) when HDR is enabled.
This commit wires up the MISC1 bit 6 for GPUs with DCE 11.x based IPs to correctly configure sinks to ignore colorimetry information in MSA, resolving the color rendering issue.
--- drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c | 15 ++++++++++++++- drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +14 -1
@@ -271,7 +271,6 @@ static void dce110_stream_encoder_dp_set bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting) { - (void)use_vsc_sdp_for_colorimetry; (void)enable_sdp_splitting;uint32_t h_active_start;uint32_t v_active_start;
@@ -334,6 +333,16 @@ static void dce110_stream_encoder_dp_setif (REG (DP_MSA_MISC )) misc1 =REG_READ (DP_MSA_MISC ); +/* For YCbCr420 and BT2020 Colorimetry Formats, VSC SDP shall be used. +* When MISC1, bit 6, is Set to 1, a Source device uses a VSC SDP to indicate the +* Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7, +* and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become "don't care"). +*/ +if (use_vsc_sdp_for_colorimetry) + misc1 = misc1 |0x40 ; +else + misc1 = misc1 & ~0x40 ; +/* set color depth */ switch (hw_crtc_timing.display_color_depth) {
@@ -499,6 +508,10 @@ static void dce110_stream_encoder_dp_set hw_crtc_timing.h_addressable + hw_crtc_timing.h_border_right,DP_MSA_VHEIGHT , hw_crtc_timing.v_border_top + hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom); + }else { +/* DCE-only path */ +if (REG (DP_MSA_MISC )) +REG_WRITE (DP_MSA_MISC , misc1);/* MSA_MISC1 */ } }
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h +2 -1
@@ -96,7 +96,8 @@#define SE_COMMON_REG_LIST (id)\ SE_COMMON_REG_LIST_DCE_BASE(id), \ - SRI(AFMT_CNTL, DIG, id) + SRI(AFMT_CNTL, DIG, id), \ + SRI(DP_MSA_MISC, DP, id)#define SE_DCN_REG_LIST (id)\ SE_COMMON_REG_LIST_BASE(id),\
Greg Kroah-Hartman
maintainerPATCH 419/744 drm/amd/display: Handle struct drm_plane_state.ignore_damage_clips
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit ac11060c6d4959e2d4ceada037d2e1e1bfcf6645 upstream.
The mode-setting pipeline can disabled damage clippings for a commit by setting ignore_damage_clips in struct drm_plane_state. The commit will then do a full display update.
Test the flag in DCN code and do a full update in DCN code if it has been set.
Commit 35ed38d58257 ("drm: Allow drivers to indicate the damage helpers to ignore damage clips") introduced ignore_damage_clips to selectively ignore damage clipping in certain framebuffer changes. This driver does not do that, but DRM's damage iterator will soon rely on the flag. Therefore supporting it here as well make sense for consistency.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +6 -4
@@ -6440,8 +6440,8 @@ static void fill_dc_dirty_rects(struct d {struct dm_crtc_state *dm_crtc_state =to_dm_crtc_state (crtc_state);struct rect *dirty_rects = flip_addrs->dirty_rects; -u32 num_clips; -struct drm_mode_rect *clips; +u32 num_clips =0 ; +struct drm_mode_rect *clips =NULL ;bool bb_changed;bool fb_changed;u32 i =0 ;
@@ -6457,8 +6457,10 @@ static void fill_dc_dirty_rects(struct dif (new_plane_state->rotation !=DRM_MODE_ROTATE_0 ) goto ffu; - num_clips =drm_plane_get_damage_clips_count (new_plane_state); - clips =drm_plane_get_damage_clips (new_plane_state); +if (!new_plane_state->ignore_damage_clips) { + num_clips =drm_plane_get_damage_clips_count (new_plane_state); + clips =drm_plane_get_damage_clips (new_plane_state); + }if (num_clips && (!amdgpu_damage_clips || (amdgpu_damage_clips <0 && is_psr_su)))
Greg Kroah-Hartman
maintainerPATCH 420/744 drm/amd/display: use kvzalloc to allocate struct dc
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Honglei Huang <[email protected]>
commit 75050390151a14802be433c3856ddcb483cecd24 upstream.
struct dc has grown large over time (most of it the two inlined dc_scratch_space copies) and now sits close to the page allocator's 4 MiB contiguous allocation limit. Its actual size is not fixed by the source alone, it also depends on the compiler and the .config, so it can easily cross 4 MiB, e.g. with a newer GCC or a config change.
dc_create() allocates it with kzalloc(). Once struct dc exceeds 4 MiB the request is rounded up to order 11 (8 MiB), which is above MAX_PAGE_ORDER, so the page allocator warns and returns NULL. dc_create() then fails, DM init fails and amdgpu probe aborts with -EINVAL:
WARNING: mm/page_alloc.c:5197 at __alloc_frozen_pages_noprof+0x2f9/0x380 dc_create+0x38/0x660 [amdgpu] amdgpu_dm_init+0x2d9/0x510 [amdgpu] dm_hw_init+0x1b/0x90 [amdgpu] amdgpu_device_init.cold+0x150d/0x1e13 [amdgpu] amdgpu_driver_load_kms+0x19/0x80 [amdgpu] amdgpu_pci_probe+0x1e2/0x4c0 [amdgpu]
dc_create() then returns NULL and DM init fails, which aborts the whole GPU init and makes amdgpu probe fail with -EINVAL ("hw_init of IP block <dm> failed -22"), leaving the display unusable. The subsequent amdgpu_irq_put() warnings during teardown are just fallout of unwinding a half-initialized device.
struct dc is a software-only bookkeeping structure that is never handed to hardware DMA and is only ever kept as an opaque pointer, so it does not require physically contiguous memory. Allocate it with kvzalloc() (and free it with kvfree()) so that the allocator can fall back to vmalloc() when a contiguous allocation of that size is not available, which also avoids the MAX_PAGE_ORDER warning entirely.
v2:
- Rebase to amd-staging-drm-next.
--- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/dc/core/dc.c +3 -3
@@ -1507,7 +1507,7 @@ static void disable_vbios_mode_if_requirstruct dc *dc_create (const struct dc_init_data *init_params) { -struct dc *dc =kzalloc_obj (*dc); +struct dc *dc =kvzalloc_obj (*dc);unsigned int full_pipe_count;if (!dc)
@@ -1555,7 +1555,7 @@ struct dc *dc_create(const struct dc_ini destruct_dc:dc_destruct (dc); -kfree (dc); +kvfree (dc);return NULL ; }
@@ -1604,7 +1604,7 @@ void dc_deinit_callbacks(struct dc *dc)void dc_destroy (struct dc **dc) {dc_destruct (*dc); -kfree (*dc); +kvfree (*dc); *dc =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 421/744 drm/amd/display: detect_link_and_local_sink: DP alt mode timeout path leaks prev_sink reference
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: WenTao Liang <[email protected]>
commit a6e14b976be48eebd8769cb5b883a6af7fc5ade1 upstream.
prev_sink is unconditionally retained via dc_sink_retain at function
entry, but the DP alt mode timeout path inside SIGNAL_TYPE_DISPLAY_PORT returns false without releasing prev_sink. All other return paths in the function correctly call dc_sink_release(prev_sink), making this the only missing cleanup.
--- drivers/gpu/drm/amd/display/dc/link/link_detection.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/link/link_detection.c +4 -1
@@ -1069,8 +1069,11 @@ static bool detect_link_and_local_sink(s link->link_enc->features.flags.bits.DP_IS_USB_C == 1) {/* if alt mode times out, return false */ -if (!wait_for_entering_dp_alt_mode (link)) +if (!wait_for_entering_dp_alt_mode (link)) { +if (prev_sink) +dc_sink_release (prev_sink);return false; + } }if (!detect_dp (link, &sink_caps, reason)) {
Greg Kroah-Hartman
maintainerPATCH 422/744 Revert "drm/amd/display: Restore 5s vbl offdelay for NV3x+ DGPUs"
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Li <[email protected]>
commit f39283eab44fb7e304677b2aa1d8c38f151b6566 upstream.
Now that proper fixes have been found, let's revert this workaround.
This reverts commit a1fc7bf6677eb547167cb72b3bcafdc34b976692.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +3 -15
@@ -9427,21 +9427,9 @@ static void manage_dm_interrupts(structif (acrtc_state) { timing = &acrtc_state->stream->timing; -if (amdgpu_ip_version (adev,DCE_HWIP ,0 ) >= -IP_VERSION (3 ,2 ,0 ) && - !(adev->flags &AMD_IS_APU )) { -/* -* DGPUs NV3x and newer that support idle optimizations -* experience intermittent flip-done timeouts on cursor -* updates. Restore 5s offdelay behavior for now. -* -* Discussion on the issue: -* https://lore.kernel.org/amd-gfx/[email protected]/ -*/ - config.offdelay_ms =5000 ; - config.disable_immediate = false; - }else if (amdgpu_ip_version (adev,DCE_HWIP ,0 ) < -IP_VERSION (3 ,5 ,0 )) { +if (amdgpu_ip_version (adev,DCE_HWIP ,0 ) < +IP_VERSION (3 ,5 ,0 ) || + !(adev->flags &AMD_IS_APU )) {/* * Older HW and DGPU have issues with instant off; * use a 2 frame offdelay.
Greg Kroah-Hartman
maintainerPATCH 423/744 drm/virtio: bound EDID block reads to the response buffer
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 4e1a53892ba7f8a3e1da6bfc53c83ae7c812dccd upstream.
virtio_get_edid_block() validates the read offset only against the device-supplied resp->size field, never against the fixed-size resp->edid array. The EDID block index is driven by the device-supplied extension count, so a malicious virtio-gpu backend can advertise a large size together with a high block count and read far past the array into adjacent kernel memory, which is then surfaced in the parsed EDID (an out-of-bounds read / info leak).
Also reject any read whose end exceeds the size of the edid array. Conforming EDID responses stay within the array and are unaffected.
--- drivers/gpu/drm/virtio/virtgpu_vq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/virtio/virtgpu_vq.c +2 -1
@@ -894,7 +894,8 @@ static int virtio_get_edid_block(void *dstruct virtio_gpu_resp_edid *resp = data;size_t start = block *EDID_LENGTH ; -if (start + len >le32_to_cpu (resp->size)) +if (start + len >le32_to_cpu (resp->size) || + start + len >sizeof (resp->edid))return -EINVAL ;memcpy (buf, resp->edid + start, len);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 424/744 drm/i915/vrr: require valid min/max vfreq for VRR
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
commit f8a9262c7a6fc2de9802e14b0228114f0333869e upstream.
Ensure the EDID provided min/max vfreq are valid. Most scenarios are already covered (by coincidence) through the checks in intel_vrr_is_capable() and intel_vrr_is_in_range(), but be more explicit about it. At worst, a zero min_vfreq could lead to a division by zero in intel_vrr_compute_vmax().
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/display/intel_vrr.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/gpu/drm/i915/display/intel_vrr.c +4 -0
@@ -64,6 +64,10 @@ bool intel_vrr_is_capable(struct intel_creturn false; } +if (!info->monitor_range.min_vfreq || !info->monitor_range.max_vfreq || + info->monitor_range.min_vfreq > info->monitor_range.max_vfreq) +return false; +return info->monitor_range.max_vfreq - info->monitor_range.min_vfreq >10 ; }
Greg Kroah-Hartman
maintainerPATCH 425/744 drm/i915/hdcp: require monotonically increasing seq_num_v
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
commit db9e64c983dcb07ff256bd455f258c44aa530ff8 upstream.
The HDCP 2.2 specification requires the seq_num_v to be monotonically increasing, and repeated seq_num_v needs to be treated as an integrity failure. Make it so.
For the first message, seq_num_v must be zero, and is already checked. We can only check for less-than-or-equal for the subsequent messages, where hdcp2_encrypted is true.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/display/intel_hdcp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/display/intel_hdcp.c +4 -3
@@ -1785,9 +1785,10 @@ int hdcp2_authenticate_repeater_topologyreturn -EINVAL ; } -if (seq_num_v < hdcp->seq_num_v) { -/* Roll over of the seq_num_v from repeater. Reauthenticate. */ -drm_dbg_kms (display->drm,"Seq_num_v roll over.\n" ); +if (hdcp->hdcp2_encrypted && seq_num_v <= hdcp->seq_num_v) { +/* Reauthenticate on Seq_num_v repeat or rollover */ +drm_dbg_kms (display->drm,"Seq_num_v %s\n" , + seq_num_v == hdcp->seq_num_v ?"repeat" :"rollover" );return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 426/744 drm/i915/hdcp: check streams[] bounds before overflow
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
commit bbb15a6b042d02e5508a02b4847e02d2579ee7bc upstream.
The data->streams[] overflow check is done after the buffer overflow has already happened. Move the overflow check before the write.
Side note, emitting a warning splat with a backtrace might be overkill here, but prefer not changing the behaviour other than not doing the overrun.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/display/intel_hdcp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_hdcp.c +4 -1
@@ -132,6 +132,9 @@ intel_hdcp_required_content_stream(strucif (conn_dig_port != dig_port)continue ; +if (drm_WARN_ON (display->drm, data->k >=INTEL_NUM_PIPES (display))) +return -EINVAL ; + data->streams[data->k].stream_id =intel_conn_to_vcpi (state, connector); data->k++;
@@ -142,7 +145,7 @@ intel_hdcp_required_content_stream(struc }drm_connector_list_iter_end (&conn_iter); -if (drm_WARN_ON (display->drm, data->k >INTEL_NUM_PIPES (display) || data->k ==0 )) +if (drm_WARN_ON (display->drm, !data->k))return -EINVAL ;/*
Greg Kroah-Hartman
maintainerPATCH 427/744 drm/amdgpu: add the doorbell index input for suspending userq
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prike Liang <[email protected]>
commit b181bf68d11f034efe27ae1377a0f659605f040f upstream.
It requires inputing the doorbell offset for MES firmware preempts the userq, and adding the doorbell offset also keep aliging with the union MESAPI__SUSPEND in MES firmware.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +2 -0
@@ -288,12 +288,14 @@ struct mes_suspend_gang_input {uint64_t gang_context_addr;uint64_t suspend_fence_addr;uint32_t suspend_fence_value; +uint32_t doorbell_offset; };struct mes_resume_gang_input {uint32_t xcc_id;bool resume_all_gangs;uint64_t gang_context_addr; +uint32_t doorbell_offset; };struct mes_reset_queue_input {
Greg Kroah-Hartman
maintainerPATCH 428/744 drm/amdgpu/sdma7.0: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit e80e28f398f5d9f6e361ffb56382d2e74fc87556 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +2 -2
@@ -363,7 +363,7 @@ static void sdma_v7_0_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_COPY_LINEAR_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* Ucached(UC) */ /* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -374,7 +374,7 @@ static void sdma_v7_0_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_COPY_LINEAR_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 429/744 drm/amdgpu/sdma6.0: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit ec42c96c322e5cc48099ab5e67b5cbe236cb1949 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +2 -2
@@ -360,7 +360,7 @@ static void sdma_v6_0_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_COPY_LINEAR_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* Ucached(UC) */ /* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -371,7 +371,7 @@ static void sdma_v6_0_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_COPY_LINEAR_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 430/744 drm/amdgpu/sdma5.2: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit b9dd618a635d39fbb211454b6e8837b2a7f10fb0 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +2 -2
@@ -377,7 +377,7 @@ static void sdma_v5_2_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* Ucached(UC) */ /* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -388,7 +388,7 @@ static void sdma_v5_2_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 431/744 drm/amdgpu/sdma5.0: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 9e98ed3113943257ad6e5c1e6beddbdb482a70ad upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +2 -2
@@ -527,7 +527,7 @@ static void sdma_v5_0_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* Ucached(UC) */ /* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -538,7 +538,7 @@ static void sdma_v5_0_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 432/744 drm/i915: Return NULL on error in active_instance
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <[email protected]>
commit 1e33f0de5fdcd09e51fdec1e5822448970b6420f upstream.
Avoid returning &node->base when node is NULL due to OOM during GFP_ATOMIC allocation.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/i915_active.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/i915_active.c +6 -1
@@ -318,7 +318,7 @@ active_instance(struct i915_active *ref,*/ node =kmem_cache_alloc (slab_cache,GFP_ATOMIC );if (!node) - goto out; + goto err;__i915_active_fence_init (&node->base,NULL , node_retire); node->ref = ref;
@@ -332,6 +332,11 @@ out:spin_unlock_irq (&ref->tree_lock);return &node->base; + +err: +spin_unlock_irq (&ref->tree_lock); + +return NULL ; } void __i915_active_init(struct i915_active *ref,
Greg Kroah-Hartman
maintainerPATCH 433/744 drm/i915/bios: range check LFP Data Block panel_type2
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
commit 2084503f2d087bf956198e7f6eb25b03a7049cb2 upstream.
While the panel_type from LFP Data Block is range checked, panel_type2 is not. Add a few helpers for range checking, and use them to not only check panel_type2, but also improve clarity and correctness in the panel type selection.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
v2:
- Fix commit message typo (Michał)
- Add is_panel_type_pnp() (Ville)
--- drivers/gpu/drm/i915/display/intel_bios.c | 36 +++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-)
drivers/gpu/drm/i915/display/intel_bios.c +28 -8
@@ -623,6 +623,21 @@ get_lfp_data_tail(const struct bdb_lfp_dreturn NULL ; } +static bool is_panel_type_valid (int panel_type) +{ +return panel_type >=0 && panel_type <16 ; +} + +static bool is_panel_type_pnp (int panel_type) +{ +return panel_type ==0xff ; +} + +static bool is_panel_type_valid_or_pnp (int panel_type) +{ +return is_panel_type_valid (panel_type) ||is_panel_type_pnp (panel_type); +} +static int opregion_get_panel_type (struct intel_display *display,const struct intel_bios_encoder_data *devdata,const struct drm_edid *drm_edid,bool use_fallback)
@@ -640,15 +655,21 @@ static int vbt_get_panel_type(struct intif (!lfp_options)return -1 ; -if (lfp_options->panel_type >0xf && - lfp_options->panel_type !=0xff ) { +if (!is_panel_type_valid_or_pnp (lfp_options->panel_type)) {drm_dbg_kms (display->drm,"Invalid VBT panel type 0x%x\n" , lfp_options->panel_type);return -1 ; } -if (devdata && devdata->child.handle ==DEVICE_HANDLE_LFP2 ) +if (devdata && devdata->child.handle ==DEVICE_HANDLE_LFP2 ) { +if (!is_panel_type_valid_or_pnp (lfp_options->panel_type2)) { +drm_dbg_kms (display->drm,"Invalid VBT panel type 2 0x%x\n" , + lfp_options->panel_type2); +return -1 ; + } +return lfp_options->panel_type2; + }drm_WARN_ON (display->drm, devdata && devdata->child.handle !=DEVICE_HANDLE_LFP1 );
@@ -762,13 +783,12 @@ static int get_panel_type(struct intel_d panel_types[i].name, panel_types[i].panel_type); } -if (panel_types[PANEL_TYPE_OPREGION ].panel_type >=0 ) +if (is_panel_type_valid (panel_types[PANEL_TYPE_OPREGION ].panel_type)) i =PANEL_TYPE_OPREGION ; -else if (panel_types[PANEL_TYPE_VBT ].panel_type ==0xff && - panel_types[PANEL_TYPE_PNPID ].panel_type >=0 ) +else if (is_panel_type_pnp (panel_types[PANEL_TYPE_VBT ].panel_type) && +is_panel_type_valid (panel_types[PANEL_TYPE_PNPID ].panel_type)) i =PANEL_TYPE_PNPID ; -else if (panel_types[PANEL_TYPE_VBT ].panel_type !=0xff && - panel_types[PANEL_TYPE_VBT ].panel_type >=0 ) +else if (is_panel_type_valid (panel_types[PANEL_TYPE_VBT ].panel_type)) i =PANEL_TYPE_VBT ;else i =PANEL_TYPE_FALLBACK ;
Greg Kroah-Hartman
maintainerPATCH 434/744 drm/amdgpu/soc24: reset dGPU if suspend got aborted
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakob Linke <[email protected]>
commit aff079bdce65f6d085e4b0091fdf87fffa95b0d9 upstream.
For SOC24 ASICs (RDNA4 / Navi 4x dGPUs) re-enabling PM features fails if an S3 suspend got aborted, the same issue already handled for SOC21 and SOC15:
commit df3c7dc5c58b ("drm/amdgpu: Reset dGPU if suspend got aborted") commit 38e8ca3e4b6d ("amdgpu/soc15: enable asic reset for dGPU in case of suspend abort")
The aborted resume fails with:
amdgpu: SMU: No response msg_reg: 6 resp_reg: 0
amdgpu: Failed to enable requested dpm features!
amdgpu: resume of IP block <smu> failed -62
Apply the same workaround for soc24: detect the aborted-suspend state at resume via the sign-of-life register and reset the device before re-init.
This is a workaround till a proper solution is finalized.
--- drivers/gpu/drm/amd/amdgpu/soc24.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
drivers/gpu/drm/amd/amdgpu/soc24.c +28 -0
@@ -515,8 +515,36 @@ static int soc24_common_suspend(struct areturn soc24_common_hw_fini (ip_block); } +static bool soc24_need_reset_on_resume (struct amdgpu_device *adev) +{ +u32 sol_reg1, sol_reg2; + +/* Will reset for the following suspend abort cases. +* 1) Only reset dGPU side. +* 2) S3 suspend got aborted and TOS is active. +* As for dGPU suspend abort cases the SOL value +* will be kept as zero at this resume point. +*/ +if (!(adev->flags &AMD_IS_APU ) && adev->in_s3) { + sol_reg1 =RREG32_SOC15 (MP0 ,0 , regMPASP_SMN_C2PMSG_81); +msleep (100 ); + sol_reg2 =RREG32_SOC15 (MP0 ,0 , regMPASP_SMN_C2PMSG_81); + +return (sol_reg1 != sol_reg2); + } + +return false; +} +static int soc24_common_resume (struct amdgpu_ip_block *ip_block) { +struct amdgpu_device *adev = ip_block->adev; + +if (soc24_need_reset_on_resume (adev)) { +dev_info (adev->dev,"S3 suspend aborted, resetting..." ); +soc24_asic_reset (adev); + } +return soc24_common_hw_init (ip_block); }
Greg Kroah-Hartman
maintainerPATCH 435/744 drm/amdgpu/gfx11: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 0eebcab1ea2a77f086a04108f386f82ee3496022 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +5 -8
@@ -542,7 +542,7 @@ static void gfx_v11_0_wait_reg_mem(struc WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -5953,7 +5953,7 @@ static void gfx_v11_0_ring_emit_ib_gfx(s }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5988,7 +5988,7 @@ static void gfx_v11_0_ring_emit_ib_compu }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -6021,9 +6021,9 @@ static void gfx_v11_0_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -6077,9 +6077,6 @@ static void gfx_v11_0_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 436/744 drm/amd/amdgpu: disable ASPM on VI if pcie dpm is disabled
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kenneth Feng <[email protected]>
commit 18a7826aea6fd09f2d371c02cec70c7234fc4879 upstream.
Disable ASPM on VI if PCIE dpm is disabled.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +2 -1
@@ -1328,7 +1328,8 @@ static bool amdgpu_device_aspm_support_q* It's unclear if this is a platform-specific or GPU-specific issue. * Disable ASPM on SI for the time being. */ -if (adev->family ==AMDGPU_FAMILY_SI ) +if (adev->family ==AMDGPU_FAMILY_SI || + (!(adev->pm.pp_feature &PP_PCIE_DPM_MASK ) && adev->family ==AMDGPU_FAMILY_VI ))return true;#if IS_ENABLED (CONFIG_X86 )
Greg Kroah-Hartman
maintainerPATCH 437/744 drm/amdgpu: fix lifetime issue of amdgpu_vm_get_task_info_pasid()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shahyan Soltani <[email protected]>
commit 04cc4aa3617b0ed67e859f91f09de5d896a46f3a upstream.
The vm pointer returned from amdgpu_vm_get_vm_from_pasid() is only valid while the lock is still being held. Once xa_unlock_irqrestore is called and returned, the pointer is no longer under lock and is subject to modification. Since, the caller still dereferences vm->task_info in amdgpu_vm_get_task_info_vm() after the lock is removed, this causes a use after unlock problem.
Remove the lifetime issue present in amdgpu_vm_get_task_info_pasid() through removing the amdgpu_vm_get_vm_from_pasid() function from amdgpu_vm.c and making the relevant code inline to hold the lock while it is still in use.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +10 -15
@@ -2487,19 +2487,6 @@ static void amdgpu_vm_destroy_task_info(kfree (ti); } -static inline struct amdgpu_vm * -amdgpu_vm_get_vm_from_pasid (struct amdgpu_device *adev,u32 pasid) -{ -struct amdgpu_vm *vm; -unsigned long flags; - -xa_lock_irqsave (&adev->vm_manager.pasids, flags); - vm =xa_load (&adev->vm_manager.pasids, pasid); -xa_unlock_irqrestore (&adev->vm_manager.pasids, flags); - -return vm; -} -/** * amdgpu_vm_put_task_info - reference down the vm task_info ptr *
@@ -2546,8 +2533,16 @@ amdgpu_vm_get_task_info_vm(struct amdgpustruct amdgpu_task_info *amdgpu_vm_get_task_info_pasid (struct amdgpu_device *adev,u32 pasid) { -return amdgpu_vm_get_task_info_vm ( -amdgpu_vm_get_vm_from_pasid (adev, pasid)); +struct amdgpu_task_info *ti; +struct amdgpu_vm *vm; +unsigned long flags; + +xa_lock_irqsave (&adev->vm_manager.pasids, flags); + vm =xa_load (&adev->vm_manager.pasids, pasid); + ti =amdgpu_vm_get_task_info_vm (vm); +xa_unlock_irqrestore (&adev->vm_manager.pasids, flags); + +return ti; }static int amdgpu_vm_create_task_info (struct amdgpu_vm *vm)
Greg Kroah-Hartman
maintainerPATCH 438/744 drm/amdgpu: trigger GPU recovery when userq destroy fails to unmap a hung queue
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <[email protected]>
commit 614e8a989d462876c4f6a659f56e1075e72ad515 upstream.
Destroying a hung user queue issues a MES REMOVE_QUEUE that times out, The destroy path only logged the error and freed the queue, so the
next userq submission failed and forced a GPU reset attributed to an innocent workload.
Kick the userq reset work when unmap fails so the GPU is recovered at destroy time.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +9 -0
@@ -523,6 +523,15 @@ amdgpu_userq_destroy(struct amdgpu_userqamdgpu_userq_cleanup (queue);mutex_unlock (&uq_mgr->userq_mutex); +/* +* A failed unmap means MES could not remove the hung queue and is now +* unresponsive. Recover the GPU here so the wedged MES does not fail +* the next, unrelated queue submission and trigger a reset attributed +* to an innocent workload. +*/ +if (r) +queue_work (adev->reset_domain->wq, &uq_mgr->reset_work); +cancel_delayed_work_sync (&queue->hang_detect_work); uq_funcs->mqd_destroy (queue); queue->userq_mgr =NULL ;
Greg Kroah-Hartman
maintainerPATCH 439/744 drm/i915/gem: Do not leak siblings[] on proto context error
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <[email protected]>
commit eed3de2acf6aa5154d49098b026710b646db67ee upstream.
After a successful BALANCE/PARALLEL_SUBMIT extension on context creation, error during processing of next user extension leaks the siblings[] array. Fix that.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/gem/i915_gem_context.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
drivers/gpu/drm/i915/gem/i915_gem_context.c +14 -8
@@ -769,8 +769,8 @@ static int set_proto_ctx_engines(structstruct intel_engine_cs *engine;if (copy_from_user (&ci, &user->engines[n],sizeof (ci))) { -kfree (set.engines); -return -EFAULT ; + err = -EFAULT ; + goto err; }memset (&set.engines[n],0 ,sizeof (set.engines[n]));
@@ -786,8 +786,8 @@ static int set_proto_ctx_engines(structdrm_dbg (&i915->drm,"Invalid engine[%d]: { class:%d, instance:%d }\n" , n, ci.engine_class, ci.engine_instance); -kfree (set.engines); -return -ENOENT ; + err = -ENOENT ; + goto err; } set.engines[n].type =I915_GEM_ENGINE_TYPE_PHYSICAL ;
@@ -800,15 +800,21 @@ static int set_proto_ctx_engines(struct set_proto_ctx_engines_extensions,ARRAY_SIZE (set_proto_ctx_engines_extensions), &set); -if (err) { -kfree (set.engines); -return err; - } +if (err) + goto err_extensions; pc->num_user_engines = set.num_engines; pc->user_engines = set.engines;return 0 ; + +err_extensions: +for (n =0 ; n < set.num_engines; n++) +kfree (set.engines[n].siblings); +err: +kfree (set.engines); + +return err; } static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
Greg Kroah-Hartman
maintainerPATCH 440/744 drm/i915/gem: Fix NULL deref in I915_CONTEXT_PARAM_SSEU
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <[email protected]>
commit 2b56757a9a7456825eb668fde92299e01c5e2721 upstream.
Setting context engine slot N into I915_ENGINE_CLASS_INVALID / I915_ENGINE_CLASS_INVALID_NONE and attempting to apply I915_CONTEXT_PARAM_SSEU to the same slot N will deref NULL. Fix that.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/gem/i915_gem_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gem/i915_gem_context.c +1 -1
@@ -856,7 +856,7 @@ static int set_proto_ctx_sseu(struct drm pe = &pc->user_engines[idx];/* Only render engine supports RPCS configuration. */ -if (pe->engine->class !=RENDER_CLASS ) +if (!pe->engine || pe->engine->class !=RENDER_CLASS )return -EINVAL ; sseu = &pe->sseu;
Greg Kroah-Hartman
maintainerPATCH 441/744 drm/i915/gt: Fix NULL deref on sched_engine alloc failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <[email protected]>
commit 82ec992c404c3dc774c5e9f3d4aa858e97187675 upstream.
Avoid using intel_context_put() before intel_context_init() in execlists_create_virtual() as the kref_put() inside would lead to NULL deref on the IOCTL path when sched_engine allocation fails.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
--- drivers/gpu/drm/i915/gt/intel_execlists_submission.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
drivers/gpu/drm/i915/gt/intel_execlists_submission.c +10 -9
@@ -3932,11 +3932,11 @@ execlists_create_virtual(struct intel_enstruct drm_i915_private *i915 = siblings[0 ]->i915;struct virtual_engine *ve;unsigned int n; -int err; +int err = -ENOMEM ; ve =kzalloc_flex (*ve, siblings, count);if (!ve) -return ERR_PTR (-ENOMEM ); + goto err; ve->base.i915 = i915; ve->base.gt = siblings[0 ]->gt;
@@ -3968,10 +3968,8 @@ execlists_create_virtual(struct intel_enintel_engine_init_execlists (&ve->base); ve->base.sched_engine =i915_sched_engine_create (ENGINE_VIRTUAL ); -if (!ve->base.sched_engine) { - err = -ENOMEM ; - goto err_put; - } +if (!ve->base.sched_engine) + goto err_noput; ve->base.sched_engine->private_data = &ve->base; ve->base.cops = &virtual_context_ops;
@@ -3987,10 +3985,8 @@ execlists_create_virtual(struct intel_enintel_context_init (&ve->context, &ve->base); ve->base.breadcrumbs =intel_breadcrumbs_create (NULL ); -if (!ve->base.breadcrumbs) { - err = -ENOMEM ; +if (!ve->base.breadcrumbs) goto err_put; - }for (n =0 ; n < count; n++) {struct intel_engine_cs *sibling = siblings[n];
@@ -4065,8 +4061,13 @@ execlists_create_virtual(struct intel_envirtual_engine_initial_hint (ve);return &ve->context; +err_noput: +kfree (ve); + goto err; + err_put:intel_context_put (&ve->context); +err:return ERR_PTR (err); }
Greg Kroah-Hartman
maintainerPATCH 442/744 drm/i915/mst: limit DP MST ESI service loop
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <[email protected]>
commit 005771c18c5b2c98cb4e7517661aea460990fd3f upstream.
The loop in intel_dp_check_mst_status() keeps servicing interrupts originating from the sink without bound. Add an upper bound to the new interrupts occurring during interrupt processing to not get stuck on potentially stuck sink devices. Use arbitrary 32 tries to clear incoming interrupts in one go.
Discovered using AI-assisted static analysis confirmed by Intel Product Security.
Note: The condition likely pre-dates the commit in the Fixes: tag, but this is about as far back as a backport has any chance of succeeding. Before that, the retry had a goto.
--- drivers/gpu/drm/i915/display/intel_dp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_dp.c +7 -1
@@ -5589,8 +5589,9 @@ intel_dp_check_mst_status(struct intel_dstruct intel_display *display =to_intel_display (intel_dp);bool force_retrain = intel_dp->link.force_retrain;bool reprobe_needed = false; +int tries =33 ; -for (;;) { +while (--tries) {u8 esi[4 ] = {};u8 ack[4 ] = {};bool new_irqs;
@@ -5633,6 +5634,11 @@ intel_dp_check_mst_status(struct intel_dbreak ; } +if (!tries) { +drm_dbg_kms (display->drm,"DPRX ESI not clearing, device may be stuck\n" ); + reprobe_needed = true; + } +return !reprobe_needed; }
Greg Kroah-Hartman
maintainerPATCH 443/744 drm/amd/pm: fix smu14 power limit range calculation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit e987eabc02646920cd13ab75902693e99735eca0 upstream.
SMU14 derives the default PPT limit from SocketPowerLimitAc/Dc, but MsgLimits.Power may expose a different firmware limit for the same PPT0 throttler. Using those values independently as fixed min/max bases can report an incorrect configurable power range.
Keep the socket power limit as the default value and as the fallback for current-limit queries. Calculate the reported range from both firmware values instead, using the lower value as the minimum base and the higher value as the maximum base before applying OD percentages.
--- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 28 ++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +16 -12
@@ -1621,19 +1621,23 @@ static int smu_v14_0_2_get_power_limit(s table_context->power_play_table;PPTable_t *pptable = table_context->driver_pptable;CustomSkuTable_t *skutable = &pptable->CustomSkuTable; -int16_t od_percent_upper =0 , od_percent_lower =0 ; +uint32_t pp_limit = smu->adev->pm.ac_power ? + skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0 ] : + skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0 ];uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0 ][POWER_SOURCE_AC ]; -uint32_t power_limit; +uint32_t min_limit =min_t (uint32_t, pp_limit, msg_limit); +uint32_t max_limit =max_t (uint32_t, pp_limit, msg_limit); +int16_t od_percent_upper =0 , od_percent_lower =0 ; +int ret; -if (smu_v14_0_get_current_power_limit (smu, &power_limit)) - power_limit = smu->adev->pm.ac_power ? - skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0 ] : - skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0 ]; +if (current_power_limit) { + ret =smu_v14_0_get_current_power_limit (smu, current_power_limit); +if (ret) + *current_power_limit = pp_limit; + } -if (current_power_limit) - *current_power_limit = power_limit;if (default_power_limit) - *default_power_limit = power_limit; + *default_power_limit = pp_limit;if (powerplay_table) { if (smu->od_enabled &&
@@ -1647,15 +1651,15 @@ static int smu_v14_0_2_get_power_limit(s }dev_dbg (smu->adev->dev,"od percent upper:%d, od percent lower:%d (default power: %d)\n" , - od_percent_upper, od_percent_lower, power_limit); + od_percent_upper, od_percent_lower, pp_limit);if (max_power_limit) { - *max_power_limit = msg_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /=100 ; }if (min_power_limit) { - *min_power_limit = power_limit * (100 + od_percent_lower); + *min_power_limit = min_limit * (100 + od_percent_lower); *min_power_limit /=100 ; }
Greg Kroah-Hartman
maintainerPATCH 444/744 drm/gfx10: Program DB_RING_CONTROL
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit f0262c3a3f14d60140f6b826d40d44edf62c36d6 upstream.
This is needed to allocate occlusion counters across both gfx pipes.
--- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +9 -0
@@ -5350,6 +5350,15 @@ static void gfx_v10_0_constants_init(strgfx_v10_0_get_tcc_info (adev); adev->gfx.config.pa_sc_tile_steering_override =gfx_v10_0_init_pa_sc_tile_steering_override (adev); +/* Program DB_RING_CONTROL for multiple GFX pipes +* Default power up value is 1. +* Possible values: +* 0 - split occlusion counters between gfx pipes +* 1 - all occlusion counters to pipe 0 +* 2 - all occlusion counters to pipe 1 +*/ +WREG32_FIELD15 (GC ,0 ,DB_RING_CONTROL ,COUNTER_CONTROL , + (adev->gfx.me.num_pipe_per_me >1 ) ?0 :1 );/* XXX SH_MEM regs */ /* where to put LDS, scratch, GPUVM in FSA64 space */
Greg Kroah-Hartman
maintainerPATCH 445/744 drm/virtio: Dont detach GEM from a non-created context
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Macnak <[email protected]>
commit d489a5305b9d5480d6fb97d5636f5f4b1e0b3827 upstream.
Applies the same treatment as commit 7cf6dd467e87 ("drm/virtio:
Don't attach GEM to a non-created context in gem_object_open()") to virtio_gpu_gem_object_close() to avoid trying to detach a resource that was never attached due to a context never being created when context_init is supported.
--- drivers/gpu/drm/virtio/virtgpu_gem.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
drivers/gpu/drm/virtio/virtgpu_gem.c +8 -6
@@ -139,13 +139,15 @@ void virtio_gpu_gem_object_close(structif (!vgdev->has_virgl_3d)return ; - objs =virtio_gpu_array_alloc (1 ); -if (!objs) -return ; -virtio_gpu_array_add_obj (objs, obj); +if (vfpriv->context_created) { + objs =virtio_gpu_array_alloc (1 ); +if (!objs) +return ; +virtio_gpu_array_add_obj (objs, obj); -virtio_gpu_cmd_context_detach_resource (vgdev, vfpriv->ctx_id, - objs); +virtio_gpu_cmd_context_detach_resource (vgdev, vfpriv->ctx_id, + objs); + }virtio_gpu_notify (vgdev); }
Greg Kroah-Hartman
maintainerPATCH 446/744 drm/gpusvm: publish dpagemap early to avoid device mapping leak on error
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Honglei Huang <[email protected]>
commit 7f708f51e3955bda0d77a0b67ab9bea6c97fea99 upstream.
drm_gpusvm_get_pages() only stored the local dpagemap into svm_pages->dpagemap on the success path. If a later page failed (e.g. -EOPNOTSUPP when ctx->allow_mixed is false) and jumped to err_unmap, svm_pages->dpagemap was still NULL, so __drm_gpusvm_unmap_pages() skipped device_unmap() and leaked the device mappings already created.
Assign svm_pages->dpagemap when the first device page is mapped so the err_unmap path can device_unmap() those mappings.
This issue was found by Sashiko AI review.
--- drivers/gpu/drm/drm_gpusvm.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/gpu/drm/drm_gpusvm.c +11 -5
@@ -1519,6 +1519,16 @@ map_pages: err = -EAGAIN ; goto err_unmap; } + +/* +* Set the dpagemap as soon as the first +* device page is mapped so the err_unmap path +* can device_unmap() the device mappings that +* have already been created. +*/ +drm_pagemap_get (dpagemap); +drm_pagemap_put (svm_pages->dpagemap); + svm_pages->dpagemap = dpagemap; } svm_pages->dma_addr[j] = dpagemap->ops->device_map(dpagemap,
@@ -1562,12 +1572,8 @@ map_pages: flags.has_dma_mapping = true; } -if (pagemap) { +if (pagemap) flags.has_devmem_pages = true; -drm_pagemap_get (dpagemap); -drm_pagemap_put (svm_pages->dpagemap); - svm_pages->dpagemap = dpagemap; - }/* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ WRITE_ONCE (svm_pages->flags.__flags, flags.__flags);
Greg Kroah-Hartman
maintainerPATCH 447/744 drm/ttm: Account for NULL and handle pages in ttm_pool_backup
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit 5b7b3b6595ee77d01c7463757baed114786094dd upstream.
Pages in ttm_pool_backup can be NULL or backup handles (ttm_backup_page_ptr_is_handle()), neither of which can be passed to set_pages_array_wb() or freed. Add a dedicated WB pass before the dma/purge loop that walks allocations using the same i += num_pages stride, skipping NULL and handle entries, and calls set_pages_array_wb() once per contiguous run of real pages. Apply the same NULL/handle guard to the dma/purge loop.
Fixes the following oops:
Oops: general protection fault, kernel NULL pointer dereference 0x0: 0000 [#1] SMP NOPTI RIP: 0010:__cpa_process_fault+0xf8/0x770 RSP: 0018:ffffc90000a87718 EFLAGS: 00010287 RAX: 0000000000000000 RBX: ffffc90000a87868 RCX: 0000000000000000 RDX: 0000000000001000 RSI: 0005088000000000 RDI: ffffffff827c5f34 RBP: 0005088000000000 R08: ffffc90000a877cb R09: ffffc90000a877d0 R10: 0000000000000000 R11: 000000000000001b R12: 000ffffffffff000 R13: ffffc90000a87868 R14: ffffc90000a87868 R15: ffff88815b882ae0 FS: 0000000000000000(0000) GS:ffff8884ec840000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f930b844000 CR3: 000000000262e003 CR4: 0000000008f70ef0 PKRU: 55555554 Call Trace: <TASK> __change_page_attr_set_clr+0x989/0xe90 ? __purge_vmap_area_lazy+0x6c/0x3a0 ? _vm_unmap_aliases+0x250/0x2a0 set_pages_array_wb+0x7f/0x120 ttm_pool_backup+0x4c9/0x5b0 [ttm] ? dma_resv_wait_timeout+0x3b/0xf0 ttm_tt_backup+0x32/0x60 [ttm] ttm_bo_shrink+0x66/0x110 [ttm] xe_bo_shrink_purge+0x12b/0x1b0 [xe] xe_bo_shrink+0xbb/0x270 [xe] __xe_shrinker_walk+0xf7/0x160 [xe] xe_shrinker_walk+0x9d/0xc0 [xe] xe_shrinker_scan+0x11f/0x210 [xe] do_shrink_slab+0x13b/0x270 shrink_slab+0xf1/0x400 shrink_node+0x352/0x8a0 balance_pgdat+0x32c/0x700 kswapd+0x205/0x2f0 ? __pfx_autoremove_wake_function+0x10/0x10 ? __pfx_kswapd+0x10/0x10 kthread+0xd1/0x110 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1b1/0x200 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>
--- drivers/gpu/drm/ttm/ttm_pool.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-)
drivers/gpu/drm/ttm/ttm_pool.c +30 -4
@@ -1051,9 +1051,31 @@ long ttm_pool_backup(struct ttm_pool *poreturn -EBUSY ;#ifdef CONFIG_X86 -/* Anything returned to the system needs to be cached. */ -if (tt->caching != ttm_cached) -set_pages_array_wb (tt->pages, tt->num_pages); +/* Anything returned to the system needs to be cached. Walk allocations +* skipping NULL pages and issue set_pages_array_wb() per contiguous run. +*/ +if (tt->caching != ttm_cached) { +pgoff_t run_start =0 , run_count =0 ; + +for (i =0 ; i < tt->num_pages; i += num_pages) { + page = tt->pages[i]; +if (unlikely (!page ||ttm_backup_page_ptr_is_handle (page))) { +if (run_count) { +set_pages_array_wb (&tt->pages[run_start], + run_count); + run_count =0 ; + } + num_pages =1 ; +continue ; + } + num_pages =1UL <<ttm_pool_page_order (pool, page); +if (!run_count) + run_start = i; + run_count += num_pages; + } +if (run_count) +set_pages_array_wb (&tt->pages[run_start], run_count); + }#endif if (tt->dma_address || flags->purge) {
@@ -1061,7 +1083,7 @@ long ttm_pool_backup(struct ttm_pool *pounsigned int order; page = tt->pages[i]; -if (unlikely (!page)) { +if (unlikely (!page ||ttm_backup_page_ptr_is_handle (page))) { num_pages =1 ;continue ; }
@@ -1104,6 +1126,10 @@ long ttm_pool_backup(struct ttm_pool *poif (unlikely (!page))continue ; +/* Already-handled entry from a previous attempt. */ +if (unlikely (ttm_backup_page_ptr_is_handle (page))) +continue ; +ttm_pool_split_for_swap (pool, page); shandle = ttm_backup_backup_page(backup, page, flags->writeback, i,
Greg Kroah-Hartman
maintainerPATCH 448/744 drm/panthor: return error on truncated firmware
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Osama Abdelkader <[email protected]>
commit 4a2c8cbe9bcba170706fdf08b1c84b6cbcf5b044 upstream.
panthor_fw_load() detects truncated firmware images, but jumps to the common cleanup path without setting ret. If no previous error was recorded, the function can return 0 and treat the invalid firmware as successfully loaded.
Set ret to -EINVAL before leaving the truncated-image path.
--- drivers/gpu/drm/panthor/panthor_fw.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/panthor/panthor_fw.c +1 -0
@@ -824,6 +824,7 @@ static int panthor_fw_load(struct pantho }if (hdr.size > iter.size) { + ret = -EINVAL ;drm_err (&ptdev->base,"Firmware image is truncated\n" ); goto out; }
Greg Kroah-Hartman
maintainerPATCH 449/744 drm/amdgpu: Release VFCT ACPI table reference
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit 65bff26617607c1331283232016c0e89088c5b78 upstream.
amdgpu_acpi_vfct_bios() fetches the VFCT table with acpi_get_table() but never releases it. acpi_get_table() takes a reference on the table (incrementing its validation_count and mapping it on the 0->1 transition); without a paired acpi_put_table() the mapping is leaked on every call, whether or not a matching VBIOS image is found.
Route all exit paths after the table is acquired through a common acpi_put_table(). The VBIOS image is copied out with kmemdup() before the table is released, so it remains valid for the caller.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +11 -6
@@ -377,13 +377,14 @@ static bool amdgpu_acpi_vfct_bios(structacpi_size tbl_size;UEFI_ACPI_VFCT *vfct;unsigned int offset; +bool r = false;if (!ACPI_SUCCESS (acpi_get_table ("VFCT" ,1 , &hdr)))return false; tbl_size = hdr->length;if (tbl_size <sizeof (UEFI_ACPI_VFCT )) {dev_info (adev->dev,"ACPI VFCT table present but broken (too short #1),skipping\n" ); -return false; + goto out; } vfct = (UEFI_ACPI_VFCT *)hdr;
@@ -396,13 +397,13 @@ static bool amdgpu_acpi_vfct_bios(struct offset +=sizeof (VFCT_IMAGE_HEADER );if (offset > tbl_size) {dev_info (adev->dev,"ACPI VFCT image header truncated,skipping\n" ); -return false; + goto out; } offset += vhdr->ImageLength;if (offset > tbl_size) {dev_info (adev->dev,"ACPI VFCT image truncated,skipping\n" ); -return false; + goto out; } if (vhdr->ImageLength &&
@@ -417,15 +418,19 @@ static bool amdgpu_acpi_vfct_bios(structif (!check_atom_bios (adev, vhdr->ImageLength)) {amdgpu_bios_release (adev); -return false; + goto out; } adev->bios_size = vhdr->ImageLength; - return true; + r = true; + goto out; } }dev_info (adev->dev,"ACPI VFCT table present but broken (too short #2),skipping\n" ); -return false; + +out: +acpi_put_table (hdr); +return r; }#else static inline bool amdgpu_acpi_vfct_bios (struct amdgpu_device *adev)
Greg Kroah-Hartman
maintainerPATCH 450/744 drm/amdgpu: Fix VFCT bus number matching with soft filter
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit db7e8108809a2245f0a17ba323f027cac0941ffb upstream.
On systems where PCI bus renumbering occurs (e.g. pci=realloc, resource conflicts), the runtime bus number may differ from the BIOS POST bus number recorded in the VFCT table. This causes amdgpu_acpi_vfct_bios() to fail finding the VBIOS even though the correct device entry exists.
Introduce amdgpu_acpi_vfct_match() which treats the bus number as a soft filter: vendor/device/function identity is the hard requirement, while exact bus match is the preferred path. When bus numbers disagree but device identity matches, accept the VFCT entry and log a dev_notice for diagnostics.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 45 +++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +40 -5
@@ -371,6 +371,45 @@ static bool amdgpu_read_disabled_bios(st }#ifdef CONFIG_ACPI +/** +* amdgpu_acpi_vfct_match() - Check if a VFCT entry matches the device +* @adev: AMDGPU device +* @vhdr: VFCT image header to check +* +* VFCT entries contain the PCI bus number as recorded during BIOS POST. +* On systems where the kernel renumbers PCI buses (e.g. pci=realloc or +* resource conflicts), the runtime bus number may differ from the POST +* value. Match by device identity (vendor + device + function) and use +* the bus number as a preference: exact bus match is preferred, but when +* the bus numbers disagree we accept the entry if the device identity +* matches. +* +* Returns: 0 on match, -ENODEV on no match +*/ +static int amdgpu_acpi_vfct_match (struct amdgpu_device *adev, +VFCT_IMAGE_HEADER *vhdr) +{ +/* Vendor and device IDs must always match */ +if (vhdr->VendorID != adev->pdev->vendor || + vhdr->DeviceID != adev->pdev->device) +return -ENODEV ; + +if (vhdr->PCIDevice !=PCI_SLOT (adev->pdev->devfn) || + vhdr->PCIFunction !=PCI_FUNC (adev->pdev->devfn)) +return -ENODEV ; + +/* Exact bus number match - preferred */ +if (vhdr->PCIBus == adev->pdev->bus->number) +return 0 ; + +/* Bus mismatch but device identity matches (PCI renumbering case) */ +dev_notice (adev->dev, +"VFCT bus number mismatch: table %u != runtime %u, matching by device identity (vendor 0x%04x device 0x%04x)\n" , + vhdr->PCIBus, adev->pdev->bus->number, + adev->pdev->vendor, adev->pdev->device); +return 0 ; +} +static bool amdgpu_acpi_vfct_bios (struct amdgpu_device *adev) {struct acpi_table_header *hdr;
@@ -407,11 +446,7 @@ static bool amdgpu_acpi_vfct_bios(struct }if (vhdr->ImageLength && - vhdr->PCIBus == adev->pdev->bus->number && - vhdr->PCIDevice ==PCI_SLOT (adev->pdev->devfn) && - vhdr->PCIFunction ==PCI_FUNC (adev->pdev->devfn) && - vhdr->VendorID == adev->pdev->vendor && - vhdr->DeviceID == adev->pdev->device) { + !amdgpu_acpi_vfct_match (adev, vhdr)) { adev->bios =kmemdup (&vbios->VbiosContent, vhdr->ImageLength,GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 451/744 drm/amdgpu/userq: fix indefinite fence wait during GPU reset
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <[email protected]>
commit 5d75ec2e5f1736c2f10c7d6f4565bf1bf29f29a7 upstream.
pre_reset only force-completes fences of MAPPED queues. A queue in any other state (e.g. mid-eviction) keeps its last_fence pending; after a GPU reset that fence never signals, so the eviction/suspend worker and process teardown (amdgpu_evf_mgr_flush_suspend) wait on it forever and wedge the machine:
INFO: task kworker/6:28 blocked for more than 120 seconds. Workqueue: events amdgpu_eviction_fence_suspend_worker [amdgpu] Call Trace: dma_fence_wait_timeout+0x7e/0x130 amdgpu_userq_evict+0x67/0x140 [amdgpu] amdgpu_eviction_fence_suspend_worker+0xd8/0x160 [amdgpu] process_scheduled_works+0xa6/0x420
Force-complete every queue's fence regardless of state. The unmap and mark-hung step stays gated on MAPPED, since unmapping a queue that is not mapped is invalid.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +12 -9
@@ -1376,16 +1376,19 @@ void amdgpu_userq_pre_reset(struct amdgp/* TODO: We probably need a new lock for the queue state */ xa_for_each (&adev->userq_doorbell_xa, queue_id, queue) { -if (queue->state !=AMDGPU_USERQ_STATE_MAPPED ) -continue ; - - userq_funcs = adev->userq_funcs[queue->queue_type]; - userq_funcs->unmap (queue); -/* just mark all queues as hung at this point. -* if unmap succeeds, we could map again -* in amdgpu_userq_post_reset() if vram is not lost +if (queue->state ==AMDGPU_USERQ_STATE_MAPPED ) { + userq_funcs = adev->userq_funcs[queue->queue_type]; + userq_funcs->unmap (queue); +/* just mark all queues as hung at this point. +* if unmap succeeds, we could map again +* in amdgpu_userq_post_reset() if vram is not lost +*/ + queue->state =AMDGPU_USERQ_STATE_HUNG ; + } +/* Force-complete any pending fence regardless of queue state so +* that eviction/suspend and queue teardown waiters don't block +* forever on a fence that will never signal after the reset. */ - queue->state =AMDGPU_USERQ_STATE_HUNG ;amdgpu_userq_fence_driver_force_completion (queue); } }
Greg Kroah-Hartman
maintainerPATCH 452/744 drm/amd: Create a device link between APU display and XHCI devices
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit 75c8746b9d0a0317d8a58aa0efa2ff2f7359908b upstream.
Some AMD APU multi-function devices expose an integrated USB xHCI controller. In some circumstances (such as larger VRAM), the PM core can resume can fail when the xHCI controller is resuming in parallel with the GPU/display function.
On affected systems, the xHCI controller can complete pci_pm_resume and start resuming USB devices while the GPU is still in its much longer resume path. This race condition leads to USB device resume failures followed by:
xhci_hcd ...: xHCI host not responding to stop endpoint command xhci_hcd ...: HC died; cleaning up
Create a device link from any xHCI controller sharing the same PCIe root port as the APU display function. The link uses DL_FLAG_STATELESS and DL_FLAG_PM_RUNTIME to ensure the GPU completes its resume before the xHCI controller begins resuming USB devices.
This device link is done specifically in amdgpu so that if the platform firmware has been modified such that this issue doesn't happen the version can be detected and the workaround skipped.
--- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 12 +++++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 12 ++++- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 45 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +12 -0
@@ -1365,6 +1365,14 @@ static void smu_feature_cap_init(structbitmap_zero (fea_cap->cap_map,SMU_FEATURE_CAP_ID__COUNT ); } +static int smu_set_power_dep (struct smu_context *smu,bool enable) +{ +if (!smu->ppt_funcs->set_power_dep) +return 0 ; + +return smu->ppt_funcs->set_power_dep (smu, enable); +} +static int smu_sw_init (struct amdgpu_ip_block *ip_block) {struct amdgpu_device *adev = ip_block->adev;
@@ -1426,6 +1434,8 @@ static int smu_sw_init(struct amdgpu_ip_if (!smu->ppt_funcs->get_fan_control_mode) smu->adev->pm.no_fan = true; +smu_set_power_dep (smu, true); +return 0 ; }
@@ -1448,6 +1458,8 @@ static int smu_sw_fini(struct amdgpu_ip_smu_fini_microcode (smu); +smu_set_power_dep (smu, false); +return 0 ; }
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +11 -1
@@ -749,6 +749,9 @@ struct smu_context {bool pm_enabled;bool is_apu; +/* Power dependency link from an integrated xHCI controller to the GPU */ +struct device_link *usb_power_link; +uint32_t smc_driver_if_version;uint32_t smc_fw_if_version;uint32_t smc_fw_version;
@@ -1648,12 +1651,19 @@ struct pptable_funcs {int (*ras_send_msg)(struct smu_context *smu,enum smu_message_type msg,uint32_t param,uint32_t *read_arg); -/** * @get_ras_smu_drv: Get RAS smu driver interface * Return: ras_smu_drv * */ int (*get_ras_smu_drv)(struct smu_context *smu,const struct ras_smu_drv **ras_smu_drv); + +/** +* @set_power_dep: Create or destroy a power dependency link +* from an integrated xHCI controller to the GPU so that the GPU is +* resumed before the USB controller during PM resume. @enable is true +* to create the link and false to tear it down. +*/ +int (*set_power_dep)(struct smu_context *smu,bool enable); }; typedef enum {
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +45 -0
57 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 453/744 drm/amd/pm/ci: Dont disable MCLK DPM on Bonaire 0x6658 (R7 260X)
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit 85371c5ef502d10add72eab38711e191dccea981 upstream.
The old radeon driver has a documented workaround in ci_dpm.c which claims that Bonaire 0x6658 with old memory controller firmware is unstable with MCLK DPM, so as a precaution I disabled MCLK DPM on this ASIC in amdgpu.
Note that the old MC firmware is not actually used with amdgpu, but in theory it's possible that the VBIOS sets up the ASIC with an old MC firmware that is already running when amdgpu initializes (in which case amdgpu doesn't load its own firmware).
What I expected to happen is that the GPU would simply use its maximum memory clock, and indeed this is what seemed to happen according to amdgpu_pm_info which reads the current MCLK value from the SMU.
However, some users reported a huge perf regression and upon a closer look it seems that the GPU seems to not actually use the highest MCLK value, despite the SMU reporting that it does.
Let's not disable MCLK DPM on Bonaire 0x6658 (R7 260X).
Keep MCLK DPM disabled on R9 M380 in the 2015 iMac because that still hangs if we enable it.
--- drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +2 -5
@@ -106,11 +106,8 @@ int hwmgr_early_init(struct pp_hwmgr *hw hwmgr->od_enabled = false;switch (hwmgr->chip_id) {case CHIP_BONAIRE : -/* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM -* R7 260X cards with old MC ucode: MCLK DPM is unstable -*/ -if (adev->pdev->subsystem_vendor ==0x106B || - adev->pdev->device ==0x6658 ) { +/* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM */ +if (adev->pdev->subsystem_vendor ==0x106B ) {dev_info (adev->dev,"disabling MCLK DPM on quirky ASIC" ); adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK ; hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK ;
Greg Kroah-Hartman
maintainerPATCH 454/744 drm/amd/display: set new_stream to NULL after release
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: WenTao Liang <[email protected]>
commit 9fa26b9eed6195bf840f39ac183b9a6237548755 upstream.
In dm_update_crtc_state(), the skip_modeset path releases new_stream via dc_stream_release() but does not set the pointer to NULL.
If a later error (e.g., color management failure) triggers the fail label, the error path calls dc_stream_release() again on the same dangling pointer, causing a double release and potential use-after-free.
Fix this by setting new_stream to NULL after the initial release.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +1 -0
@@ -11715,6 +11715,7 @@ skip_modeset:/* Release extra reference */ if (new_stream)dc_stream_release (new_stream); + new_stream =NULL ;/* * We want to do dc stream updates that do not require a
Greg Kroah-Hartman
maintainerPATCH 455/744 drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Li <[email protected]>
commit 8382cd234981ae36299bb66a10bac2cd8ff1b99d upstream.
[Why]
On DCN, vblank events were delivered from VSTARTUP/VUPDATE (dm_crtc_high_irq/dm_vupdate_high_irq) and pageflip completion from GRPH_PFLIP (dm_pflip_high_irq). These signals can be masked by hardware by a few things:
* DPG - DCN can Dynamically Power Gate parts of the display pipe when a self-refresh capable eDP is connected. DPG is engaged when there's enough static frames (detected through drm_vblank_off). Once gated, even though the OTG (output timing generator) is still enabled, VSTARTUP and GRPH_FLIP are masked.
* GSL - Driver can use the Global Sync Lock to block HW from latching onto double-buffered registers during programming, to prevent HW from latching onto a partially programmed state. This will mask VSTARTUP, GRPH_FLIP, and VUPDATE. See dcn20_pipe_control_lock().
* MALL - A DCN accessible cache introduced in DCN32+ DGPUs that can store fb data to allow for longer DRAM sleep. When scanning out from MALL, VSTARTUP is masked.
When masked, events are never delivered, which can show up as flip_done timeouts in the wild.
However, there is an interrupt source on DCN that is never masked:VUPDATE_NO_LOCK. It's simply an unmasked variant of VUPDATE, which fires while the OTG is active, at the exact point hardware latches double-buffered registers. It is therefore the natural single signal for delivering both vblank and flip-completion events on DCN, and the correct point to timestamp both VRR and non-VRR vblanks.
DCE's interrupt sources are different, it does not have an unmaskable VUPDATE_NO_LOCK. The only unmaskable DCE interrupt is VLINE0, but it can only be programmed as a vline offset from vsync_start, making it unsuitable for VRR. Thus, we keep DCE untouched and use the existing mix of interrupt sources.
[How]
For DCN1 and newer only:
* Factor the body of dm_crtc_high_irq() into dm_crtc_high_irq_handler() and drive it from dm_vupdate_high_irq() (VUPDATE_NO_LOCK). DCE keeps using dm_crtc_high_irq() (VSTARTUP) and dm_pflip_high_irq() (GRPH_PFLIP) unchanged.
* Stop registering VSTARTUP (crtc_irq) and GRPH_PFLIP (pageflip_irq) on DCN, and stop enabling them in amdgpu_dm_crtc_set_vblank() / manage_dm_interrupts(). Enable VUPDATE whenever vblank is enabled on DCN (previously only in VRR mode). The secure-display vline0 interrupt is left untouched.
* VUPDATE_NO_LOCK does not early-fire on an immediate (tearing / async) flip, since HW latches the new address right away. Deliver the flip completion event immediately after programming such flips in amdgpu_dm_commit_planes(), and clear pflip_status so the next vupdate handler does not double-send.
v2: Do not gate VUPDATE_NO_LOCK on DCN in dm_handle_vrr_transition()
Also toggle VUPDATE_NO_LOCK on DCN in dm_gpureset_toggle_interrupts() Re-cook vblank event count and timestamp for immediate flips
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 349 +++++++++-------- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 70 ++- 2 files changed, 229 insertions(+), 190 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +187 -162
@@ -576,89 +576,25 @@ static void schedule_dc_vmin_vmax(structqueue_work (system_percpu_wq, &offload_work->work); } -static void dm_vupdate_high_irq (void *interrupt_params) -{ -struct common_irq_params *irq_params = interrupt_params; -struct amdgpu_device *adev = irq_params->adev; -struct amdgpu_crtc *acrtc; -struct drm_device *drm_dev; -struct drm_vblank_crtc *vblank; -ktime_t frame_duration_ns, previous_timestamp; -unsigned long flags; -int vrr_active; - - acrtc =get_crtc_by_otg_inst (adev, irq_params->irq_src -IRQ_TYPE_VUPDATE ); - -if (acrtc) { - vrr_active =amdgpu_dm_crtc_vrr_active_irq (acrtc); - drm_dev = acrtc->base.dev; - vblank =drm_crtc_vblank_crtc (&acrtc->base); - previous_timestamp =atomic64_read (&irq_params->previous_timestamp); - frame_duration_ns = vblank->time - previous_timestamp; - -if (frame_duration_ns >0 ) { -trace_amdgpu_refresh_rate_track (acrtc->base.index, - frame_duration_ns, -ktime_divns (NSEC_PER_SEC , frame_duration_ns)); -atomic64_set (&irq_params->previous_timestamp, vblank->time); - } - -drm_dbg_vbl (drm_dev, -"crtc:%d, vupdate-vrr:%d\n" , acrtc->crtc_id, - vrr_active); - -/* Core vblank handling is done here after end of front-porch in -* vrr mode, as vblank timestamping will give valid results -* while now done after front-porch. This will also deliver -* page-flip completion events that have been queued to us -* if a pageflip happened inside front-porch. -*/ -if (vrr_active && acrtc->dm_irq_params.stream) { -bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; -bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; -bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state - ==VRR_STATE_ACTIVE_VARIABLE ; - -amdgpu_dm_crtc_handle_vblank (acrtc); - -/* BTR processing for pre-DCE12 ASICs */ -if (adev->family <AMDGPU_FAMILY_AI ) { -spin_lock_irqsave (&adev_to_drm (adev)->event_lock, flags); -mod_freesync_handle_v_update ( - adev->dm.freesync_module, - acrtc->dm_irq_params.stream, - &acrtc->dm_irq_params.vrr_params); - -if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { -schedule_dc_vmin_vmax (adev, - acrtc->dm_irq_params.stream, - &acrtc->dm_irq_params.vrr_params.adjust); - } -spin_unlock_irqrestore (&adev_to_drm (adev)->event_lock, flags); - } - } - } -} -/** -* dm_crtc_high_irq() - Handles CRTC interrupt -* @interrupt_params: used for determining the CRTC instance +* dm_crtc_high_irq_handler() - Common OTG vblank/flip event handling +* @adev: amdgpu device +* @acrtc: the CRTC to service * -* Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK -* event handler. +* Performs writeback completion, vblank event handling, CRC processing, VRR BTR +* updates and pageflip completion delivery. +* +* On DCN this is driven by VUPDATE_NO_LOCK (the register latch point) from +* dm_vupdate_high_irq(); on DCE it is driven by VLINE0 at the start of vblank +* from dm_crtc_high_irq(). */ -static void dm_crtc_high_irq (void *interrupt_params) +static void dm_crtc_high_irq_handler (struct amdgpu_device *adev, +struct amdgpu_crtc *acrtc) { -struct common_irq_params *irq_params = interrupt_params; -struct amdgpu_device *adev = irq_params->adev;struct drm_writeback_job *job; -struct amdgpu_crtc *acrtc;unsigned long flags;int vrr_active; - - acrtc =get_crtc_by_otg_inst (adev, irq_params->irq_src -IRQ_TYPE_VBLANK ); -if (!acrtc) -return ; +bool is_dcn =amdgpu_ip_version (adev,DCE_HWIP ,0 ) !=0 ;if (acrtc->wb_conn) {spin_lock_irqsave (&acrtc->wb_conn->job_lock, flags);
@@ -695,12 +631,17 @@ static void dm_crtc_high_irq(void *inter vrr_active, acrtc->dm_irq_params.active_planes);/** -* Core vblank handling at start of front-porch is only possible -* in non-vrr mode, as only there vblank timestamping will give -* valid results while done in front-porch. Otherwise defer it -* to dm_vupdate_high_irq after end of front-porch. +* Core vblank handling. +* +* On DCN this handler runs at VUPDATE_NO_LOCK, the register latch +* point, which is the correct place to timestamp both VRR and non-VRR +* vblanks. +* +* On DCE this handler runs at the start of front-porch, where only +* non-VRR timestamping is valid; VRR vblank is deferred to +* dm_vupdate_high_irq() after end of front-porch. */ -if (!vrr_active) +if (is_dcn || !vrr_active)amdgpu_dm_crtc_handle_vblank (acrtc);/**
@@ -733,18 +674,16 @@ static void dm_crtc_high_irq(void *inter }/* -* If there aren't any active_planes then DCH HUBP may be clock-gated. -* In that case, pageflip completion interrupts won't fire and pageflip -* completion events won't get delivered. Prevent this by sending -* pending pageflip events from here if a flip is still pending. +* Deliver pageflip completion events (DCN only). * -* If any planes are enabled, use dm_pflip_high_irq() instead, to -* avoid race conditions between flip programming and completion, -* which could cause too early flip completion events. -*/ -if (adev->family >=AMDGPU_FAMILY_RV && - acrtc->pflip_status ==AMDGPU_FLIP_SUBMITTED && - acrtc->dm_irq_params.active_planes ==0 ) { +* Since GRPH_PFLIP is not used, VUPDATE_NO_LOCK is the flip latch +* point. Deliver any pending pageflip completion event from here. +* +* NOTE: This can deliver an event for a flip that was armed but not yet +* programmed into HW; that race is closed in a follow-up change by +* checking the programmed flip status. +*/ +if (is_dcn && acrtc->pflip_status ==AMDGPU_FLIP_SUBMITTED ) {if (acrtc->event) {drm_crtc_send_vblank_event (&acrtc->base, acrtc->event); acrtc->event =NULL ;
@@ -756,6 +695,104 @@ static void dm_crtc_high_irq(void *interspin_unlock_irqrestore (&adev_to_drm (adev)->event_lock, flags); } +static void dm_vupdate_high_irq (void *interrupt_params) +{ +struct common_irq_params *irq_params = interrupt_params; +struct amdgpu_device *adev = irq_params->adev; +struct amdgpu_crtc *acrtc; +struct drm_device *drm_dev; +struct drm_vblank_crtc *vblank; +ktime_t frame_duration_ns, previous_timestamp; +unsigned long flags; +int vrr_active; + + acrtc =get_crtc_by_otg_inst (adev, irq_params->irq_src -IRQ_TYPE_VUPDATE ); +if (!acrtc) +return ; + + vrr_active =amdgpu_dm_crtc_vrr_active_irq (acrtc); + drm_dev = acrtc->base.dev; + vblank =drm_crtc_vblank_crtc (&acrtc->base); + previous_timestamp =atomic64_read (&irq_params->previous_timestamp); + frame_duration_ns = vblank->time - previous_timestamp; + +if (frame_duration_ns >0 ) { +trace_amdgpu_refresh_rate_track (acrtc->base.index, + frame_duration_ns, +ktime_divns (NSEC_PER_SEC , frame_duration_ns)); +atomic64_set (&irq_params->previous_timestamp, vblank->time); + } + +drm_dbg_vbl (drm_dev, +"crtc:%d, vupdate-vrr:%d\n" , acrtc->crtc_id, + vrr_active); + +/* +* On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver +* vblank and pageflip completion events; VSTARTUP and GRPH_PFLIP are +* not used. Run the full handler here. +*/ +if (amdgpu_ip_version (adev,DCE_HWIP ,0 ) !=0 ) { +dm_crtc_high_irq_handler (adev, acrtc); +return ; + } + +/* DCE only below. */ + +/* Core vblank handling is done here after end of front-porch in +* vrr mode, as vblank timestamping will give valid results +* while now done after front-porch. This will also deliver +* page-flip completion events that have been queued to us +* if a pageflip happened inside front-porch. +*/ +if (vrr_active && acrtc->dm_irq_params.stream) { +bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; +bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; +bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state + ==VRR_STATE_ACTIVE_VARIABLE ; + +amdgpu_dm_crtc_handle_vblank (acrtc); + +/* BTR processing for pre-DCE12 ASICs */ +if (adev->family <AMDGPU_FAMILY_AI ) { +spin_lock_irqsave (&adev_to_drm (adev)->event_lock, flags); +mod_freesync_handle_v_update ( + adev->dm.freesync_module, + acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params); + +if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { +schedule_dc_vmin_vmax (adev, + acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params.adjust); + } +spin_unlock_irqrestore (&adev_to_drm (adev)->event_lock, flags); + } + } +} + +/** +* dm_crtc_high_irq() - Handles CRTC interrupt +* @interrupt_params: used for determining the CRTC instance +* +* Handles the CRTC/VSYNC interrupt by notifying DRM's VBLANK event handler. +* +* Used on DCE (VLINE0, set to vblank start). On DCN the equivalent handling is +* driven by VUPDATE_NO_LOCK in dm_vupdate_high_irq(). +*/ +static void dm_crtc_high_irq (void *interrupt_params) +{ +struct common_irq_params *irq_params = interrupt_params; +struct amdgpu_device *adev = irq_params->adev; +struct amdgpu_crtc *acrtc; + + acrtc =get_crtc_by_otg_inst (adev, irq_params->irq_src -IRQ_TYPE_VBLANK ); +if (!acrtc) +return ; + +dm_crtc_high_irq_handler (adev, acrtc); +} +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY )/** * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
@@ -3169,6 +3206,13 @@ static void dm_gpureset_toggle_interrupt*/ if (!dc_interrupt_set (adev->dm.dc, irq_source, enable))drm_warn (adev_to_drm (adev),"Failed to %sable vblank interrupt\n" , enable ?"en" :"dis" ); + + }else if (acrtc && state->stream_status[i].plane_count !=0 ) { +/* DCN only needs to toggle VUPDATE_NO_LOCK */ + rc =amdgpu_dm_crtc_set_vupdate_irq (&acrtc->base, enable); +if (rc) +drm_warn (adev_to_drm (adev),"Failed to %sable vupdate interrupt\n" , + enable ?"en" :"dis" ); } }
@@ -4734,38 +4778,6 @@ static int dcn10_register_irq_handlers(s* for acknowledging and handling. */ -/* Use VSTARTUP interrupt */ -for (i =DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP ; - i <=DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc -1 ; - i++) { - r =amdgpu_irq_add_id (adev,SOC15_IH_CLIENTID_DCE , i, &adev->crtc_irq); - -if (r) { -drm_err (adev_to_drm (adev),"Failed to add crtc irq id!\n" ); -return r; - } - - int_params.int_context =INTERRUPT_HIGH_IRQ_CONTEXT ; - int_params.irq_source = -dc_interrupt_to_irq_source (dc, i,0 ); - -if (int_params.irq_source ==DC_IRQ_SOURCE_INVALID || - int_params.irq_source <DC_IRQ_SOURCE_VBLANK1 || - int_params.irq_source >DC_IRQ_SOURCE_VBLANK6 ) { -drm_err (adev_to_drm (adev),"Failed to register vblank irq!\n" ); -return -EINVAL ; - } - - c_irq_params = &adev->dm.vblank_params[int_params.irq_source -DC_IRQ_SOURCE_VBLANK1 ]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - -if (!amdgpu_dm_irq_register_interrupt (adev, &int_params, - dm_crtc_high_irq, c_irq_params)) -return -ENOMEM ; - } -/* Use otg vertical line interrupt */ #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY )for (i =0 ; i <= adev->mode_info.num_crtc -1 ; i++) {
@@ -4837,37 +4849,6 @@ static int dcn10_register_irq_handlers(sreturn -ENOMEM ; } -/* Use GRPH_PFLIP interrupt */ -for (i =DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT ; - i <=DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num -1 ; - i++) { - r =amdgpu_irq_add_id (adev,SOC15_IH_CLIENTID_DCE , i, &adev->pageflip_irq); -if (r) { -drm_err (adev_to_drm (adev),"Failed to add page flip irq id!\n" ); -return r; - } - - int_params.int_context =INTERRUPT_HIGH_IRQ_CONTEXT ; - int_params.irq_source = -dc_interrupt_to_irq_source (dc, i,0 ); - -if (int_params.irq_source ==DC_IRQ_SOURCE_INVALID || - int_params.irq_source <DC_IRQ_SOURCE_PFLIP_FIRST || - int_params.irq_source >DC_IRQ_SOURCE_PFLIP_LAST ) { -drm_err (adev_to_drm (adev),"Failed to register pflip irq!\n" ); -return -EINVAL ; - } - - c_irq_params = &adev->dm.pflip_params[int_params.irq_source -DC_IRQ_SOURCE_PFLIP_FIRST ]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - -if (!amdgpu_dm_irq_register_interrupt (adev, &int_params, - dm_pflip_high_irq, c_irq_params)) -return -ENOMEM ; - } -/* HPD */ r =amdgpu_irq_add_id (adev,SOC15_IH_CLIENTID_DCE ,DCN_1_0__SRCID__DC_HPD1_INT , &adev->hpd_irq);
@@ -9448,14 +9429,22 @@ static void manage_dm_interrupts(structdrm_crtc_vblank_on_config (&acrtc->base, &config); -/* Allow RX6xxx, RX7700, RX7800 GPUs to call amdgpu_irq_get.*/ +/* +* Since pflip_high_irq is no longer registered for DCN, grab an +* extra reference to vupdate irq instead to workaround this +* issue: +* https://gitlab.freedesktop.org/drm/amd/-/work_items/3936 +* +* The callbacks to drm_vblank_on/off should really take care of +* this though. +*/ switch (amdgpu_ip_version (adev,DCE_HWIP ,0 )) {case IP_VERSION (3 ,0 ,0 ):case IP_VERSION (3 ,0 ,2 ):case IP_VERSION (3 ,0 ,3 ):case IP_VERSION (3 ,2 ,0 ): -if (amdgpu_irq_get (adev, &adev->pageflip_irq, irq_type)) -drm_err (dev,"DM_IRQ: Cannot get pageflip irq!\n" ); +if (amdgpu_irq_get (adev, &adev->vupdate_irq, irq_type)) +drm_err (dev,"DM_IRQ: Cannot get vupdate irq!\n" );#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY )if (amdgpu_irq_get (adev, &adev->vline0_irq, irq_type))drm_err (dev,"DM_IRQ: Cannot get vline0 irq!\n" );
@@ -9473,8 +9462,8 @@ static void manage_dm_interrupts(structif (amdgpu_irq_put (adev, &adev->vline0_irq, irq_type))drm_err (dev,"DM_IRQ: Cannot put vline0 irq!\n" );#endif -if (amdgpu_irq_put (adev, &adev->pageflip_irq, irq_type)) -drm_err (dev,"DM_IRQ: Cannot put pageflip irq!\n" ); +if (amdgpu_irq_put (adev, &adev->vupdate_irq, irq_type)) +drm_err (dev,"DM_IRQ: Cannot put vupdate irq!\n" ); }drm_crtc_vblank_off (&acrtc->base);
@@ -9487,6 +9476,10 @@ static void dm_update_pflip_irq_state(stint irq_type =amdgpu_display_crtc_idx_to_irq_type (adev, acrtc->crtc_id); +/* GRPH_PFLIP is not used on DCN; nothing to reapply. */ +if (amdgpu_ip_version (adev,DCE_HWIP ,0 ) !=0 ) +return ; +/** * This reads the current state for the IRQ and force reapplies * the setting to hardware.
@@ -9818,9 +9811,13 @@ static void update_stream_irq_parametersstatic void amdgpu_dm_handle_vrr_transition (struct dm_crtc_state *old_state,struct dm_crtc_state *new_state) { +struct amdgpu_device *adev =drm_to_adev (new_state->base.crtc->dev);bool old_vrr_active =amdgpu_dm_crtc_vrr_active (old_state);bool new_vrr_active =amdgpu_dm_crtc_vrr_active (new_state); +/* Only DCE gates vupdate on VRR, keep it enabled for DCN */ +bool vrr_gates_vupdate =amdgpu_ip_version (adev,DCE_HWIP ,0 ) ==0 ; +if (!old_vrr_active && new_vrr_active) {/* Transition VRR inactive -> active: * While VRR is active, we must not disable vblank irq, as a
@@ -9830,7 +9827,8 @@ static void amdgpu_dm_handle_vrr_transit* We also need vupdate irq for the actual core vblank handling * at end of vblank. */ -WARN_ON (amdgpu_dm_crtc_set_vupdate_irq (new_state->base.crtc, true) !=0 ); +if (vrr_gates_vupdate) +WARN_ON (amdgpu_dm_crtc_set_vupdate_irq (new_state->base.crtc, true) !=0 );WARN_ON (drm_crtc_vblank_get (new_state->base.crtc) !=0 );drm_dbg_driver (new_state->base.crtc->dev,"%s: crtc=%u VRR off->on: Get vblank ref\n" , __func__, new_state->base.crtc->base.id);
@@ -9838,7 +9836,8 @@ static void amdgpu_dm_handle_vrr_transit/* Transition VRR active -> inactive: * Allow vblank irq disable again for fixed refresh rate. */ -WARN_ON (amdgpu_dm_crtc_set_vupdate_irq (new_state->base.crtc, false) !=0 ); +if (vrr_gates_vupdate) +WARN_ON (amdgpu_dm_crtc_set_vupdate_irq (new_state->base.crtc, false) !=0 );drm_crtc_vblank_put (new_state->base.crtc);drm_dbg_driver (new_state->base.crtc->dev,"%s: crtc=%u VRR on->off: Drop vblank ref\n" , __func__, new_state->base.crtc->base.id);
@@ -10014,6 +10013,7 @@ static void amdgpu_dm_commit_planes(strubool vrr_active =amdgpu_dm_crtc_vrr_active (acrtc_state);bool cursor_update = false;bool pflip_present = false; +bool immediate_flip = false;bool dirty_rects_changed = false;bool updated_planes_and_streams = false;struct {
@@ -10180,6 +10180,8 @@ static void amdgpu_dm_commit_planes(stru acrtc_state->update_type ==UPDATE_TYPE_FAST &&get_mem_type (old_plane_state->fb) ==get_mem_type (fb); + immediate_flip |= bundle->flip_addrs[planes_count].flip_immediate; + timestamp_ns =ktime_get_ns (); bundle->flip_addrs[planes_count].flip_timestamp_in_us =div_u64 (timestamp_ns,1000 ); bundle->surface_updates[planes_count].flip_addr = &bundle->flip_addrs[planes_count];
@@ -10381,6 +10383,29 @@ static void amdgpu_dm_commit_planes(stru acrtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE)amdgpu_dm_commit_cursors (state); +/* +* On DCN, flip completion is normally delivered from VUPDATE_NO_LOCK. +* However, an immediate (tearing / async) flip is latched by HW right +* away and does not wait for the next vupdate, so deliver its +* completion event here after programming. +* +* On DCE, GRPH_PFLIP already fires immediately for immediate flips, so +* this is DCN-only. +*/ +if (immediate_flip &&amdgpu_ip_version (dm->adev,DCE_HWIP ,0 ) !=0 ) { +spin_lock_irqsave (&pcrtc->dev->event_lock, flags); +if (acrtc_attach->pflip_status ==AMDGPU_FLIP_SUBMITTED && + acrtc_attach->event) { +drm_crtc_accurate_vblank_count (&acrtc_attach->base); +drm_crtc_send_vblank_event (&acrtc_attach->base, + acrtc_attach->event); + acrtc_attach->event =NULL ; +drm_crtc_vblank_put (&acrtc_attach->base); + acrtc_attach->pflip_status =AMDGPU_FLIP_NONE ; + } +spin_unlock_irqrestore (&pcrtc->dev->event_lock, flags); + } + cleanup:kfree (bundle); }
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +42 -28
85 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 456/744 drm/amd/display: dce100: skip non-DP stream encoders for DP MST
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andriy Korud <[email protected]>
commit d340cba0df4cf327c7e89c7c1a4e79d4771d7dd5 upstream.
On DCE8-class ASICs (e.g. Bonaire), the resource pool contains digital DIG stream encoders plus one analog DAC encoder. When assigning a stream encoder for a second DisplayPort MST stream, if the preferred digital encoder is already acquired, dce100_find_first_free_match_stream_enc_for_link() falls back to the first free pool entry. That entry may be the analog encoder, whose funcs table lacks DP hooks such as dp_set_stream_attribute. The subsequent atomic commit then dereferences NULL function pointers in link_set_dpms_on() and crashes.
Skip encoders without dp_set_stream_attribute when the stream uses a DP signal (including MST). Use dc_is_dp_signal(stream->signal) for the MST fallback path instead of checking only the link connector signal.
Tested on:
- GPU: AMD Radeon R7 260X (Bonaire / DCE8)
- Board: Supermicro C9X299-PG300
- Setup: DP MST daisy chain, hotplug second monitor or have it connected on boot
- Kernel: 7.1.3 (issue observed since 6.19)
- Result: kernel oops without patch; dual monitors stable with patch
--- drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +6 -1
@@ -992,6 +992,11 @@ struct stream_encoder *dce100_find_firstfor (i =0 ; i < pool->stream_enc_count; i++) {if (!res_ctx->is_stream_enc_acquired[i] && pool->stream_enc[i]) { +/* DP/MST needs a digital encoder; skip analog/no-DP encoders */ +if (dc_is_dp_signal (stream->signal) && + (!pool->stream_enc[i]->funcs || + !pool->stream_enc[i]->funcs->dp_set_stream_attribute)) +continue ;/* Store first available for MST second display * in daisy chain use case */
@@ -1014,7 +1019,7 @@ struct stream_encoder *dce100_find_first* required for non DP connectors. */ -if (j >=0 && link->connector_signal ==SIGNAL_TYPE_DISPLAY_PORT ) +if (j >=0 &&dc_is_dp_signal (stream->signal))return pool->stream_enc[j];return NULL ;
Greg Kroah-Hartman
maintainerPATCH 457/744 drm/amd/display: Force PWM backlight on Lenovo Legion 5 15ARH05
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alessandro Rinaldi <[email protected]>
commit bad177fa75e607e396cd57daaaed881450d7a471 upstream.
The Lenovo Legion 5 15ARH05 (Renoir) ships a BOE 0x08DF eDP panel that advertises AUX/DPCD backlight control, so amdgpu's automatic detection (amdgpu_backlight == -1) selects AUX. On this panel the AUX backlight path has no effect: brightness writes are accepted but the panel level never changes, the display is stuck at a fixed brightness and max_brightness is reported as a bogus 511000. As a result neither the desktop brightness slider nor the brightness hotkeys do anything.
Forcing PWM backlight (amdgpu.backlight=0) restores working control:max_brightness becomes 65535 and the level tracks writes. This has long been applied by users as a manual kernel-parameter workaround.
Extend the generic panel backlight quirk with a force_pwm flag, add an entry for the Legion 5 15ARH05 / BOE 0x08DF panel, and have amdgpu disable AUX backlight (use PWM) when the quirk matches and the user lets the driver auto-select the backlight type.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++-- drivers/gpu/drm/drm_panel_backlight_quirks.c | 9 +++++++++ include/drm/drm_utils.h | 1 + 3 files changed, 15 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +5 -2
@@ -3984,6 +3984,8 @@ static void update_connector_ext_caps(st caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; caps->aux_support = false; + panel_backlight_quirk =drm_get_panel_backlight_quirk (aconnector->drm_edid); +if (caps->ext_caps->bits.oled ==1 /* * ||
@@ -3996,6 +3998,9 @@ static void update_connector_ext_caps(st caps->aux_support = false; else if (amdgpu_backlight == 1) caps->aux_support = true; + else if (!IS_ERR_OR_NULL(panel_backlight_quirk) && + panel_backlight_quirk->force_pwm) + caps->aux_support = false; if (caps->aux_support) aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX;
@@ -4011,8 +4016,6 @@ static void update_connector_ext_caps(stelse caps->aux_min_input_signal =1 ; - panel_backlight_quirk = -drm_get_panel_backlight_quirk (aconnector->drm_edid);if (!IS_ERR_OR_NULL (panel_backlight_quirk)) {if (panel_backlight_quirk->min_brightness) { caps->min_input_signal =
drivers/gpu/drm/drm_panel_backlight_quirks.c +9 -0
@@ -21,6 +21,15 @@ struct drm_get_panel_backlight_quirk { };static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks[] = { +/* Lenovo Legion 5 15ARH05, AUX backlight non-functional, force PWM */ + { + .dmi_match.field =DMI_SYS_VENDOR , + .dmi_match.value ="LENOVO" , + .dmi_match_other.field =DMI_PRODUCT_VERSION , + .dmi_match_other.value ="Lenovo Legion 5 15ARH05" , + .ident.panel_id =drm_edid_encode_panel_id ('B' ,'O' ,'E' ,0x08df ), + .quirk = { .force_pwm = true, }, + },/* 13 inch matte panel */ { .dmi_match.field =DMI_BOARD_VENDOR ,
include/drm/drm_utils.h +1 -0
@@ -19,6 +19,7 @@ int drm_get_panel_orientation_quirk(intstruct drm_panel_backlight_quirk {u16 min_brightness;u32 brightness_mask; +bool force_pwm; }; const struct drm_panel_backlight_quirk *
Greg Kroah-Hartman
maintainerPATCH 458/744 drm/amd/display: Fix backlight max_brightness to match exported range
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit f1b5d8f9cc54ae8a2567ac126867ae488e1bf625 upstream.
[Why]
FWTS autobrightness fails on eDP panels because actual_brightness can read higher than the advertised max_brightness (e.g. 63576 vs 62451).
The conversion helpers expose the firmware PWM range to userspace as [0..max]. But max_brightness is advertised as (max - min), which is smaller. So reading the level can return a value above max_brightness.
This regressed in commit 4b61b8a39051 ("drm/amd/display: Add debugging message for brightness caps"), which changed max_brightness to (max - min) and undid commit 8dbd72cb7900 ("drm/amd/display: Export full brightness range to userspace").
[How]
Advertise max_brightness as max, and scale the initial AC/DC brightness against max too. Update the KUnit expectations to match.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +3 -3
@@ -5383,11 +5383,11 @@ amdgpu_dm_register_backlight_device(stru caps = &dm->backlight_caps[aconnector->bl_idx];if (get_brightness_range (caps, &min, &max)) {if (power_supply_is_system_supplied () >0 ) - props.brightness =DIV_ROUND_CLOSEST ((max - min) * caps->ac_level,100 ); + props.brightness =DIV_ROUND_CLOSEST (max * caps->ac_level,100 );else - props.brightness =DIV_ROUND_CLOSEST ((max - min) * caps->dc_level,100 ); + props.brightness =DIV_ROUND_CLOSEST (max * caps->dc_level,100 );/* min is zero, so max needs to be adjusted */ - props.max_brightness = max - min; + props.max_brightness = max;drm_dbg (drm,"Backlight caps: min: %d, max: %d, ac %d, dc %d\n" , min, max, caps->ac_level, caps->dc_level); }else
Greg Kroah-Hartman
maintainerPATCH 459/744 drm/amdgpu: Disable PCIe dynamic speed switching on Ryzen Pinnacle Ridge
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit 0148ac33547b9af1c5a7f3bb6e5baffcb6e9fac2 upstream.
AMD Ryzen Pinnacle Ridge (Zen+, family 0x17 model 0x08) CPUs have PCI controllers that don't support PCIe dynamic speed switching, causing system freezes during GPU initialization when enabled.
Disable dynamic speed switching when this CPU is detected.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +9 -0
@@ -1318,6 +1318,15 @@ static bool amdgpu_device_pcie_dynamic_sif (c->x86_vendor ==X86_VENDOR_INTEL )return false; + +/* +* AMD Ryzen Pinnacle Ridge (Zen+, family 0x17 model 0x08) CPUs don't +* support PCIe dynamic speed switching. +* https://gitlab.freedesktop.org/drm/amd/-/work_items/5436 +*/ +if (c->x86_vendor ==X86_VENDOR_AMD && c->x86 ==0x17 && + c->x86_model ==0x08 ) +return false;#endif return true; }
Greg Kroah-Hartman
maintainerPATCH 460/744 drm/amdgpu: fix bo->pin leaking in amdgpu_bo_create_reserved
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhu Lingshan <[email protected]>
commit a2f895f3c852063258d62e9f74b081de07ca95df upstream.
amdgpu_bo_create_reserved() only allocates a new BO when *bo_ptr (struct amdgpu_bo **bo_ptr as input parameter) is NULL, it simply skips creation when *bo_ptr is non-NULL. But it unconditionally reserves, pins, gart allocates and maps the BO afterwards.
When the same non-NULL BO pointer is passed in again,
for example firmware buffers that live in adev and are re-loaded on every resume / cp_resume / start
under AMDGPU_FW_LOAD_DIRECT, amdgpu_bo_pin() just increases pin_count unconditionally, however the matching teardown only unpins once, so pin_count never drops to zero, so TTM is not able to move, swap or evict a BO, causing BO leaks.
This commit fixes this issue by only pinning the bo once at creation, and repeated calls no longer take additional pin references.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +8 -5
@@ -276,10 +276,12 @@ int amdgpu_bo_create_reserved(struct amd goto error_free; } - r =amdgpu_bo_pin (*bo_ptr, domain); -if (r) { -dev_err (adev->dev,"(%d) kernel bo pin failed\n" , r); - goto error_unreserve; +if (free) { + r =amdgpu_bo_pin (*bo_ptr, domain); +if (r) { +dev_err (adev->dev,"(%d) kernel bo pin failed\n" , r); + goto error_unreserve; + } } r =amdgpu_ttm_alloc_gart (&(*bo_ptr)->tbo);
@@ -302,7 +304,8 @@ int amdgpu_bo_create_reserved(struct amdreturn 0 ; error_unpin: -amdgpu_bo_unpin (*bo_ptr); +if (free) +amdgpu_bo_unpin (*bo_ptr); error_unreserve:amdgpu_bo_unreserve (*bo_ptr);
Greg Kroah-Hartman
maintainerPATCH 461/744 drm/amdgpu: Print vmid, pasid and more task info in devcoredump
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
commit ea9d70db278957e1e81e4aea58b4b131ba262cfb upstream.
These are in the dmesg logs but are missing from devcoredumps.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 7 ++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +6 -1
@@ -240,10 +240,14 @@ amdgpu_devcoredump_format(char *buffer,drm_printf (&p,"kernel: " UTS_RELEASE "\n" );drm_printf (&p,"module: " KBUILD_MODNAME "\n" );drm_printf (&p,"time: %ptSp\n" , &coredump->reset_time); +drm_printf (&p,"pasid: %u\n" , coredump->pasid); +drm_printf (&p,"vmid: %u\n" , coredump->vmid);if (coredump->reset_task_info.task.pid) -drm_printf (&p,"process_name: %s PID: %d\n" , +drm_printf (&p,"process_name: %s TGID: %d thread: %s PID: %d\n" , coredump->reset_task_info.process_name, + coredump->reset_task_info.tgid, + coredump->reset_task_info.task.comm, coredump->reset_task_info.task.pid);/* SOC Information */
@@ -525,6 +529,7 @@ void amdgpu_coredump(struct amdgpu_devicamdgpu_vm_put_task_info (ti); } coredump->pasid = job->pasid; + coredump->vmid = job->vmid; coredump->num_ibs = job->num_ibs;for (i =0 ; i < job->num_ibs; ++i) { coredump->ibs[i].gpu_addr = job->ibs[i].gpu_addr;
drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h +1 -0
@@ -63,6 +63,7 @@ struct amdgpu_coredump_info {char *formatted;unsigned int pasid; +unsigned int vmid;int num_ibs; struct amdgpu_coredump_ib_info ibs[] __counted_by(num_ibs); };
Greg Kroah-Hartman
maintainerPATCH 462/744 drm/amdgpu: always emit the job vm fence
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit b2ff0595c31cce4303957dd0058e14c89eb70152 upstream.
We need the fence to reemit the gds switch or spm update after a queue reset.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +4 -6
@@ -865,12 +865,10 @@ void amdgpu_vm_flush(struct amdgpu_ring job->oa_size); } -if (vm_flush_needed || pasid_mapping_needed || cleaner_shader_needed) { -amdgpu_fence_emit (ring, job->hw_vm_fence,0 ); - fence = &job->hw_vm_fence->base; -/* get a ref for the job */ -dma_fence_get (fence); - } +amdgpu_fence_emit (ring, job->hw_vm_fence,0 ); + fence = &job->hw_vm_fence->base; +/* get a ref for the job */ +dma_fence_get (fence);if (vm_flush_needed) {mutex_lock (&id_mgr->lock);
Greg Kroah-Hartman
maintainerPATCH 463/744 drm/amd/display: Fix flip-done timeouts on mode1 reset
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Li <[email protected]>
commit 82730dba0cf9d9524af0ceeb7eb6b5c3ab1bdb87 upstream.
The vblank on/off callbacks mixed use of amdgpu_irq_get/put() and amdgpu_dm_crtc_set_vupdate_irq() to enable and disable IRQs.
With get/put, base driver will callback into DC to disable IRQs when refcount == 0. With set_vupdate_irq(), DC is called directly to disable IRQs, bypassing base driver's refcount tracking.
During gpu reset, base driver can restore IRQs via amdgpu_irq_gpu_reset_resume_helper() > amdgpu_irq_update(). So if get/put() is not used (i.e. refcount == 0), then vupdate_irq will be disabled.
This is problematic if DRM requests vblank on before amdgpu_irq_update() is called: drm_vblank_on() > set_vupdate_irq() enables vupdate_irq, but the refcount is still 0. gpu_reset_resume_helper() > irq_update() then immediately disables it, thus leading to flip done timeouts.
This is made worse on DCN since VUPDATE_NO_LOCK is the only IRQ enabled. Prior to 8382cd234981, a combination of GRPH_FLIP and VSTARTUP IRQs were used, and they used get/put(). This explains why 8382cd234981 exposed this issue.
Fix by using get/put() instead of set_vupdate_irq(). DCE is unchanged, since it relies on unbalanced enable/disable calls based on VRR status, and hence requires direct set_vupdate_irq(). Plus, it also uses GRPH_FLIP and VLINE IRQs, which are properly tracked by get/put().
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +11 -2
@@ -314,10 +314,19 @@ static inline int amdgpu_dm_crtc_set_vbl* is enabled. On DCE, vupdate is only needed in VRR mode. */ if (amdgpu_ip_version (adev,DCE_HWIP ,0 ) !=0 ) { - rc =amdgpu_dm_crtc_set_vupdate_irq (crtc, enable); +if (enable) { + rc =amdgpu_irq_get (adev, &adev->vupdate_irq, irq_type); +drm_dbg_vbl (crtc->dev,"Get vupdate_irq ret=%d\n" , rc); + }else { + rc =amdgpu_irq_put (adev, &adev->vupdate_irq, irq_type); +drm_dbg_vbl (crtc->dev,"Put vupdate_irq ret=%d\n" , rc); + } }else if (dc_supports_vrr (dm->dc->ctx->dce_version)) {if (enable) { -/* vblank irq on -> Only need vupdate irq in vrr mode */ +/* vblank irq on -> Only need vupdate irq in vrr mode +* Not ref-counted since we need explicit enable/disable +* for DCE VRR handling +*/ if (amdgpu_dm_crtc_vrr_active (acrtc_state)) rc =amdgpu_dm_crtc_set_vupdate_irq (crtc, true); }else {
Greg Kroah-Hartman
maintainerPATCH 464/744 drm/vc4: Shut down BO cache timer before teardown
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
commit 6273dd3ffb54ec581855b82ae77331b66028249c upstream.
The BO cache timer callback schedules time_work, and time_work can rearm the timer through vc4_bo_cache_free_old().
vc4_bo_cache_destroy() deletes the timer and then cancels the work, which does not break that cycle: the work being cancelled can rearm the timer, and the timer then queues work again after teardown.
Use timer_shutdown_sync() instead, so the timer cannot be rearmed and the cycle ends with cancel_work_sync().
--- drivers/gpu/drm/vc4/vc4_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_bo.c +1 -1
@@ -1045,7 +1045,7 @@ static void vc4_bo_cache_destroy(structstruct vc4_dev *vc4 =to_vc4_dev (dev);int i; -timer_delete (&vc4->bo_cache.time_timer); +timer_shutdown_sync (&vc4->bo_cache.time_timer);cancel_work_sync (&vc4->bo_cache.time_work);vc4_bo_cache_purge (dev);
Greg Kroah-Hartman
maintainerPATCH 465/744 drm/amd/display: Fix missing DCE check in dm_gpureset_toggle_interrupts()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Li <[email protected]>
commit fbbaca9e208733652828ea98d00f09f260a7770e upstream.
This line was lost when cping from amd-staging-drm-next to drm-fixes. So add it back.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -1
@@ -3178,7 +3178,8 @@ static void dm_gpureset_toggle_interrupt acrtc =get_crtc_by_otg_inst ( adev, state->stream_status[i].primary_otg_inst); -if (acrtc && state->stream_status[i].plane_count !=0 ) { +if (acrtc && state->stream_status[i].plane_count !=0 && +amdgpu_ip_version (adev,DCE_HWIP ,0 ) ==0 ) { irq_source =IRQ_TYPE_PFLIP + acrtc->otg_inst; rc =dc_interrupt_set (adev->dm.dc, irq_source, enable) ?0 : -EBUSY ;if (rc)
Greg Kroah-Hartman
maintainerPATCH 466/744 drm/pagemap: Clear driver-provided PFNs from migration PFN array
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit 1f1be4ba643fb67410d753111c37ae42a2e2a814 upstream.
DRM pagemap overloads the migration PFN array to store driver-provided PFNs before calling migrate_vma_*() to finalize the migration. If an error occurs during the incremental copy phase, the migration PFN entries are reverted to their original state. After reverting the device-folio mutations, clear any remaining driver-provided PFNs to avoid confusing the migrate_vma_*() helpers.
Also clear any driver-provided PFNs if populate_devmem_pfn() fails, as a precaution against stale entries being interpreted as migration PFNs.
--- drivers/gpu/drm/drm_pagemap.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/drm_pagemap.c +8 -3
@@ -628,8 +628,10 @@ int drm_pagemap_migrate_to_devmem(struct } err = ops->populate_devmem_pfn (devmem_allocation, npages, migrate.dst); -if (err) - goto err_aborted_migration; +if (err) { + npages =0 ; + goto err_finalize; + } own_pages =0 ;
@@ -710,8 +712,11 @@ next:msecs_to_jiffies (mdetails->timeslice_ms); err_finalize: -if (err) +if (err) {drm_pagemap_migration_unlock_put_pages (npages, migrate.dst); +for (i = npages; i <npages_in_range (start, end); ++i) + migrate.dst[i] =0 ; + } err_aborted_migration:migrate_vma_pages (&migrate);
Greg Kroah-Hartman
maintainerPATCH 467/744 drm/vmwgfx: Validate vmw_surface_metadata::array_size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Forbes <[email protected]>
commit a4f55260f7f7d4dc4d0ee55063dfb0c457b77991 upstream.
This field comes from userspace and should be validated against specific limits depending on which Shader Model (SM) is available.
--- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +17 -5
@@ -78,7 +78,7 @@ static int vmw_gb_surface_unbind(structstatic int vmw_gb_surface_destroy (struct vmw_resource *res);static int vmw_gb_surface_define_internal (struct drm_device *dev, -struct drm_vmw_gb_surface_create_ext_req *req, +const struct drm_vmw_gb_surface_create_ext_req *req,struct drm_vmw_gb_surface_create_rep *rep,struct drm_file *file_priv); static int
@@ -1503,7 +1503,7 @@ int vmw_gb_surface_reference_ext_ioctl(s*/ static int vmw_gb_surface_define_internal (struct drm_device *dev, -struct drm_vmw_gb_surface_create_ext_req *req, +const struct drm_vmw_gb_surface_create_ext_req *req,struct drm_vmw_gb_surface_create_rep *rep,struct drm_file *file_priv) {
@@ -1521,9 +1521,21 @@ vmw_gb_surface_define_internal(struct dr req->base.svga3d_flags);/* array_size must be null for non-GL3 host. */ -if (req->base.array_size >0 && !has_sm4_context (dev_priv)) { -VMW_DEBUG_USER ("SM4 surface not supported.\n" ); -return -EINVAL ; +if (req->base.array_size >0 ) { +if (has_sm5_context (dev_priv)) { +if (req->base.array_size >SVGA3D_SM5_MAX_SURFACE_ARRAYSIZE ) { +VMW_DEBUG_USER ("Invalid Surface Array Size.\n" ); +return -EINVAL ; + } + }else if (has_sm4_context (dev_priv)) { +if (req->base.array_size >SVGA3D_SM4_MAX_SURFACE_ARRAYSIZE ) { +VMW_DEBUG_USER ("Invalid Surface Array Size.\n" ); +return -EINVAL ; + } + }else { +VMW_DEBUG_USER ("SM4+ surface not supported.\n" ); +return -EINVAL ; + } }if (!has_sm4_1_context (dev_priv)) {
Greg Kroah-Hartman
maintainerPATCH 468/744 drm/vc4: Prevent shader BO mappings from becoming writable
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
commit 0c9e6367639548307d3f578f6943ce72c9d39087 upstream.
vc4_gem_object_mmap() rejects a writable mapping of a validated shader BO, but leaves VM_MAYWRITE set. Userspace can map the BO read-only and then turn it writable with mprotect().
Validated shader BOs must stay read-only: the validator checks the instructions once and the GPU trusts them afterwards. A writable mapping lets userspace rewrite the code after validation, bypassing the validator.
Clear VM_MAYWRITE on the read-only path so the mapping cannot be upgraded, as i915 already does for its read-only objects.
--- drivers/gpu/drm/vc4/vc4_bo.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/gpu/drm/vc4/vc4_bo.c +7 -3
@@ -733,9 +733,13 @@ static int vc4_gem_object_mmap(struct dr {struct vc4_bo *bo =to_vc4_bo (obj); -if (bo->validated_shader && (vma->vm_flags &VM_WRITE )) { -DRM_DEBUG ("mmapping of shader BOs for writing not allowed.\n" ); -return -EINVAL ; +if (bo->validated_shader) { +if (vma->vm_flags &VM_WRITE ) { +DRM_DEBUG ("mmapping of shader BOs for writing not allowed.\n" ); +return -EINVAL ; + } + +vm_flags_clear (vma,VM_MAYWRITE ); }mutex_lock (&bo->madv_lock);
Greg Kroah-Hartman
maintainerPATCH 469/744 drm/pagemap: Guard HPAGE_PMD_ORDER use with CONFIG_ARCH_ENABLE_THP_MIGRATION
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit 04b177544a040cbafab760d6b766381c6b22e0a8 upstream.
HPAGE_PMD_SHIFT expands to BUILD_BUG() when CONFIG_PGTABLE_HAS_HUGE_LEAVES is not set, causing a compile error when both CONFIG_TRANSPARENT_HUGEPAGE and CONFIG_HUGETLB_PAGE are disabled:
drivers/gpu/drm/drm_pagemap.c:480:12: error: call to '__compiletime_assert_458' declared with 'error' attribute: BUILD_BUG failed
480 | order = HPAGE_PMD_ORDER;
| ^
include/linux/huge_mm.h:117:26: note: expanded from macro 'HPAGE_PMD_ORDER'
117 | #define HPAGE_PMD_ORDER (HPAGE_PMD_SHIFT-PAGE_SHIFT)
| ^
include/linux/huge_mm.h:113:28: note: expanded from macro 'HPAGE_PMD_SHIFT'
113 | #define HPAGE_PMD_SHIFT ({ BUILD_BUG(); 0; })
Define DRM_PAGEMAP_PMD_ORDER, which maps to HPAGE_PMD_ORDER when CONFIG_ARCH_ENABLE_THP_MIGRATION is enabled and to -1 otherwise.
This is safe because all code paths that use DRM_PAGEMAP_PMD_ORDER are reachable only when CONFIG_ARCH_ENABLE_THP_MIGRATION is enabled.
--- drivers/gpu/drm/drm_pagemap.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/gpu/drm/drm_pagemap.c +10 -3
@@ -12,6 +12,12 @@#include <drm/drm_pagemap_util.h> #include <drm/drm_print.h> +#if IS_ENABLED (CONFIG_ARCH_ENABLE_THP_MIGRATION ) +#define DRM_PAGEMAP_PMD_ORDER HPAGE_PMD_ORDER +#else +#define DRM_PAGEMAP_PMD_ORDER (-1) +#endif +/** * DOC: Overview *
@@ -480,7 +486,7 @@ static int drm_pagemap_cpages(unsigned l order =folio_order (folio); cpages +=NR_PAGES (order); }else if (migrate_pfn[i] &MIGRATE_PFN_COMPOUND ) { - order =HPAGE_PMD_ORDER ; + order =DRM_PAGEMAP_PMD_ORDER ; cpages +=NR_PAGES (order); }
@@ -670,10 +676,11 @@ int drm_pagemap_migrate_to_devmem(structif (migrate.src[i] &MIGRATE_PFN_COMPOUND ) {drm_WARN_ONCE (dpagemap->drm, src_page && -folio_order (page_folio (src_page)) !=HPAGE_PMD_ORDER , +folio_order (page_folio (src_page)) != +DRM_PAGEMAP_PMD_ORDER ,"Unexpected folio order\n" ); - order =HPAGE_PMD_ORDER ; + order =DRM_PAGEMAP_PMD_ORDER ; migrate.dst[i] |=MIGRATE_PFN_COMPOUND ;for (j =1 ; j <NR_PAGES (order) && i + j < npages; j++)
Greg Kroah-Hartman
maintainerPATCH 470/744 drm/ttm/pool: back up at native page order
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit a3fdf74ffa5966e5b4a17f1e9c5687f73bb0d536 upstream.
ttm_pool_split_for_swap() unconditionally splits high-order pool pages into order-0 pages before backup, so every compound the shrinker touches is shattered even when the rest of the system would prefer it stay intact. Under sustained kswapd pressure this fragments memory enough to drive other parts of MM into recovery loops.
Back up each compound at its native order instead. In ttm_pool_backup(), hand the full compound to the new ttm_backup_backup_folio(), which backs up subpages to a contiguous range of shmem indices and returns the base handle plus the number of subpages actually backed up (@nr_backed). On full success, free the compound once at its native order -- no split_page(), no per-4K refcount juggling.
A per-folio backup can't be made fully atomic under memory pressure:ttm_backup_backup_folio() must allocate shmem folios before source subpages can be released, so under true OOM any subpage may fail while the rest of the compound is still live. Two mechanisms handle this without regressing reclaim behaviour:
- alloc_gfp gets __GFP_NOMEMALLOC whenever order > 0 (cleared again for order-0), so a high-order backup fails fast with -ENOMEM instead of draining kernel reserves, leaving them for other allocations under the same pressure.
- If ttm_backup_backup_folio() still returns a short @nr_backed with a valid handle for the successfully-backed prefix, split the source compound with ttm_pool_split_for_swap(), free the prefix as order-0 pages (already safely in shmem), and retry the remaining subpages at order 0, where __GFP_NOMEMALLOC is cleared and reserves may be used as a last resort.
This preserves the original split-on-OOM fallback while keeping the common case fragmentation-free, and preserves the "partial backup is allowed" contract (shrunken is incremented per subpage backed up).
The restore-side leftover-page split in ttm_pool_restore_commit() is left as-is: it's unreachable in practice and not worth complicating the restore state machine to avoid.
Testing: the existing backup_fault_inject point only truncated tt->num_pages, which never exercised the reactive split path above since it never left a compound partially backed up. Wire fault injection into ttm_backup_backup_folio() itself: past the first subpage of a compound, synthesize a -ENOMEM in place of shmem_read_folio_gfp() when should_fail() trips, producing the same short @nr_pages_backed a real failure would and forcing ttm_pool_backup() through the split-and-retry path. The fault_attr stays private to ttm_pool.c; ttm_backup.c reaches it through ttm_backup_fault_inject_folio(), declared in ttm_pool_internal.h.
While converting the writeback branch to operate on the whole folio, the unlock condition after shmem_writeout() also changed from if (ret) to if (ret == AOP_WRITEPAGE_ACTIVATE), matching the actual
contract: shmem_writeout()/swap_writeout() only leave the folio locked when returning AOP_WRITEPAGE_ACTIVATE; any other return (including a hard error from arch_prepare_to_swap()) means the folio was already unlocked internally. The old if (ret) check would have double- unlocked in that hard-error case.
--- drivers/gpu/drm/ttm/ttm_backup.c | 127 +++++++++++++++++++++----------- drivers/gpu/drm/ttm/ttm_pool.c | 89 ++++++++++++++++++---- drivers/gpu/drm/ttm/ttm_pool_internal.h | 8 ++ include/drm/ttm/ttm_backup.h | 12 +-- 4 files changed, 172 insertions(+), 64 deletions(-)
drivers/gpu/drm/ttm/ttm_backup.c +84 -43
@@ -6,9 +6,10 @@#include <drm/ttm/ttm_backup.h> #include <linux/export.h> -#include <linux/page-flags.h> #include <linux/swap.h> +#include "ttm_pool_internal.h" +/* * Need to map shmem indices to handle since a handle value * of 0 means error, following the swp_entry_t convention.
@@ -68,17 +69,23 @@ int ttm_backup_copy_page(struct file *ba }/** -* ttm_backup_backup_page() - Backup a page +* ttm_backup_backup_folio() - Backup a folio * @backup: The struct backup pointer to use. -* @page: The page to back up. -* @writeback: Whether to perform immediate writeback of the page. +* @folio: The folio to back up. +* @order: The allocation order of @folio. Since TTM allocates higher-order +* pages without __GFP_COMP, folio_nr_pages(@folio) would always +* return 1; the caller must pass the true order explicitly. +* @writeback: Whether to perform immediate writeback of the folio's pages. * This may have performance implications. -* @idx: A unique integer for each page and each struct backup. +* @idx: A unique integer for the first page of the folio and each struct backup. * This allows the backup implementation to avoid managing * its address space separately. -* @page_gfp: The gfp value used when the page was allocated. -* This is used for accounting purposes. +* @folio_gfp: The gfp value used when the folio was allocated. +* Currently unused. * @alloc_gfp: The gfp to be used when allocating memory. +* @nr_pages_backed: Output. On a successful return, set to the number of +* pages actually backed up, which may be less than (1 << @order) +* if an -ENOMEM was encountered mid-folio. * * Context: If called from reclaim context, the caller needs to * assert that the shrinker gfp has __GFP_FS set, to avoid
@@ -87,53 +94,87 @@ int ttm_backup_copy_page(struct file *ba* that the shrinker gfp has __GFP_IO set, since without it, * we're not allowed to start backup IO. * -* Return: A handle on success. Negative error code on failure. -* -* Note: This function could be extended to back up a folio and -* implementations would then split the folio internally if needed. -* Drawback is that the caller would then have to keep track of -* the folio size- and usage. +* Return: A handle for the first backed-up page on success (handles for +* subsequent pages follow sequentially). -ENOMEM if no pages could be backed +* up. Any other negative error code if a non-ENOMEM failure occurred; in that +* case any pages backed up so far are truncated before returning. */ s64 -ttm_backup_backup_page (struct file *backup,struct page *page, -bool writeback,pgoff_t idx,gfp_t page_gfp, -gfp_t alloc_gfp) +ttm_backup_backup_folio (struct file *backup,struct folio *folio, +unsigned int order,bool writeback,pgoff_t idx, +gfp_t folio_gfp,gfp_t alloc_gfp, +pgoff_t *nr_pages_backed) {struct address_space *mapping = backup->f_mapping; -unsigned long handle =0 ; +int nr_pages =1 << order;struct folio *to_folio; -int ret; +int ret, i; + + *nr_pages_backed =0 ; + +for (i =0 ; i < nr_pages; ) { +int to_nr, j; - to_folio =shmem_read_folio_gfp (mapping, idx, alloc_gfp); -if (IS_ERR (to_folio)) -return PTR_ERR (to_folio); - -folio_mark_accessed (to_folio); -folio_lock (to_folio); -folio_mark_dirty (to_folio); -copy_highpage (folio_file_page (to_folio, idx), page); - handle =ttm_backup_shmem_idx_to_handle (idx); - -if (writeback && !folio_mapped (to_folio) && -folio_clear_dirty_for_io (to_folio)) { -folio_set_reclaim (to_folio); - ret =shmem_writeout (to_folio,NULL ,NULL ); -if (!folio_test_writeback (to_folio)) -folio_clear_reclaim (to_folio);/* -* If writeout succeeds, it unlocks the folio. errors -* are otherwise dropped, since writeout is only best -* effort here. +* Only inject past the first subpage so *nr_pages_backed is +* always > 0 here, matching a genuine mid-compound -ENOMEM +* and driving the caller's reactive split fallback instead +* of an early, no-progress failure. */ -if (ret) +if (IS_ENABLED (CONFIG_FAULT_INJECTION ) && i && +ttm_backup_fault_inject_folio ()) + to_folio =ERR_PTR (-ENOMEM ); +else + to_folio =shmem_read_folio_gfp (mapping, idx + i, alloc_gfp); +if (IS_ERR (to_folio)) { +int err =PTR_ERR (to_folio); + +if (err == -ENOMEM && *nr_pages_backed) +return ttm_backup_shmem_idx_to_handle (idx); + +if (*nr_pages_backed) { +shmem_truncate_range (file_inode (backup), + (loff_t )idx <<PAGE_SHIFT , + ((loff_t)(idx + i) <<PAGE_SHIFT ) -1 ); +/* +* The pages just truncated are no longer +* backed up; don't let the caller mistake +* them for valid handles. +*/ + *nr_pages_backed =0 ; + } +return err; + } + + to_nr =min_t (int, nr_pages - i, +folio_next_index (to_folio) - (idx + i)); + +folio_mark_accessed (to_folio); +folio_lock (to_folio); +folio_mark_dirty (to_folio); + +for (j =0 ; j < to_nr; j++) +copy_highpage (folio_file_page (to_folio, idx + i + j), +folio_page (folio, i + j)); + +if (writeback && !folio_mapped (to_folio) && +folio_clear_dirty_for_io (to_folio)) { +folio_set_reclaim (to_folio); + ret =shmem_writeout (to_folio,NULL ,NULL ); +if (!folio_test_writeback (to_folio)) +folio_clear_reclaim (to_folio); +if (ret ==AOP_WRITEPAGE_ACTIVATE ) +folio_unlock (to_folio); + }else {folio_unlock (to_folio); - }else { -folio_unlock (to_folio); - } + } -folio_put (to_folio); +folio_put (to_folio); + i += to_nr; + *nr_pages_backed = i; + } -return handle; +return ttm_backup_shmem_idx_to_handle (idx); }/**
drivers/gpu/drm/ttm/ttm_pool.c +74 -15
129 lines not on this page · raw message
drivers/gpu/drm/ttm/ttm_pool_internal.h +8 -0
@@ -22,4 +22,12 @@ static inline unsigned int ttm_pool_bene return pool->alloc_flags & 0xff; } +/* +* Implemented in ttm_pool.c, used by ttm_backup.c. Returns true if a fault +* should be injected mid-compound to test the reactive split-and-retry +* fallback in ttm_pool_backup(). Always returns false when +* CONFIG_FAULT_INJECTION is disabled. +*/ +bool ttm_backup_fault_inject_folio (void ); +#endif
include/drm/ttm/ttm_backup.h +6 -6
@@ -13,9 +13,8 @@* ttm_backup_handle_to_page_ptr() - Convert handle to struct page pointer * @handle: The handle to convert. * -* Converts an opaque handle received from the -* ttm_backup_backup_page() function to an (invalid) -* struct page pointer suitable for a struct page array. +* Converts an opaque handle received from a ttm_backup_backup_*() +* function to an (invalid) struct page pointer suitable for a struct page array. * * Return: An (invalid) struct page pointer. */
@@ -59,9 +58,10 @@ int ttm_backup_copy_page(struct file *ba pgoff_t handle, bool intr, gfp_t additional_gfp);s64 -ttm_backup_backup_page (struct file *backup,struct page *page, -bool writeback,pgoff_t idx,gfp_t page_gfp, -gfp_t alloc_gfp); +ttm_backup_backup_folio (struct file *backup,struct folio *folio, +unsigned int order,bool writeback,pgoff_t idx, +gfp_t folio_gfp,gfp_t alloc_gfp, +pgoff_t *nr_pages_backed);void ttm_backup_fini (struct file *backup);
Greg Kroah-Hartman
maintainerPATCH 471/744 drm/gpusvm: Zero HMM PFNs before scanning ranges
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
commit 67b8bfd4ec7dac6e79a7ad9ad19a7a9d6fc35a26 upstream.
drm_gpusvm_scan_mm() asks HMM to report the current CPU page-table state without faulting missing entries by leaving default_flags set to zero. The HMM PFN array is still caller-owned input/output state, and the framework may preserve input bits while filling entries. It is not safe for the caller to hand HMM an uninitialized array and then treat entries without HMM_PFN_VALID as an authoritative unpopulated result.
Use kvcalloc() for the temporary PFN array so entries that are not reported as valid start from the documented zero state. This prevents random stack or heap contents from being interpreted as HMM PFN flags or PFN values during the scan.
--- drivers/gpu/drm/drm_gpusvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/drm_gpusvm.c +1 -1
@@ -781,7 +781,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_sconst struct dev_pagemap *other =NULL ;int err, i; - pfns =kvmalloc_array (npages,sizeof (*pfns),GFP_KERNEL ); + pfns =kvcalloc (npages,sizeof (*pfns),GFP_KERNEL );if (!pfns)return DRM_GPUSVM_SCAN_UNPOPULATED ;
Greg Kroah-Hartman
maintainerPATCH 472/744 drm/gpusvm: Fix MM reference leak in drm_gpusvm_range_evict
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
commit 847b371debf3c8c72384ab7b9a0c4123a74cc925 upstream.
If kvmalloc_array() fails in drm_gpusvm_range_evict(), the MM reference acquired earlier is not released, resulting in a reference leak.
Fix this by dropping the MM reference on the kvmalloc_array() failure path.
--- drivers/gpu/drm/drm_gpusvm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/drm_gpusvm.c +3 -1
@@ -1704,8 +1704,10 @@ int drm_gpusvm_range_evict(struct drm_gpreturn -EFAULT ; pfns =kvmalloc_array (npages,sizeof (*pfns),GFP_KERNEL ); -if (!pfns) +if (!pfns) { +mmput (mm);return -ENOMEM ; + } hmm_range.hmm_pfns = pfns;while (!time_after (jiffies, timeout)) {
Greg Kroah-Hartman
maintainerPATCH 473/744 drm/v3d: Reach the GMP through the hub registers on V3D 7.x
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
commit f7df2da0d1c375c1c4c70e1e0b569592de0d6b73 upstream.
v3d_idle_axi() drains the GPU's memory interface for a safe powerdown by using the V3D_GMP_CFG register. It reached both registers with the macros V3D_CORE_READ and V3D_CORE_WRITE.
On V3D 7.x the GMP is no longer a per-core block; it lives in the hub register region. Reaching it through the per-core register block addresses the wrong region.
Select the hub accessors (V3D_{READ,WRITE}) for the GMP on V3D 7.x and keep the per-core path for earlier generations.
--- drivers/gpu/drm/v3d/v3d_gem.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/gpu/drm/v3d/v3d_gem.c +12 -0
@@ -46,6 +46,18 @@ v3d_init_hw_state(struct v3d_dev *v3d)static void v3d_idle_axi (struct v3d_dev *v3d,int core) { +if (v3d->ver >=V3D_GEN_71 ) { +V3D_WRITE (V3D_GMP_CFG (v3d->ver),V3D_GMP_CFG_STOP_REQ ); + +if (wait_for ((V3D_READ (V3D_GMP_STATUS (v3d->ver)) & + (V3D_GMP_STATUS_RD_COUNT_MASK | +V3D_GMP_STATUS_WR_COUNT_MASK | +V3D_GMP_STATUS_CFG_BUSY )) ==0 ,100 )) { +drm_err (&v3d->drm,"Failed to wait for safe GMP shutdown\n" ); + } +return ; + } +V3D_CORE_WRITE (core,V3D_GMP_CFG (v3d->ver),V3D_GMP_CFG_STOP_REQ ); if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS(v3d->ver)) &
Greg Kroah-Hartman
maintainerPATCH 474/744 media: airspy: Return queued buffers on start_streaming() failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit 04344d0b4929caa94c0df72f767752aa0935ef5d upstream.
The vb2 framework hands buffers to the driver via buf_queue() before calling start_streaming(). If start_streaming() returns an error without first returning those buffers via vb2_buffer_done(), vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued buffers leak.
airspy_start_streaming() returned -ENODEV early when the USB device had been disconnected (s->udev == NULL) without returning any buffers that buf_queue() had already accepted. Take v4l2_lock first and jump to the existing err_clear_bit label, which already drains s->queued_bufs via vb2_buffer_done(..., VB2_BUF_STATE_QUEUED) before unlocking.
This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo:
Return queued buffers on start_streaming() failure").
--- drivers/media/usb/airspy/airspy.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/media/usb/airspy/airspy.c +5 -3
@@ -522,11 +522,13 @@ static int airspy_start_streaming(structdev_dbg (s->dev,"\n" ); -if (!s->udev) -return -ENODEV ; -mutex_lock (&s->v4l2_lock); +if (!s->udev) { + ret = -ENODEV ; + goto err_clear_bit; + } + s->sequence =0 ;set_bit (POWER_ON , &s->flags);
Greg Kroah-Hartman
maintainerPATCH 475/744 media: amlogic-c3: Add validations for ae and awb config
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Ribalda <[email protected]>
commit 9724164f71974a2a44a5e026614fbcc05bab6d91 upstream.
Avoid invalid memory access if the zones_num is bigger than zone_weight.
This patch fixes the following smatch errors:drivers/media/platform/amlogic/c3/isp/c3-isp-params.c:111 c3_isp_params_awb_wt() error: buffer overflow 'cfg->zone_weight' 768 <= u32max drivers/media/platform/amlogic/c3/isp/c3-isp-params.c:111 c3_isp_params_awb_wt() error: buffer overflow 'cfg->zone_weight' 768 <= u32max drivers/media/platform/amlogic/c3/isp/c3-isp-params.c:227 c3_isp_params_ae_wt() error: buffer overflow 'cfg->zone_weight' 255 <= u32max drivers/media/platform/amlogic/c3/isp/c3-isp-params.c:227 c3_isp_params_ae_wt() error: buffer overflow 'cfg->zone_weight' 255 <= u32max
--- drivers/media/platform/amlogic/c3/isp/c3-isp-params.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/media/platform/amlogic/c3/isp/c3-isp-params.c +4 -0
@@ -104,6 +104,8 @@ static void c3_isp_params_awb_wt(structc3_isp_write (isp,ISP_AWB_BLK_WT_ADDR ,0 ); zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; +if (zones_num >C3_ISP_AWB_MAX_ZONES ) + zones_num =C3_ISP_AWB_MAX_ZONES ;/* Need to write 8 weights at once */ for (i =0 ; i < zones_num /8 ; i++) {
@@ -220,6 +222,8 @@ static void c3_isp_params_ae_wt(struct cc3_isp_write (isp,ISP_AE_BLK_WT_ADDR ,0 ); zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; +if (zones_num >C3_ISP_AE_MAX_ZONES ) + zones_num =C3_ISP_AE_MAX_ZONES ;/* Need to write 8 weights at once */ for (i =0 ; i < zones_num /8 ; i++) {
Greg Kroah-Hartman
maintainerPATCH 476/744 media: aspeed: fix missing of_reserved_mem_device_release() on probe failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit 253c8ef7d57da0c74db251f385324faaa5ae2257 upstream.
aspeed_video_init() calls of_reserved_mem_device_init() to associate reserved memory regions with the device. When aspeed_video_setup_video() subsequently fails in aspeed_video_probe(), the error path frees the JPEG buffer and unprepares the clocks but does not release the reserved memory association, leaking the rmem_assigned_device entry on the global list.
The normal remove path already calls of_reserved_mem_device_release() correctly; only the probe error path was missing it.
Add the missing of_reserved_mem_device_release() call to the aspeed_video_setup_video() failure cleanup.
--- drivers/media/platform/aspeed/aspeed-video.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/platform/aspeed/aspeed-video.c +1 -0
@@ -2343,6 +2343,7 @@ static int aspeed_video_probe(struct pla rc =aspeed_video_setup_video (video);if (rc) {aspeed_video_free_buf (video, &video->jpeg); +of_reserved_mem_device_release (&pdev->dev);clk_unprepare (video->vclk);clk_unprepare (video->eclk);return rc;
Greg Kroah-Hartman
maintainerPATCH 477/744 media: cec: seco: unregister adapter on IR probe failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit c3a78691be8245e52ced489f268e413f18061ac2 upstream.
If secocec_ir_probe() fails after cec_register_adapter() succeeds, probe returns an error and the driver remove callback is not called. The current unwind path unregisters the notifier and then falls through to cec_delete_adapter(), which violates the CEC adapter lifetime rules after a successful registration.
Add a registered-adapter unwind path that unregisters the notifier and the adapter instead.
--- drivers/media/cec/platform/seco/seco-cec.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/media/cec/platform/seco/seco-cec.c +5 -1
@@ -649,7 +649,7 @@ static int secocec_probe(struct platform ret =secocec_ir_probe (secocec);if (ret) - goto err_notifier; + goto err_unregister_adapter;platform_set_drvdata (pdev, secocec);
@@ -657,6 +657,10 @@ static int secocec_probe(struct platformreturn ret; +err_unregister_adapter: +cec_notifier_cec_adap_unregister (secocec->notifier, secocec->cec_adap); +cec_unregister_adapter (secocec->cec_adap); + goto err; err_notifier:cec_notifier_cec_adap_unregister (secocec->notifier, secocec->cec_adap); err_delete_adapter:
Greg Kroah-Hartman
maintainerPATCH 478/744 media: cedrus: clean up media device on probe failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 2c869b6969f3061cbbdab587f4c0a88bd7fc3cc9 upstream.
cedrus_probe() initializes the media device before registering the video device, the media controller, and the media device. If any of those later steps fails, probe returns without calling media_device_cleanup(), so the media device internals initialized by media_device_init() are left behind.
Add a media-device cleanup label to the probe unwind path and route video registration failures through it as well.
--- drivers/staging/media/sunxi/cedrus/cedrus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/staging/media/sunxi/cedrus/cedrus.c +3 -2
@@ -507,7 +507,7 @@ static int cedrus_probe(struct platform_ ret =video_register_device (vfd,VFL_TYPE_VIDEO ,0 );if (ret) {v4l2_err (&dev->v4l2_dev,"Failed to register video device\n" ); - goto err_m2m; + goto err_media; } v4l2_info(&dev->v4l2_dev,
@@ -533,7 +533,8 @@ err_m2m_mc:v4l2_m2m_unregister_media_controller (dev->m2m_dev); err_video:video_unregister_device (&dev->vfd); -err_m2m: +err_media: +media_device_cleanup (&dev->mdev);v4l2_m2m_release (dev->m2m_dev); err_v4l2:v4l2_device_unregister (&dev->v4l2_dev);
Greg Kroah-Hartman
maintainerPATCH 479/744 media: cedrus: Fix missing cleanup in error path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Holland <[email protected]>
commit d99732334aaf33b9f93926b70b6a11c2cef3de39 upstream.
According to the documentation struct v4l2_fh has to be cleaned up with v4l2_fh_exit() before being freed. [1]
Currently there is no actual bug here, when v4l2_fh_exit() isn't called. v4l2_fh_exit() in this case only destroys internal mutex. But it may change in the future, when v4l2_fh_init/v4l2_fh_exit will be enhanced.
1. https://docs.kernel.org/driver-api/media/v4l2-fh.html
--- drivers/staging/media/sunxi/cedrus/cedrus.c | 1 + 1 file changed, 1 insertion(+)
drivers/staging/media/sunxi/cedrus/cedrus.c +1 -0
@@ -391,6 +391,7 @@ static int cedrus_open(struct file *file err_m2m_release:v4l2_m2m_ctx_release (ctx->fh.m2m_ctx); err_free: +v4l2_fh_exit (&ctx->fh);kfree (ctx);mutex_unlock (&dev->dev_mutex);
Greg Kroah-Hartman
maintainerPATCH 480/744 media: cedrus: skip invalid H.264 reference list entries
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit 10358ea986c3c85516d1c8206486464f79d36e76 upstream.
Cedrus consumes H.264 ref_pic_list0/ref_pic_list1 entries from the stateless slice control and later uses their indices to look up decode->dpb[] in _cedrus_write_ref_list().
Rejecting such controls in cedrus_try_ctrl() would break existing userspace, since stateless H.264 reference lists may legitimately carry out-of-range indices for missing references. Instead, guard the actual DPB lookup in Cedrus and skip entries whose indices do not fit the fixed V4L2_H264_NUM_DPB_ENTRIES array.
This keeps the fix local to the driver use site and avoids out-of-bounds reads from malformed or unsupported reference list entries.
--- drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/staging/media/sunxi/cedrus/cedrus_h264.c +3 -0
@@ -210,6 +210,9 @@ static void _cedrus_write_ref_list(strucu8 dpb_idx; dpb_idx = ref_list[i].index; +if (dpb_idx >=V4L2_H264_NUM_DPB_ENTRIES ) +continue ; + dpb = &decode->dpb[dpb_idx];if (!(dpb->flags &V4L2_H264_DPB_ENTRY_FLAG_ACTIVE ))
Greg Kroah-Hartman
maintainerPATCH 481/744 media: chips-media: wave5: Move src_buf Removal to finish_encode
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brandon Brnich <[email protected]>
commit b20157147089a9c16a38c7810e2fe6f2df8e3277 upstream.
During encoder processing, there is a case where the IRQ response could return the buffer back to userspace via v4l2_m2m_buf_done call. In this time, userspace could queue up this same buffer before start_encode removes the index from the ready queue. This would then lead to a case where the buffer in the ready queue could be a self loop due to the WRITE_ONCE(prev->next, new) call in __list_add.
When __list_del is finally called, the loop is already made so nothing points back to ready queue list head and pointers are poisoned.
A buffer should not be marked as DONE before the buffer is removed from m2m ready queue. Move removal entirely to finish_encode.
--- drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 29 ++------------- 1 file changed, 4 insertions(+), 25 deletions(-)
drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +4 -25
@@ -226,13 +226,6 @@ static int start_encode(struct vpu_insta }else {dev_dbg (inst->dev->dev,"%s: wave5_vpu_enc_start_one_frame success\n" , __func__); -/* -* Remove the source buffer from the ready-queue now and finish -* it in the videobuf2 framework once the index is returned by the -* firmware in finish_encode -*/ -if (src_buf) -v4l2_m2m_src_buf_remove_by_idx (m2m_ctx, src_buf->vb2_buf.index); }return 0 ;
@@ -259,27 +252,13 @@ static void wave5_vpu_enc_finish_encode( __func__, enc_output_info.pic_type, enc_output_info.recon_frame_index, enc_output_info.enc_src_idx, enc_output_info.enc_pic_byte, enc_output_info.pts); -/* -* The source buffer will not be found in the ready-queue as it has been -* dropped after sending of the encode firmware command, locate it in -* the videobuf2 queue directly -*/ if (enc_output_info.enc_src_idx >=0 ) { -struct vb2_buffer *vb =vb2_get_buffer (v4l2_m2m_get_src_vq (m2m_ctx), - enc_output_info.enc_src_idx); -if (vb->state !=VB2_BUF_STATE_ACTIVE ) -dev_warn (inst->dev->dev, -"%s: encoded buffer (%d) was not in ready queue %i." , - __func__, enc_output_info.enc_src_idx, vb->state); -else - src_buf =to_vb2_v4l2_buffer (vb); - -if (src_buf) { + src_buf =v4l2_m2m_src_buf_remove_by_idx (m2m_ctx, enc_output_info.enc_src_idx); +if (!src_buf) { +dev_warn (inst->dev->dev,"%s: no source buffer found\n" , __func__); + }else { inst->timestamp = src_buf->vb2_buf.timestamp;v4l2_m2m_buf_done (src_buf,VB2_BUF_STATE_DONE ); - }else { -dev_warn (inst->dev->dev,"%s: no source buffer with index: %d found\n" , - __func__, enc_output_info.enc_src_idx); } }
Greg Kroah-Hartman
maintainerPATCH 482/744 media: cx231xx: fix devres lifetime
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 7d6358ab02866e5b7ed8d3a00805297617bbb0ec upstream.
USB drivers bind to USB interfaces and any device managed resources should have their lifetime tied to the interface rather than parent USB device. This avoids issues like memory leaks when drivers are unbound without their devices being physically disconnected (e.g. on probe deferral or configuration changes).
Fix the driver state lifetime so that it is released on driver unbind.
--- drivers/media/usb/cx231xx/cx231xx-cards.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/media/usb/cx231xx/cx231xx-cards.c +11 -5
@@ -1573,7 +1573,8 @@ static int cx231xx_init_v4l2(struct cx23 dev->video_mode.end_point_addr, dev->video_mode.num_alt); - dev->video_mode.alt_max_pkt_size =devm_kmalloc_array (&udev->dev,32 , dev->video_mode.num_alt,GFP_KERNEL ); + dev->video_mode.alt_max_pkt_size =devm_kmalloc_array (&interface->dev,32 , + dev->video_mode.num_alt,GFP_KERNEL );if (dev->video_mode.alt_max_pkt_size ==NULL )return -ENOMEM ;
@@ -1614,7 +1615,8 @@ static int cx231xx_init_v4l2(struct cx23 dev->vbi_mode.num_alt);/* compute alternate max packet sizes for vbi */ - dev->vbi_mode.alt_max_pkt_size =devm_kmalloc_array (&udev->dev,32 , dev->vbi_mode.num_alt,GFP_KERNEL ); + dev->vbi_mode.alt_max_pkt_size =devm_kmalloc_array (&interface->dev,32 , + dev->vbi_mode.num_alt,GFP_KERNEL );if (dev->vbi_mode.alt_max_pkt_size ==NULL )return -ENOMEM ;
@@ -1656,7 +1658,9 @@ static int cx231xx_init_v4l2(struct cx23"sliced CC EndPoint Addr 0x%x, Alternate settings: %i\n" , dev->sliced_cc_mode.end_point_addr, dev->sliced_cc_mode.num_alt); - dev->sliced_cc_mode.alt_max_pkt_size =devm_kmalloc_array (&udev->dev,32 , dev->sliced_cc_mode.num_alt,GFP_KERNEL ); + dev->sliced_cc_mode.alt_max_pkt_size =devm_kmalloc_array (&interface->dev,32 , + dev->sliced_cc_mode.num_alt, +GFP_KERNEL );if (dev->sliced_cc_mode.alt_max_pkt_size ==NULL )return -ENOMEM ;
@@ -1720,7 +1724,7 @@ static int cx231xx_usb_probe(struct usb_ udev =interface_to_usbdev (interface);/* allocate memory for our device state and initialize it */ - dev =devm_kzalloc (&udev->dev,sizeof (*dev),GFP_KERNEL ); + dev =devm_kzalloc (&interface->dev,sizeof (*dev),GFP_KERNEL );if (dev ==NULL ) { retval = -ENOMEM ; goto err_if;
@@ -1850,7 +1854,9 @@ static int cx231xx_usb_probe(struct usb_ dev->ts1_mode.end_point_addr, dev->ts1_mode.num_alt); - dev->ts1_mode.alt_max_pkt_size =devm_kmalloc_array (&udev->dev,32 , dev->ts1_mode.num_alt,GFP_KERNEL ); + dev->ts1_mode.alt_max_pkt_size =devm_kmalloc_array (&interface->dev,32 , + dev->ts1_mode.num_alt, +GFP_KERNEL );if (dev->ts1_mode.alt_max_pkt_size ==NULL ) { retval = -ENOMEM ; goto err_video_alt;
Greg Kroah-Hartman
maintainerPATCH 483/744 media: cx23885: add ioremap return check and cleanup
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wang Jun <[email protected]>
commit a0701e387b46e2481c05b47f1235b954bfc2af3e upstream.
Add a check for the return value of pci_ioremap_bar() in cx23885_dev_setup().
If ioremap for BAR0 fails, release the already allocated PCI memory region,
decrement the device count, and return -ENODEV.
This prevents a potential null pointer dereference and ensures proper cleanup
on memory mapping failure.
--- drivers/media/pci/cx23885/cx23885-core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
drivers/media/pci/cx23885/cx23885-core.c +12 -2
@@ -1002,8 +1002,12 @@ static int cx23885_dev_setup(struct cx23 }/* PCIe stuff */ - dev->lmmio =ioremap (pci_resource_start (dev->pci,0 ), -pci_resource_len (dev->pci,0 )); + dev->lmmio =pci_ioremap_bar (dev->pci,0 ); +if (!dev->lmmio) { +dev_err (&dev->pci->dev,"CORE %s: can't ioremap MMIO memory\n" , + dev->name); + goto err_release_region; + } dev->bmmio = (u8 __iomem *)dev->lmmio;
@@ -1109,6 +1113,12 @@ static int cx23885_dev_setup(struct cx23 }return 0 ; + +err_release_region: +release_mem_region (pci_resource_start (dev->pci,0 ), +pci_resource_len (dev->pci,0 )); + cx23885_devcount--; +return -ENODEV ; }static void cx23885_dev_unregister (struct cx23885_dev *dev)
Greg Kroah-Hartman
maintainerPATCH 484/744 media: dw9719: Add back the I²C device id table
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sakari Ailus <[email protected]>
commit d7fe0d53b2a8b08f6042cc89315118dee49e072e upstream.
The I²C device id table is necessary as the device may be, besides through system firmware, also instantiated in the IPU bridge so matching takes place using the I²C device id table. Add back the table, with ids for all supported devices.
--- drivers/media/i2c/dw9719.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/media/i2c/dw9719.c +10 -0
@@ -439,6 +439,15 @@ static void dw9719_remove(struct i2c_clipm_runtime_set_suspended (&client->dev); } +static const struct i2c_device_id dw9719_id_table[] = { + { .name ="dw9718s" , .driver_data = (kernel_ulong_t )DW9718S }, + { .name ="dw9719" , .driver_data = (kernel_ulong_t )DW9719 }, + { .name ="dw9761" , .driver_data = (kernel_ulong_t )DW9761 }, + { .name ="dw9800k" , .driver_data = (kernel_ulong_t )DW9800K }, + { } +}; +MODULE_DEVICE_TABLE (i2c, dw9719_id_table); +static const struct of_device_id dw9719_of_table[] = { { .compatible ="dongwoon,dw9718s" , .data = (const void *)DW9718S }, { .compatible ="dongwoon,dw9719" , .data = (const void *)DW9719 },
@@ -459,6 +468,7 @@ static struct i2c_driver dw9719_i2c_driv }, .probe = dw9719_probe, .remove = dw9719_remove, + .id_table = dw9719_id_table, };module_i2c_driver (dw9719_i2c_driver);
Greg Kroah-Hartman
maintainerPATCH 485/744 media: i2c: alvium: fix critical pointer access in alvium_ctrl_init
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Hecht <[email protected]>
commit 4f6f28ff24709710c08557c127b3e4c3fb1b4159 upstream.
The current implementation of alvium_ctrl_init creates several controls in function alvium_ctrl_init and uses the returned pointer without check. That can cause write access over NULL-pointer for several controls. The reworked code checks the pointers before adding flags.
--- drivers/media/i2c/alvium-csi2.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)
drivers/media/i2c/alvium-csi2.c +14 -7
@@ -2100,20 +2100,21 @@ static int alvium_ctrl_init(struct alviuV4L2_CID_PIXEL_RATE ,0 ,ALVIUM_DEFAULT_PIXEL_RATE_MHZ ,1 , ALVIUM_DEFAULT_PIXEL_RATE_MHZ); - ctrls->pixel_rate->flags |=V4L2_CTRL_FLAG_READ_ONLY ;/* Link freq is fixed */ ctrls->link_freq =v4l2_ctrl_new_int_menu (hdl, ops,V4L2_CID_LINK_FREQ ,0 ,0 , &alvium->link_freq); - ctrls->link_freq->flags |=V4L2_CTRL_FLAG_READ_ONLY ; +if (ctrls->link_freq) + ctrls->link_freq->flags |=V4L2_CTRL_FLAG_READ_ONLY ;/* Auto/manual white balance */ if (alvium->avail_ft.auto_whiteb) { ctrls->auto_wb =v4l2_ctrl_new_std (hdl, ops,V4L2_CID_AUTO_WHITE_BALANCE ,0 ,1 ,1 ,1 ); -v4l2_ctrl_auto_cluster (3 , &ctrls->auto_wb,0 , false); +if (ctrls->auto_wb) +v4l2_ctrl_auto_cluster (3 , &ctrls->auto_wb,0 , false); } ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops,
@@ -2122,6 +2123,7 @@ static int alvium_ctrl_init(struct alviu alvium->max_bbalance, alvium->inc_bbalance, alvium->dft_bbalance); + ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, alvium->min_rbalance,
@@ -2136,7 +2138,9 @@ static int alvium_ctrl_init(struct alviuV4L2_CID_EXPOSURE_AUTO ,V4L2_EXPOSURE_MANUAL ,0 , V4L2_EXPOSURE_AUTO); -v4l2_ctrl_auto_cluster (2 , &ctrls->auto_exp,1 , true); +if (ctrls->auto_exp) +v4l2_ctrl_auto_cluster (2 , &ctrls->auto_exp, +V4L2_EXPOSURE_MANUAL , true); } ctrls->exposure = v4l2_ctrl_new_std(hdl, ops,
@@ -2145,14 +2149,16 @@ static int alvium_ctrl_init(struct alviu alvium->max_exp, alvium->inc_exp, alvium->dft_exp); - ctrls->exposure->flags |=V4L2_CTRL_FLAG_VOLATILE ; +if (ctrls->exposure) + ctrls->exposure->flags |=V4L2_CTRL_FLAG_VOLATILE ;/* Auto/manual gain */ if (alvium->avail_ft.auto_gain) { ctrls->auto_gain =v4l2_ctrl_new_std (hdl, ops,V4L2_CID_AUTOGAIN ,0 ,1 ,1 ,1 ); -v4l2_ctrl_auto_cluster (2 , &ctrls->auto_gain,0 , true); +if (ctrls->auto_gain) +v4l2_ctrl_auto_cluster (2 , &ctrls->auto_gain,0 , true); }if (alvium->avail_ft.gain) {
@@ -2162,7 +2168,8 @@ static int alvium_ctrl_init(struct alviu alvium->max_gain, alvium->inc_gain, alvium->dft_gain); - ctrls->gain->flags |=V4L2_CTRL_FLAG_VOLATILE ; +if (ctrls->gain) + ctrls->gain->flags |=V4L2_CTRL_FLAG_VOLATILE ; }if (alvium->avail_ft.sat)
Greg Kroah-Hartman
maintainerPATCH 486/744 media: imx219: Fix maximum frame length in lines
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sakari Ailus <[email protected]>
commit 2c4f1ba7354312ad2d6e34e70a518a51a9344715 upstream.
The driver used the maximum frame length in lines value of 0xffff, but the maximum appears to be 0xfffe instead. Fix it.
--- drivers/media/i2c/imx219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/i2c/imx219.c +1 -1
@@ -72,7 +72,7 @@/* V_TIMING internal */ #define IMX219_REG_FRM_LENGTH_A CCI_REG16(0x0160) -#define IMX219_FLL_MAX 0xffff +#define IMX219_FLL_MAX 0xfffe#define IMX219_VBLANK_MIN 32#define IMX219_REG_LINE_LENGTH_A CCI_REG16(0x0162)#define IMX219_LLP_MIN 0x0d78
Greg Kroah-Hartman
maintainerPATCH 487/744 media: intel/ipu6: Improve DWC PHY HSFREQRANGE band selection for overlapping ranges
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Nenciarini <[email protected]>
commit 477620dccf3e9481ed6ae67cb5c747f25751c531 upstream.
The get_hsfreq_by_mbps() function searches the freqranges[] table backward (from highest to lowest index). Because adjacent frequency bands overlap, a data rate that falls in the overlap region always lands on the higher-indexed band.
For data rates up to 1500 Mbps (index 42) every band uses osc_freq_target 335. Starting at index 43 (1461-1640 Mbps) the osc_freq_target drops to 208. A sensor running at 1498 Mbps sits in the overlap between index 42 (1414-1588, osc 335) and index 43 (1461-1640, osc 208). The backward search picks index 43, programming the lower osc_freq_target of 208 instead of the optimal 335.
This causes DDL lock instability and CSI-2 CRC errors on affected configurations, such as the OmniVision OV08X40 sensor on Intel Arrow Lake platforms (Dell Pro Max 16).
Rewrite get_hsfreq_by_mbps() to select the optimal band:
1. Among bands whose min/max range covers the data rate, prefer the one with the higher osc_freq_target.
2. If osc_freq_target is equal, prefer the band whose default_mbps is closest to the requested rate.
Since the frequency ranges are monotonically increasing, the loop exits early once min exceeds the requested rate.
For 1498 Mbps this now correctly selects index 42 (osc_freq_target 335, range 1414-1588) instead of index 43 (osc_freq_target 208, range 1461-1640).
--- drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c | 24 +++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c +18 -6
@@ -288,15 +288,27 @@ static const struct dwc_dphy_freq_rangestatic u16 get_hsfreq_by_mbps (u32 mbps) { -unsigned int i =DPHY_FREQ_RANGE_NUM ; +u16 best =DPHY_FREQ_RANGE_INVALID_INDEX ; +unsigned int i; -while (i--) { -if (freqranges[i].default_mbps == mbps || - (mbps >= freqranges[i].min && mbps <= freqranges[i].max)) -return i; +for (i =0 ; i <DPHY_FREQ_RANGE_NUM ; i++) { +if (mbps > freqranges[i].max) +continue ; + +if (mbps < freqranges[i].min) +break ; + +if (best ==DPHY_FREQ_RANGE_INVALID_INDEX || + freqranges[i].osc_freq_target > + freqranges[best].osc_freq_target || + (freqranges[i].osc_freq_target == + freqranges[best].osc_freq_target && +abs ((int )mbps - (int )freqranges[i].default_mbps) < +abs ((int )mbps - (int )freqranges[best].default_mbps))) + best = i; } -return DPHY_FREQ_RANGE_INVALID_INDEX ; +return best; } static int ipu6_isys_dwc_phy_config(struct ipu6_isys *isys,
Greg Kroah-Hartman
maintainerPATCH 488/744 media: iris: Fix use IRQF_NO_AUTOEN when requesting the IRQ
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <[email protected]>
commit 45ac2230f929b9f0fae899c4a5c6bf763250fc13 upstream.
Requesting the IRQ and then immediately disabling it is fragile as it leaves a window when the IRQ is still enabled although the underlying device might be not completely setup for IRQ handling. Pass IRQF_NO_AUTOEN instead of calling disable_irq_nosync().
--- drivers/media/platform/qcom/iris/iris_probe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/media/platform/qcom/iris/iris_probe.c +3 -3
@@ -252,12 +252,12 @@ static int iris_probe(struct platform_de core->iris_platform_data =of_device_get_match_data (core->dev); ret =devm_request_threaded_irq (core->dev, core->irq, iris_hfi_isr, - iris_hfi_isr_handler,IRQF_TRIGGER_HIGH ,"iris" , core); + iris_hfi_isr_handler, +IRQF_TRIGGER_HIGH |IRQF_NO_AUTOEN , +"iris" , core);if (ret)return ret; -disable_irq_nosync (core->irq); -iris_init_ops (core); core->iris_platform_data->init_hfi_command_ops (core); core->iris_platform_data->init_hfi_response_ops (core);
Greg Kroah-Hartman
maintainerPATCH 489/744 media: mali-c55: Add missing of_reserved_mem_device_release()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit 38e3509dd98d7e970db87e13f8ec7412852a6967 upstream.
mali_c55_probe() calls of_reserved_mem_device_init() to associate reserved memory regions with the device. This function allocates a struct rmem_assigned_device and adds it to a global linked list, which must be explicitly released via of_reserved_mem_device_release() — there is no devm variant of this API.
However, neither the probe error paths nor mali_c55_remove() called of_reserved_mem_device_release(). Any probe failure after the of_reserved_mem_device_init() call, as well as every normal device removal, leaked the reserved memory association on the global list.
Fix this by adding an err_release_mem label at the end of the probe error chain and calling of_reserved_mem_device_release() in mali_c55_remove(). The remove teardown order is also corrected to call mali_c55_media_frameworks_deinit() before kfree(), mirroring the probe init order in reverse.
--- drivers/media/platform/arm/mali-c55/mali-c55-core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/media/platform/arm/mali-c55/mali-c55-core.c +8 -3
@@ -806,8 +806,10 @@ static int mali_c55_probe(struct platforvb2_dma_contig_set_max_seg_size (dev,UINT_MAX ); ret =__mali_c55_power_on (mali_c55); -if (ret) -return dev_err_probe (dev, ret,"failed to power on\n" ); +if (ret) { +dev_err_probe (dev, ret,"failed to power on\n" ); + goto err_release_mem; + } ret =mali_c55_check_hwcfg (mali_c55);if (ret)
@@ -846,6 +848,8 @@ err_free_context_registers:kfree (mali_c55->context.registers); err_power_off:__mali_c55_power_off (mali_c55); +err_release_mem: +of_reserved_mem_device_release (dev);return ret; }
@@ -854,8 +858,9 @@ static void mali_c55_remove(struct platf {struct mali_c55 *mali_c55 =platform_get_drvdata (pdev); -kfree (mali_c55->context.registers);mali_c55_media_frameworks_deinit (mali_c55); +kfree (mali_c55->context.registers); +of_reserved_mem_device_release (&pdev->dev); }static const struct of_device_id mali_c55_of_match[] = {
Greg Kroah-Hartman
maintainerPATCH 490/744 media: mali-c55: Disable pm_runtime on probe error
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit a1db83cc6f7e88a166c77d9060507ec01d617784 upstream.
When mali_c55_media_frameworks_init() fails, the goto target jumps to err_free_context_registers, skipping pm_runtime_disable() despite pm_runtime having already been enabled earlier in the function.
Fix this by adding an err_pm_runtime_disable label and redirecting the frameworks init failure to it, so pm_runtime is properly unwound on that error path. The runtime PM status is also set back to suspended before disabling, to undo the pm_runtime_set_active() from probe.
--- drivers/media/platform/arm/mali-c55/mali-c55-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/media/platform/arm/mali-c55/mali-c55-core.c +3 -2
@@ -828,7 +828,7 @@ static int mali_c55_probe(struct platfor ret =mali_c55_media_frameworks_init (mali_c55);if (ret) - goto err_free_context_registers; + goto err_pm_runtime_disable;pm_runtime_idle (&pdev->dev);
@@ -843,8 +843,9 @@ static int mali_c55_probe(struct platfor err_deinit_media_frameworks:mali_c55_media_frameworks_deinit (mali_c55); +err_pm_runtime_disable: +pm_runtime_set_suspended (&pdev->dev);pm_runtime_disable (&pdev->dev); -err_free_context_registers:kfree (mali_c55->context.registers); err_power_off:__mali_c55_power_off (mali_c55);
Greg Kroah-Hartman
maintainerPATCH 491/744 media: mali-c55: Fix possible ERR_PTR in enable_streams
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alper Ak <[email protected]>
commit 94c6402e423d36a2bd6f62055a65a0d439d84da7 upstream.
The media_pad_remote_pad_unique() function returns either a valid pointer or an ERR_PTR() on failure (-ENOTUNIQ if multiple links are enabled, -ENOLINK if no connected pad is found). The return value was assigned directly to isp->remote_src and dereferenced in the next line without checking for errors, which could lead to an ERR_PTR dereference.
Add proper error checking with IS_ERR() before dereferencing the pointer. Also set isp->remote_src to NULL on error to maintain consistency with other error paths in the function.
--- drivers/media/platform/arm/mali-c55/mali-c55-isp.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/media/platform/arm/mali-c55/mali-c55-isp.c +7 -0
@@ -333,6 +333,13 @@ static int mali_c55_isp_enable_streams(s sink_pad = &isp->pads[MALI_C55_ISP_PAD_SINK_VIDEO ]; isp->remote_src =media_pad_remote_pad_unique (sink_pad); +if (IS_ERR (isp->remote_src)) { + ret =PTR_ERR (isp->remote_src); +dev_err (mali_c55->dev,"Failed to get remote source pad: %d\n" , ret); + isp->remote_src =NULL ; +return ret; + } + src_sd =media_entity_to_v4l2_subdev (isp->remote_src->entity); isp->frame_sequence =0 ;
Greg Kroah-Hartman
maintainerPATCH 492/744 media: mali-c55: Power-off the peripheral in remove()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit 2c9b9bcc2569f52e366ec71ca012542e161f1f8d upstream.
The Mali C55 driver doesn't depend on PM. For this reason, if pm_runtime is not compiled in it is required to manually power-off the peripheral during the driver's remove() handler.
Also pm_runtime_enable() is called during probe but mali_c55_remove() never calls pm_runtime_disable(), leaving the device's runtime PM state enabled after the driver is unbound.
Manually power-off the peripheral in remove() if the peripheral has not been suspended using runtime_pm and disable runtime pm.
--- drivers/media/platform/arm/mali-c55/mali-c55-core.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/media/platform/arm/mali-c55/mali-c55-core.c +5 -0
@@ -860,6 +860,11 @@ static void mali_c55_remove(struct platfstruct mali_c55 *mali_c55 =platform_get_drvdata (pdev);mali_c55_media_frameworks_deinit (mali_c55); +if (!pm_runtime_suspended (&pdev->dev)) { +__mali_c55_power_off (mali_c55); +pm_runtime_set_suspended (&pdev->dev); + } +pm_runtime_disable (&pdev->dev);kfree (mali_c55->context.registers);of_reserved_mem_device_release (&pdev->dev); }