Skip to content

Commit 55c074e

Browse files
committed
drm/asahi: Add verbose UAPI error reporting
Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent 4c7de13 commit 55c074e

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
@@ -52,12 +52,14 @@ pub(crate) struct SyncItem {
5252
impl SyncItem {
5353
fn parse_one(file: &DrmFile, data: uapi::drm_asahi_sync, out: bool) -> Result<SyncItem> {
5454
if data.extensions != 0 {
55+
cls_pr_debug!(Errors, "drm_asahi_sync extension unexpected\n");
5556
return Err(EINVAL);
5657
}
5758

5859
match data.sync_type {
5960
uapi::drm_asahi_sync_type_DRM_ASAHI_SYNC_SYNCOBJ => {
6061
if data.timeline_value != 0 {
62+
cls_pr_debug!(Errors, "Non-timeline sync object with a nonzero value\n");
6163
return Err(EINVAL);
6264
}
6365
let syncobj = drm::syncobj::SyncObj::lookup_handle(file, data.handle)?;
@@ -66,7 +68,10 @@ impl SyncItem {
6668
fence: if out {
6769
None
6870
} else {
69-
Some(syncobj.fence_get().ok_or(EINVAL)?)
71+
Some(syncobj.fence_get().ok_or_else(|| {
72+
cls_pr_debug!(Errors, "Failed to get fence from sync object\n");
73+
EINVAL
74+
})?)
7075
},
7176
syncobj,
7277
chain_fence: None,
@@ -81,7 +86,13 @@ impl SyncItem {
8186
Some(
8287
syncobj
8388
.fence_get()
84-
.ok_or(EINVAL)?
89+
.ok_or_else(|| {
90+
cls_pr_debug!(
91+
Errors,
92+
"Failed to get fence from timeline sync object\n"
93+
);
94+
EINVAL
95+
})?
8596
.chain_find_seqno(data.timeline_value)?,
8697
)
8798
};
@@ -97,7 +108,10 @@ impl SyncItem {
97108
timeline_value: data.timeline_value,
98109
})
99110
}
100-
_ => Err(EINVAL),
111+
_ => {
112+
cls_pr_debug!(Errors, "Invalid sync type {}\n", data.sync_type);
113+
Err(EINVAL)
114+
}
101115
}
102116
}
103117

@@ -200,6 +214,7 @@ impl File {
200214
let gpu = &device.data().gpu;
201215

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

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

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

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

@@ -423,6 +441,7 @@ impl File {
423441
);
424442

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

@@ -451,6 +470,7 @@ impl File {
451470
);
452471

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

@@ -460,7 +480,10 @@ impl File {
460480
uapi::drm_asahi_bind_op_ASAHI_BIND_OP_UNBIND_ALL => {
461481
Self::do_gem_unbind_all(device, data, file)
462482
}
463-
_ => Err(EINVAL),
483+
_ => {
484+
cls_pr_debug!(Errors, "gem_bind: Invalid op {}\n", data.op);
485+
Err(EINVAL)
486+
}
464487
}
465488
}
466489

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

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

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

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

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

@@ -492,18 +524,42 @@ impl File {
492524

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

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

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

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

@@ -590,6 +652,7 @@ impl File {
590652
| uapi::drm_asahi_queue_cap_DRM_ASAHI_QUEUE_CAP_COMPUTE))
591653
!= 0
592654
{
655+
cls_pr_debug!(Errors, "queue_create: Invalid arguments\n");
593656
return Err(EINVAL);
594657
}
595658

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

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

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

659751
let gpu = &device.data().gpu;
660752
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

@@ -606,7 +625,10 @@ impl Queue for Queue::ver {
606625
match cmd.cmd_type {
607626
uapi::drm_asahi_cmd_type_DRM_ASAHI_CMD_RENDER => last_render = Some(i),
608627
uapi::drm_asahi_cmd_type_DRM_ASAHI_CMD_COMPUTE => last_compute = Some(i),
609-
_ => return Err(EINVAL),
628+
_ => {
629+
cls_pr_debug!(Errors, "Unknown command type {}\n", cmd.cmd_type);
630+
return Err(EINVAL);
631+
}
610632
}
611633
}
612634

@@ -621,7 +643,10 @@ impl Queue for Queue::ver {
621643
if *index == uapi::DRM_ASAHI_BARRIER_NONE as u32 {
622644
continue;
623645
}
624-
if let Some(event) = events[queue_idx].get(*index as usize).ok_or(EINVAL)? {
646+
if let Some(event) = events[queue_idx].get(*index as usize).ok_or_else(|| {
647+
cls_pr_debug!(Errors, "Invalid barrier #{}: {}\n", queue_idx, index);
648+
EINVAL
649+
})? {
625650
let mut alloc = gpu.alloc();
626651
let queue_job = match cmd.cmd_type {
627652
uapi::drm_asahi_cmd_type_DRM_ASAHI_CMD_RENDER => job.get_vtx()?,
@@ -655,18 +680,29 @@ impl Queue for Queue::ver {
655680
let result_writer = match result_buf.as_ref() {
656681
None => {
657682
if cmd.result_offset != 0 || cmd.result_size != 0 {
683+
cls_pr_debug!(Errors, "No result buffer but result requested\n");
658684
return Err(EINVAL);
659685
}
660686
None
661687
}
662688
Some(buf) => {
663689
if cmd.result_size != 0 {
664-
if cmd
690+
let end_offset = cmd
665691
.result_offset
666692
.checked_add(cmd.result_size)
667-
.ok_or(EINVAL)?
668-
> buf.size() as u64
669-
{
693+
.ok_or_else(|| {
694+
cls_pr_debug!(Errors, "result_offset + result_size overflow\n");
695+
EINVAL
696+
})?;
697+
if end_offset > buf.size() as u64 {
698+
cls_pr_debug!(
699+
Errors,
700+
"Result buffer overflow ({} + {} > {})\n",
701+
cmd.result_offset,
702+
cmd.result_size,
703+
buf.size()
704+
);
705+
670706
return Err(EINVAL);
671707
}
672708
Some(ResultWriter {

0 commit comments

Comments
 (0)