@@ -33,6 +33,7 @@ use kernel::{
3333 Arc , Mutex ,
3434 } ,
3535 uapi,
36+ workqueue:: { self , impl_has_work, new_work, Work , WorkItem } ,
3637} ;
3738
3839const DEBUG_CLASS : DebugFlags = DebugFlags :: WorkQueue ;
@@ -172,6 +173,32 @@ pub(crate) trait GenSubmittedWork: Send + Sync {
172173 fn get_fence ( & self ) -> dma_fence:: Fence ;
173174}
174175
176+ #[ pin_data]
177+ struct SubmittedWorkContainer {
178+ #[ pin]
179+ work : Work < Self > ,
180+ inner : Box < dyn GenSubmittedWork > ,
181+ }
182+
183+ impl_has_work ! {
184+ impl HasWork <Self > for SubmittedWorkContainer { self . work }
185+ }
186+
187+ impl WorkItem for SubmittedWorkContainer {
188+ type Pointer = Pin < Box < SubmittedWorkContainer > > ;
189+
190+ fn run ( this : Pin < Box < SubmittedWorkContainer > > ) {
191+ mod_pr_debug ! ( "WorkQueue: Freeing command @ {:?}\n " , this. inner. gpu_va( ) ) ;
192+ }
193+ }
194+
195+ impl SubmittedWorkContainer {
196+ fn inner_mut ( self : Pin < & mut Self > ) -> & mut Box < dyn GenSubmittedWork > {
197+ // SAFETY: inner does not require structural pinning.
198+ unsafe { & mut self . get_unchecked_mut ( ) . inner }
199+ }
200+ }
201+
175202impl < O : OpaqueGpuObject , C : FnOnce ( & mut O , Option < WorkError > ) + Send + Sync > GenSubmittedWork
176203 for SubmittedWork < O , C >
177204{
@@ -220,7 +247,7 @@ struct WorkQueueInner {
220247 pipe_type : PipeType ,
221248 size : u32 ,
222249 wptr : u32 ,
223- pending : Vec < Box < dyn GenSubmittedWork > > ,
250+ pending : Vec < Pin < Box < SubmittedWorkContainer > > > ,
224251 last_token : Option < event:: Token > ,
225252 pending_jobs : usize ,
226253 last_submitted : Option < event:: EventValue > ,
@@ -269,7 +296,7 @@ pub(crate) struct Job {
269296 wq : Arc < WorkQueue :: ver > ,
270297 event_info : QueueEventInfo :: ver ,
271298 start_value : EventValue ,
272- pending : Vec < Box < dyn GenSubmittedWork > > ,
299+ pending : Vec < Pin < Box < SubmittedWorkContainer > > > ,
273300 committed : bool ,
274301 submitted : bool ,
275302 event_count : usize ,
@@ -318,17 +345,23 @@ impl Job::ver {
318345 return Err ( EINVAL ) ;
319346 }
320347
348+ let fence = self . fence . clone ( ) ;
349+ let value = self . event_info . value . next ( ) ;
350+
321351 self . pending . push (
322- Box :: new (
323- SubmittedWork :: < _ , _ > {
324- object : command,
325- value : self . event_info . value . next ( ) ,
326- error : None ,
327- callback : Some ( callback) ,
328- wptr : 0 ,
329- vm_slot,
330- fence : self . fence . clone ( ) ,
331- } ,
352+ Box :: try_pin_init (
353+ try_pin_init ! ( SubmittedWorkContainer {
354+ work <- new_work!( "SubmittedWorkWrapper::work" ) ,
355+ inner: Box :: new( SubmittedWork :: <_, _> {
356+ object: command,
357+ value,
358+ error: None ,
359+ callback: Some ( callback) ,
360+ wptr: 0 ,
361+ vm_slot,
362+ fence,
363+ } , GFP_KERNEL ) ?
364+ } ) ,
332365 GFP_KERNEL ,
333366 ) ?,
334367 GFP_KERNEL ,
@@ -375,7 +408,7 @@ impl Job::ver {
375408 if inner. free_slots ( ) > self . event_count && inner. free_space ( ) > self . pending . len ( ) {
376409 None
377410 } else if let Some ( work) = inner. pending . first ( ) {
378- Some ( work. get_fence ( ) )
411+ Some ( work. inner . get_fence ( ) )
379412 } else {
380413 pr_err ! (
381414 "WorkQueue: Cannot submit, but queue is empty? {} > {}, {} > {} (pend={} ls={:#x?} lc={:#x?}) ev={:#x?} cur={:#x?} slot {:?}\n " ,
@@ -453,11 +486,11 @@ impl Job::ver {
453486 ) ;
454487
455488 for mut command in self . pending . drain ( ..) {
456- command. set_wptr ( wptr) ;
489+ command. as_mut ( ) . inner_mut ( ) . set_wptr ( wptr) ;
457490
458491 let next_wptr = ( wptr + 1 ) % inner. size ;
459492 assert ! ( inner. doneptr( ) != next_wptr) ;
460- inner. info . ring [ wptr as usize ] = command. gpu_va ( ) . get ( ) ;
493+ inner. info . ring [ wptr as usize ] = command. inner . gpu_va ( ) . get ( ) ;
461494 wptr = next_wptr;
462495
463496 // Cannot fail, since we did a reserve(1) above
@@ -862,11 +895,11 @@ impl WorkQueue for WorkQueue::ver {
862895 let mut completed_commands: usize = 0 ;
863896
864897 for cmd in inner. pending . iter ( ) {
865- if cmd. value ( ) <= value {
898+ if cmd. inner . value ( ) <= value {
866899 mod_pr_debug ! (
867900 "WorkQueue({:?}): Command at value {:#x?} complete\n " ,
868901 inner. pipe_type,
869- cmd. value( )
902+ cmd. inner . value( )
870903 ) ;
871904 completed_commands += 1 ;
872905 } else {
@@ -878,25 +911,17 @@ impl WorkQueue for WorkQueue::ver {
878911 return inner. pending . is_empty ( ) ;
879912 }
880913
881- let mut completed = Vec :: new ( ) ;
882-
883- if completed. reserve ( completed_commands, GFP_KERNEL ) . is_err ( ) {
884- pr_crit ! (
885- "WorkQueue({:?}): Failed to allocate space for {} completed commands\n " ,
886- inner. pipe_type,
887- completed_commands
888- ) ;
889- }
890-
914+ let last_wptr = inner. pending [ completed_commands - 1 ] . inner . wptr ( ) ;
891915 let pipe_type = inner. pipe_type ;
892916
893- for cmd in inner. pending . drain ( ..completed_commands) {
894- if completed. push ( cmd, GFP_KERNEL ) . is_err ( ) {
895- pr_crit ! (
896- "WorkQueue({:?}): Failed to signal a completed command\n " ,
897- pipe_type,
898- ) ;
899- }
917+ for mut cmd in inner. pending . drain ( ..completed_commands) {
918+ mod_pr_debug ! (
919+ "WorkQueue({:?}): Queueing command @ {:?} for cleanup\n " ,
920+ pipe_type,
921+ cmd. inner. gpu_va( )
922+ ) ;
923+ cmd. as_mut ( ) . inner_mut ( ) . complete ( ) ;
924+ workqueue:: system ( ) . enqueue ( cmd) ;
900925 }
901926
902927 mod_pr_debug ! (
@@ -908,12 +933,10 @@ impl WorkQueue for WorkQueue::ver {
908933 inner. last_completed,
909934 ) ;
910935
911- if let Some ( i) = completed. last ( ) {
912- inner
913- . info
914- . state
915- . with ( |raw, _inner| raw. cpu_freeptr . store ( i. wptr ( ) , Ordering :: Release ) ) ;
916- }
936+ inner
937+ . info
938+ . state
939+ . with ( |raw, _inner| raw. cpu_freeptr . store ( last_wptr, Ordering :: Release ) ) ;
917940
918941 let empty = inner. pending . is_empty ( ) ;
919942 if empty && inner. pending_jobs == 0 {
@@ -922,16 +945,6 @@ impl WorkQueue for WorkQueue::ver {
922945 inner. last_completed = None ;
923946 }
924947
925- let dev = inner. dev . clone ( ) ;
926- core:: mem:: drop ( inner) ;
927-
928- for cmd in completed. iter_mut ( ) {
929- cmd. complete ( ) ;
930- }
931-
932- let gpu = & dev. data ( ) . gpu ;
933- gpu. add_completed_work ( completed) ;
934-
935948 empty
936949 }
937950
@@ -960,8 +973,8 @@ impl WorkQueue for WorkQueue::ver {
960973 ) ;
961974
962975 for cmd in inner. pending . iter_mut ( ) {
963- if cmd. value ( ) <= value {
964- cmd. mark_error ( error) ;
976+ if cmd. inner . value ( ) <= value {
977+ cmd. as_mut ( ) . inner_mut ( ) . mark_error ( error) ;
965978 } else {
966979 break ;
967980 }
@@ -1002,8 +1015,8 @@ impl WorkQueue for WorkQueue::ver {
10021015 core:: mem:: drop ( inner) ;
10031016
10041017 for mut cmd in cmds {
1005- cmd. mark_error ( error) ;
1006- cmd. complete ( ) ;
1018+ cmd. as_mut ( ) . inner_mut ( ) . mark_error ( error) ;
1019+ cmd. as_mut ( ) . inner_mut ( ) . complete ( ) ;
10071020 }
10081021 }
10091022}
0 commit comments