@@ -162,11 +162,16 @@ impl SyncItem {
162162 }
163163}
164164
165+ pub ( crate ) enum Object {
166+ TimestampBuffer ( Arc < mmu:: KernelMapping > ) ,
167+ }
168+
165169/// State associated with a client.
166170pub ( crate ) struct File {
167171 id : u64 ,
168172 vms : xarray:: XArray < KBox < Vm > > ,
169173 queues : xarray:: XArray < Arc < Mutex < KBox < dyn queue:: Queue > > > > ,
174+ objects : xarray:: XArray < KBox < Object > > ,
170175}
171176
172177/// Convenience type alias for our DRM `File` type.
@@ -197,6 +202,7 @@ impl drm::file::DriverFile for File {
197202 id,
198203 vms : xarray:: XArray :: new ( xarray:: flags:: ALLOC1 ) ,
199204 queues : xarray:: XArray :: new ( xarray:: flags:: ALLOC1 ) ,
205+ objects : xarray:: XArray :: new ( xarray:: flags:: ALLOC1 ) ,
200206 } ,
201207 GFP_KERNEL ,
202208 ) ?)
@@ -217,6 +223,12 @@ impl File {
217223 unsafe { self . map_unchecked ( |s| & s. queues ) }
218224 }
219225
226+ fn objects ( self : Pin < & Self > ) -> Pin < & xarray:: XArray < KBox < Object > > > {
227+ // SAFETY: Structural pinned projection for objects.
228+ // We never move out of this field.
229+ unsafe { self . map_unchecked ( |s| & s. objects ) }
230+ }
231+
220232 /// IOCTL: get_param: Get a driver parameter value.
221233 pub ( crate ) fn get_params (
222234 device : & AsahiDevice ,
@@ -733,6 +745,141 @@ impl File {
733745 Ok ( 0 )
734746 }
735747
748+ /// IOCTL: gem_bind_object: Map or unmap a GEM object as a special object.
749+ pub ( crate ) fn gem_bind_object (
750+ device : & AsahiDevice ,
751+ dev_data : <Self as drm:: file:: DriverFile >:: BorrowedData < ' _ > ,
752+ data : & mut uapi:: drm_asahi_gem_bind_object ,
753+ file : & DrmFile ,
754+ ) -> Result < u32 > {
755+ mod_dev_dbg ! (
756+ device,
757+ "[File {} VM {}]: IOCTL: gem_bind_object op={:?} handle={:#x?} flags={:#x?} {:#x?}:{:#x?} object_handle={:#x?}\n " ,
758+ file. inner( ) . id,
759+ data. vm_id,
760+ data. op,
761+ data. handle,
762+ data. flags,
763+ data. offset,
764+ data. range,
765+ data. object_handle
766+ ) ;
767+
768+ if data. extensions != 0 {
769+ cls_pr_debug ! ( Errors , "gem_bind_object: Unexpected extensions\n " ) ;
770+ return Err ( EINVAL ) ;
771+ }
772+
773+ if data. pad != 0 {
774+ cls_pr_debug ! ( Errors , "gem_bind_object: Unexpected pad\n " ) ;
775+ return Err ( EINVAL ) ;
776+ }
777+
778+ if data. vm_id != 0 {
779+ cls_pr_debug ! ( Errors , "gem_bind_object: Unexpected vm_id\n " ) ;
780+ return Err ( EINVAL ) ;
781+ }
782+
783+ match data. op {
784+ uapi:: drm_asahi_bind_object_op_ASAHI_BIND_OBJECT_OP_BIND => {
785+ Self :: do_gem_bind_object ( device, dev_data, data, file)
786+ }
787+ uapi:: drm_asahi_bind_object_op_ASAHI_BIND_OBJECT_OP_UNBIND => {
788+ Self :: do_gem_unbind_object ( device, dev_data, data, file)
789+ }
790+ _ => {
791+ cls_pr_debug ! ( Errors , "gem_bind_object: Invalid op {}\n " , data. op) ;
792+ Err ( EINVAL )
793+ }
794+ }
795+ }
796+
797+ pub ( crate ) fn do_gem_bind_object (
798+ _device : & AsahiDevice ,
799+ dev_data : <Self as drm:: file:: DriverFile >:: BorrowedData < ' _ > ,
800+ data : & mut uapi:: drm_asahi_gem_bind_object ,
801+ file : & DrmFile ,
802+ ) -> Result < u32 > {
803+ if ( data. range | data. offset ) as usize & mmu:: UAT_PGMSK != 0 {
804+ cls_pr_debug ! (
805+ Errors ,
806+ "gem_bind_object: Range/offset not page aligned: {:#x} {:#x}\n " ,
807+ data. range,
808+ data. offset
809+ ) ;
810+ return Err ( EINVAL ) ; // Must be page aligned
811+ }
812+
813+ if data. flags != uapi:: ASAHI_BIND_OBJECT_USAGE_TIMESTAMPS {
814+ cls_pr_debug ! ( Errors , "gem_bind_object: Invalid flags {:#x}\n " , data. flags) ;
815+ return Err ( EINVAL ) ;
816+ }
817+
818+ let offset = data. offset . try_into ( ) ?;
819+ let end_offset = data
820+ . offset
821+ . checked_add ( data. range )
822+ . ok_or ( EINVAL ) ?
823+ . try_into ( ) ?;
824+ let bo = gem:: lookup_handle ( file, data. handle ) ?;
825+
826+ let mapping = Arc :: new (
827+ dev_data. gpu . map_timestamp_buffer ( bo, offset..end_offset) ?,
828+ GFP_KERNEL ,
829+ ) ?;
830+ let obj = KBox :: new ( Object :: TimestampBuffer ( mapping) , GFP_KERNEL ) ?;
831+ let handle = file. inner ( ) . objects ( ) . alloc ( obj) ? as u64 ;
832+
833+ data. object_handle = handle as u32 ;
834+ Ok ( 0 )
835+ }
836+
837+ pub ( crate ) fn do_gem_unbind_object (
838+ _device : & AsahiDevice ,
839+ _dev_data : <Self as drm:: file:: DriverFile >:: BorrowedData < ' _ > ,
840+ data : & mut uapi:: drm_asahi_gem_bind_object ,
841+ file : & DrmFile ,
842+ ) -> Result < u32 > {
843+ if data. range != 0 || data. offset != 0 {
844+ cls_pr_debug ! (
845+ Errors ,
846+ "gem_unbind_object: Range/offset not zero: {:#x} {:#x}\n " ,
847+ data. range,
848+ data. offset
849+ ) ;
850+ return Err ( EINVAL ) ;
851+ }
852+
853+ if data. flags != 0 {
854+ cls_pr_debug ! (
855+ Errors ,
856+ "gem_unbind_object: Invalid flags {:#x}\n " ,
857+ data. flags
858+ ) ;
859+ return Err ( EINVAL ) ;
860+ }
861+
862+ if data. handle != 0 {
863+ cls_pr_debug ! (
864+ Errors ,
865+ "gem_unbind_object: Invalid handle {}\n " ,
866+ data. handle
867+ ) ;
868+ return Err ( EINVAL ) ;
869+ }
870+
871+ if file
872+ . inner ( )
873+ . objects ( )
874+ . remove ( data. object_handle as usize )
875+ . is_none ( )
876+ {
877+ Err ( ENOENT )
878+ } else {
879+ Ok ( 0 )
880+ }
881+ }
882+
736883 /// IOCTL: queue_create: Create a new command submission queue of a given type.
737884 pub ( crate ) fn queue_create (
738885 device : & AsahiDevice ,
0 commit comments