@@ -160,11 +160,16 @@ impl SyncItem {
160160 }
161161}
162162
163+ pub ( crate ) enum Object {
164+ TimestampBuffer ( Arc < mmu:: KernelMapping > ) ,
165+ }
166+
163167/// State associated with a client.
164168pub ( crate ) struct File {
165169 id : u64 ,
166170 vms : xarray:: XArray < KBox < Vm > > ,
167171 queues : xarray:: XArray < Arc < Mutex < KBox < dyn queue:: Queue > > > > ,
172+ objects : xarray:: XArray < KBox < Object > > ,
168173}
169174
170175/// Convenience type alias for our DRM `File` type.
@@ -192,6 +197,7 @@ impl drm::file::DriverFile for File {
192197 id,
193198 vms : xarray:: XArray :: new ( xarray:: flags:: ALLOC1 ) ,
194199 queues : xarray:: XArray :: new ( xarray:: flags:: ALLOC1 ) ,
200+ objects : xarray:: XArray :: new ( xarray:: flags:: ALLOC1 ) ,
195201 } ,
196202 GFP_KERNEL ,
197203 ) ?)
@@ -212,6 +218,12 @@ impl File {
212218 unsafe { self . map_unchecked ( |s| & s. queues ) }
213219 }
214220
221+ fn objects ( self : Pin < & Self > ) -> Pin < & xarray:: XArray < KBox < Object > > > {
222+ // SAFETY: Structural pinned projection for objects.
223+ // We never move out of this field.
224+ unsafe { self . map_unchecked ( |s| & s. objects ) }
225+ }
226+
215227 /// IOCTL: get_param: Get a driver parameter value.
216228 pub ( crate ) fn get_params (
217229 device : & AsahiDevice ,
@@ -721,6 +733,141 @@ impl File {
721733 Ok ( 0 )
722734 }
723735
736+ /// IOCTL: gem_bind_object: Map or unmap a GEM object as a special object.
737+ pub ( crate ) fn gem_bind_object (
738+ device : & AsahiDevice ,
739+ data : & mut uapi:: drm_asahi_gem_bind_object ,
740+ file : & DrmFile ,
741+ ) -> Result < u32 > {
742+ mod_dev_dbg ! (
743+ device,
744+ "[File {} VM {}]: IOCTL: gem_bind_object op={:?} handle={:#x?} flags={:#x?} {:#x?}:{:#x?} object_handle={:#x?}\n " ,
745+ file. inner( ) . id,
746+ data. vm_id,
747+ data. op,
748+ data. handle,
749+ data. flags,
750+ data. offset,
751+ data. range,
752+ data. object_handle
753+ ) ;
754+
755+ if data. extensions != 0 {
756+ cls_pr_debug ! ( Errors , "gem_bind_object: Unexpected extensions\n " ) ;
757+ return Err ( EINVAL ) ;
758+ }
759+
760+ if data. pad != 0 {
761+ cls_pr_debug ! ( Errors , "gem_bind_object: Unexpected pad\n " ) ;
762+ return Err ( EINVAL ) ;
763+ }
764+
765+ if data. vm_id != 0 {
766+ cls_pr_debug ! ( Errors , "gem_bind_object: Unexpected vm_id\n " ) ;
767+ return Err ( EINVAL ) ;
768+ }
769+
770+ match data. op {
771+ uapi:: drm_asahi_bind_object_op_ASAHI_BIND_OBJECT_OP_BIND => {
772+ Self :: do_gem_bind_object ( device, data, file)
773+ }
774+ uapi:: drm_asahi_bind_object_op_ASAHI_BIND_OBJECT_OP_UNBIND => {
775+ Self :: do_gem_unbind_object ( device, data, file)
776+ }
777+ _ => {
778+ cls_pr_debug ! ( Errors , "gem_bind_object: Invalid op {}\n " , data. op) ;
779+ Err ( EINVAL )
780+ }
781+ }
782+ }
783+
784+ pub ( crate ) fn do_gem_bind_object (
785+ device : & AsahiDevice ,
786+ data : & mut uapi:: drm_asahi_gem_bind_object ,
787+ file : & DrmFile ,
788+ ) -> Result < u32 > {
789+ if ( data. range | data. offset ) as usize & mmu:: UAT_PGMSK != 0 {
790+ cls_pr_debug ! (
791+ Errors ,
792+ "gem_bind_object: Range/offset not page aligned: {:#x} {:#x}\n " ,
793+ data. range,
794+ data. offset
795+ ) ;
796+ return Err ( EINVAL ) ; // Must be page aligned
797+ }
798+
799+ if data. flags != uapi:: ASAHI_BIND_OBJECT_USAGE_TIMESTAMPS {
800+ cls_pr_debug ! ( Errors , "gem_bind_object: Invalid flags {:#x}\n " , data. flags) ;
801+ return Err ( EINVAL ) ;
802+ }
803+
804+ let offset = data. offset . try_into ( ) ?;
805+ let end_offset = data
806+ . offset
807+ . checked_add ( data. range )
808+ . ok_or ( EINVAL ) ?
809+ . try_into ( ) ?;
810+ let bo = gem:: lookup_handle ( file, data. handle ) ?;
811+
812+ let mapping = Arc :: new (
813+ device
814+ . data ( )
815+ . gpu
816+ . map_timestamp_buffer ( bo, offset..end_offset) ?,
817+ GFP_KERNEL ,
818+ ) ?;
819+ let obj = KBox :: new ( Object :: TimestampBuffer ( mapping) , GFP_KERNEL ) ?;
820+ let handle = file. inner ( ) . objects ( ) . alloc ( obj) ? as u64 ;
821+
822+ data. object_handle = handle as u32 ;
823+ Ok ( 0 )
824+ }
825+
826+ pub ( crate ) fn do_gem_unbind_object (
827+ _device : & AsahiDevice ,
828+ data : & mut uapi:: drm_asahi_gem_bind_object ,
829+ file : & DrmFile ,
830+ ) -> Result < u32 > {
831+ if data. range != 0 || data. offset != 0 {
832+ cls_pr_debug ! (
833+ Errors ,
834+ "gem_unbind_object: Range/offset not zero: {:#x} {:#x}\n " ,
835+ data. range,
836+ data. offset
837+ ) ;
838+ return Err ( EINVAL ) ;
839+ }
840+
841+ if data. flags != 0 {
842+ cls_pr_debug ! (
843+ Errors ,
844+ "gem_unbind_object: Invalid flags {:#x}\n " ,
845+ data. flags
846+ ) ;
847+ return Err ( EINVAL ) ;
848+ }
849+
850+ if data. handle != 0 {
851+ cls_pr_debug ! (
852+ Errors ,
853+ "gem_unbind_object: Invalid handle {}\n " ,
854+ data. handle
855+ ) ;
856+ return Err ( EINVAL ) ;
857+ }
858+
859+ if file
860+ . inner ( )
861+ . objects ( )
862+ . remove ( data. object_handle as usize )
863+ . is_none ( )
864+ {
865+ Err ( ENOENT )
866+ } else {
867+ Ok ( 0 )
868+ }
869+ }
870+
724871 /// IOCTL: queue_create: Create a new command submission queue of a given type.
725872 pub ( crate ) fn queue_create (
726873 device : & AsahiDevice ,
0 commit comments