Skip to content

Commit 00eda4a

Browse files
committed
drm/asahi: Add verbose UAPI error reporting
Signed-off-by: Asahi Lina <[email protected]>
1 parent c229969 commit 00eda4a

4 files changed

Lines changed: 179 additions & 28 deletions

File tree

drivers/gpu/drm/asahi/debug.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub(crate) enum DebugFlags {
2828
Queue = 10,
2929
Render = 11,
3030
Compute = 12,
31+
Errors = 13,
3132

3233
// 14-15: Misc stats
3334
MemStats = 14,

drivers/gpu/drm/asahi/file.rs

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ pub(crate) struct SyncItem {
5151
impl SyncItem {
5252
fn parse_one(file: &DrmFile, data: uapi::drm_asahi_sync, out: bool) -> Result<SyncItem> {
5353
if data.extensions != 0 {
54+
cls_pr_debug!(Errors, "drm_asahi_sync extension unexpected\n");
5455
return Err(EINVAL);
5556
}
5657

5758
match data.sync_type {
5859
uapi::drm_asahi_sync_type_DRM_ASAHI_SYNC_SYNCOBJ => {
5960
if data.timeline_value != 0 {
61+
cls_pr_debug!(Errors, "Non-timeline sync object with a nonzero value\n");
6062
return Err(EINVAL);
6163
}
6264
let syncobj = drm::syncobj::SyncObj::lookup_handle(file, data.handle)?;
@@ -65,7 +67,10 @@ impl SyncItem {
6567
fence: if out {
6668
None
6769
} else {
68-
Some(syncobj.fence_get().ok_or(EINVAL)?)
70+
Some(syncobj.fence_get().ok_or_else(|| {
71+
cls_pr_debug!(Errors, "Failed to get fence from sync object\n");
72+
EINVAL
73+
})?)
6974
},
7075
syncobj,
7176
chain_fence: None,
@@ -80,7 +85,13 @@ impl SyncItem {
8085
Some(
8186
syncobj
8287
.fence_get()
83-
.ok_or(EINVAL)?
88+
.ok_or_else(|| {
89+
cls_pr_debug!(
90+
Errors,
91+
"Failed to get fence from timeline sync object\n"
92+
);
93+
EINVAL
94+
})?
8495
.chain_find_seqno(data.timeline_value)?,
8596
)
8697
};
@@ -96,7 +107,10 @@ impl SyncItem {
96107
timeline_value: data.timeline_value,
97108
})
98109
}
99-
_ => Err(EINVAL),
110+
_ => {
111+
cls_pr_debug!(Errors, "Invalid sync type {}\n", data.sync_type);
112+
Err(EINVAL)
113+
}
100114
}
101115
}
102116

@@ -199,6 +213,7 @@ impl File {
199213
let gpu = &device.data().gpu;
200214

201215
if data.extensions != 0 || data.param_group != 0 || data.pad != 0 {
216+
cls_pr_debug!(Errors, "get_params: Invalid arguments\n");
202217
return Err(EINVAL);
203218
}
204219

@@ -276,6 +291,7 @@ impl File {
276291
file: &DrmFile,
277292
) -> Result<u32> {
278293
if data.extensions != 0 {
294+
cls_pr_debug!(Errors, "vm_create: Unexpected extensions\n");
279295
return Err(EINVAL);
280296
}
281297

@@ -348,6 +364,7 @@ impl File {
348364
file: &DrmFile,
349365
) -> Result<u32> {
350366
if data.extensions != 0 {
367+
cls_pr_debug!(Errors, "vm_destroy: Unexpected extensions\n");
351368
return Err(EINVAL);
352369
}
353370

@@ -375,6 +392,7 @@ impl File {
375392
|| (data.flags & !(uapi::ASAHI_GEM_WRITEBACK | uapi::ASAHI_GEM_VM_PRIVATE)) != 0
376393
|| (data.flags & uapi::ASAHI_GEM_VM_PRIVATE == 0 && data.vm_id != 0)
377394
{
395+
cls_pr_debug!(Errors, "gem_create: Invalid arguments\n");
378396
return Err(EINVAL);
379397
}
380398

@@ -422,6 +440,7 @@ impl File {
422440
);
423441

424442
if data.extensions != 0 || data.flags != 0 {
443+
cls_pr_debug!(Errors, "gem_mmap_offset: Unexpected extensions or flags\n");
425444
return Err(EINVAL);
426445
}
427446

@@ -450,6 +469,7 @@ impl File {
450469
);
451470

452471
if data.extensions != 0 {
472+
cls_pr_debug!(Errors, "gem_bind: Unexpected extensions\n");
453473
return Err(EINVAL);
454474
}
455475

@@ -459,7 +479,10 @@ impl File {
459479
uapi::drm_asahi_bind_op_ASAHI_BIND_OP_UNBIND_ALL => {
460480
Self::do_gem_unbind_all(device, data, file)
461481
}
462-
_ => Err(EINVAL),
482+
_ => {
483+
cls_pr_debug!(Errors, "gem_bind: Invalid op {}\n", data.op);
484+
Err(EINVAL)
485+
}
463486
}
464487
}
465488

@@ -469,20 +492,29 @@ impl File {
469492
file: &DrmFile,
470493
) -> Result<u32> {
471494
if data.offset != 0 {
495+
pr_err!("gem_bind: Offset not supported yet\n");
472496
return Err(EINVAL); // Not supported yet
473497
}
474498

475499
if (data.addr | data.range) as usize & mmu::UAT_PGMSK != 0 {
500+
cls_pr_debug!(
501+
Errors,
502+
"gem_bind: Addr/range not page aligned: {:#x} {:#x}\n",
503+
data.addr,
504+
data.range
505+
);
476506
return Err(EINVAL); // Must be page aligned
477507
}
478508

479509
if (data.flags & !(uapi::ASAHI_BIND_READ | uapi::ASAHI_BIND_WRITE)) != 0 {
510+
cls_pr_debug!(Errors, "gem_bind: Invalid flags {:#x}\n", data.flags);
480511
return Err(EINVAL);
481512
}
482513

483514
let mut bo = gem::lookup_handle(file, data.handle)?;
484515

485516
if data.range != bo.size().try_into()? {
517+
pr_err!("gem_bind: Partial maps not supported yet\n");
486518
return Err(EINVAL); // Not supported yet
487519
}
488520

@@ -491,18 +523,42 @@ impl File {
491523

492524
if (VM_SHADER_START..=VM_SHADER_END).contains(&start) {
493525
if !(VM_SHADER_START..=VM_SHADER_END).contains(&end) {
526+
cls_pr_debug!(
527+
Errors,
528+
"gem_bind: Invalid map range {:#x}..{:#x} (straddles shader range)\n",
529+
start,
530+
end
531+
);
494532
return Err(EINVAL); // Invalid map range
495533
}
496534
} else if (VM_USER_START..=VM_USER_END).contains(&start) {
497535
if !(VM_USER_START..=VM_USER_END).contains(&end) {
536+
cls_pr_debug!(
537+
Errors,
538+
"gem_bind: Invalid map range {:#x}..{:#x} (straddles user range)\n",
539+
start,
540+
end
541+
);
498542
return Err(EINVAL); // Invalid map range
499543
}
500544
} else {
545+
cls_pr_debug!(
546+
Errors,
547+
"gem_bind: Invalid map range {:#x}..{:#x}\n",
548+
start,
549+
end
550+
);
501551
return Err(EINVAL); // Invalid map range
502552
}
503553

504554
// Just in case
505555
if end >= VM_DRV_GPU_START {
556+
cls_pr_debug!(
557+
Errors,
558+
"gem_bind: Invalid map range {:#x}..{:#x} (intrudes in kernel range)\n",
559+
start,
560+
end
561+
);
506562
return Err(EINVAL);
507563
}
508564

@@ -515,6 +571,11 @@ impl File {
515571
} else if data.flags & uapi::ASAHI_BIND_WRITE != 0 {
516572
mmu::PROT_GPU_SHARED_WO
517573
} else {
574+
cls_pr_debug!(
575+
Errors,
576+
"gem_bind: Must specify read or write (flags: {:#x})\n",
577+
data.flags
578+
);
518579
return Err(EINVAL); // Must specify one of ASAHI_BIND_{READ,WRITE}
519580
};
520581

@@ -539,6 +600,7 @@ impl File {
539600
file: &DrmFile,
540601
) -> Result<u32> {
541602
if data.flags != 0 || data.offset != 0 || data.range != 0 || data.addr != 0 {
603+
cls_pr_debug!(Errors, "gem_unbind_all: Invalid arguments\n");
542604
return Err(EINVAL);
543605
}
544606

@@ -589,6 +651,7 @@ impl File {
589651
| uapi::drm_asahi_queue_cap_DRM_ASAHI_QUEUE_CAP_COMPUTE))
590652
!= 0
591653
{
654+
cls_pr_debug!(Errors, "queue_create: Invalid arguments\n");
592655
return Err(EINVAL);
593656
}
594657

@@ -623,6 +686,7 @@ impl File {
623686
file: &DrmFile,
624687
) -> Result<u32> {
625688
if data.extensions != 0 {
689+
cls_pr_debug!(Errors, "queue_destroy: Unexpected extensions\n");
626690
return Err(EINVAL);
627691
}
628692

@@ -644,16 +708,44 @@ impl File {
644708
data: &mut uapi::drm_asahi_submit,
645709
file: &DrmFile,
646710
) -> Result<u32> {
647-
if data.extensions != 0
648-
|| data.flags != 0
649-
|| data.in_sync_count > MAX_SYNCS_PER_SUBMISSION
650-
|| data.out_sync_count > MAX_SYNCS_PER_SUBMISSION
651-
|| data.command_count > MAX_COMMANDS_PER_SUBMISSION
652-
{
711+
debug::update_debug_flags();
712+
713+
if data.extensions != 0 {
714+
cls_pr_debug!(Errors, "submit: Unexpected extensions\n");
653715
return Err(EINVAL);
654716
}
655717

656-
debug::update_debug_flags();
718+
if data.flags != 0 {
719+
cls_pr_debug!(Errors, "submit: Unexpected flags {:#x}\n", data.flags);
720+
return Err(EINVAL);
721+
}
722+
if data.in_sync_count > MAX_SYNCS_PER_SUBMISSION {
723+
cls_pr_debug!(
724+
Errors,
725+
"submit: Too many in syncs: {} > {}\n",
726+
data.in_sync_count,
727+
MAX_SYNCS_PER_SUBMISSION
728+
);
729+
return Err(EINVAL);
730+
}
731+
if data.out_sync_count > MAX_SYNCS_PER_SUBMISSION {
732+
cls_pr_debug!(
733+
Errors,
734+
"submit: Too many out syncs: {} > {}\n",
735+
data.out_sync_count,
736+
MAX_SYNCS_PER_SUBMISSION
737+
);
738+
return Err(EINVAL);
739+
}
740+
if data.command_count > MAX_COMMANDS_PER_SUBMISSION {
741+
cls_pr_debug!(
742+
Errors,
743+
"submit: Too many commands: {} > {}\n",
744+
data.command_count,
745+
MAX_COMMANDS_PER_SUBMISSION
746+
);
747+
return Err(EINVAL);
748+
}
657749

658750
let gpu = &device.data().gpu;
659751
gpu.update_globals();

drivers/gpu/drm/asahi/queue/mod.rs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,31 @@ pub(crate) struct QueueJob {
170170
#[versions(AGX)]
171171
impl QueueJob::ver {
172172
fn get_vtx(&mut self) -> Result<&mut workqueue::Job::ver> {
173-
self.sj_vtx.as_mut().ok_or(EINVAL)?.get()
173+
self.sj_vtx
174+
.as_mut()
175+
.ok_or_else(|| {
176+
cls_pr_debug!(Errors, "No vertex queue\n");
177+
EINVAL
178+
})?
179+
.get()
174180
}
175181
fn get_frag(&mut self) -> Result<&mut workqueue::Job::ver> {
176-
self.sj_frag.as_mut().ok_or(EINVAL)?.get()
182+
self.sj_frag
183+
.as_mut()
184+
.ok_or_else(|| {
185+
cls_pr_debug!(Errors, "No fragment queue\n");
186+
EINVAL
187+
})?
188+
.get()
177189
}
178190
fn get_comp(&mut self) -> Result<&mut workqueue::Job::ver> {
179-
self.sj_comp.as_mut().ok_or(EINVAL)?.get()
191+
self.sj_comp
192+
.as_mut()
193+
.ok_or_else(|| {
194+
cls_pr_debug!(Errors, "No compute queue\n");
195+
EINVAL
196+
})?
197+
.get()
180198
}
181199

182200
fn commit(&mut self) -> Result {
@@ -534,6 +552,7 @@ impl Queue for Queue::ver {
534552

535553
// Empty submissions are not legal
536554
if commands.is_empty() {
555+
cls_pr_debug!(Errors, "Empty submission\n");
537556
return Err(EINVAL);
538557
}
539558

@@ -603,7 +622,10 @@ impl Queue for Queue::ver {
603622
match cmd.cmd_type {
604623
uapi::drm_asahi_cmd_type_DRM_ASAHI_CMD_RENDER => last_render = Some(i),
605624
uapi::drm_asahi_cmd_type_DRM_ASAHI_CMD_COMPUTE => last_compute = Some(i),
606-
_ => return Err(EINVAL),
625+
_ => {
626+
cls_pr_debug!(Errors, "Unknown command type {}\n", cmd.cmd_type);
627+
return Err(EINVAL);
628+
}
607629
}
608630
}
609631

@@ -618,7 +640,10 @@ impl Queue for Queue::ver {
618640
if *index == uapi::DRM_ASAHI_BARRIER_NONE as u32 {
619641
continue;
620642
}
621-
if let Some(event) = events[queue_idx].get(*index as usize).ok_or(EINVAL)? {
643+
if let Some(event) = events[queue_idx].get(*index as usize).ok_or_else(|| {
644+
cls_pr_debug!(Errors, "Invalid barrier #{}: {}\n", queue_idx, index);
645+
EINVAL
646+
})? {
622647
let mut alloc = gpu.alloc();
623648
let queue_job = match cmd.cmd_type {
624649
uapi::drm_asahi_cmd_type_DRM_ASAHI_CMD_RENDER => job.get_vtx()?,
@@ -652,18 +677,29 @@ impl Queue for Queue::ver {
652677
let result_writer = match result_buf.as_ref() {
653678
None => {
654679
if cmd.result_offset != 0 || cmd.result_size != 0 {
680+
cls_pr_debug!(Errors, "No result buffer but result requested\n");
655681
return Err(EINVAL);
656682
}
657683
None
658684
}
659685
Some(buf) => {
660686
if cmd.result_size != 0 {
661-
if cmd
687+
let end_offset = cmd
662688
.result_offset
663689
.checked_add(cmd.result_size)
664-
.ok_or(EINVAL)?
665-
> buf.size() as u64
666-
{
690+
.ok_or_else(|| {
691+
cls_pr_debug!(Errors, "result_offset + result_size overflow\n");
692+
EINVAL
693+
})?;
694+
if end_offset > buf.size() as u64 {
695+
cls_pr_debug!(
696+
Errors,
697+
"Result buffer overflow ({} + {} > {})\n",
698+
cmd.result_offset,
699+
cmd.result_size,
700+
buf.size()
701+
);
702+
667703
return Err(EINVAL);
668704
}
669705
Some(ResultWriter {

0 commit comments

Comments
 (0)