@@ -23,6 +23,13 @@ struct idxd_cdev_context {
2323 struct ida minor_ida ;
2424};
2525
26+ /*
27+ * Since user file names are global in DSA devices, define their ida's as
28+ * global to avoid conflict file names.
29+ */
30+ static DEFINE_IDA (file_ida );
31+ static DEFINE_MUTEX (ida_lock );
32+
2633/*
2734 * ictx is an array based off of accelerator types. enum idxd_type
2835 * is used as index
@@ -39,7 +46,60 @@ struct idxd_user_context {
3946 struct mm_struct * mm ;
4047 unsigned int flags ;
4148 struct iommu_sva * sva ;
49+ struct idxd_dev idxd_dev ;
4250 u64 counters [COUNTER_MAX ];
51+ int id ;
52+ };
53+
54+ static void idxd_cdev_evl_drain_pasid (struct idxd_wq * wq , u32 pasid );
55+ static void idxd_xa_pasid_remove (struct idxd_user_context * ctx );
56+
57+ static inline struct idxd_user_context * dev_to_uctx (struct device * dev )
58+ {
59+ struct idxd_dev * idxd_dev = confdev_to_idxd_dev (dev );
60+
61+ return container_of (idxd_dev , struct idxd_user_context , idxd_dev );
62+ }
63+
64+ static void idxd_file_dev_release (struct device * dev )
65+ {
66+ struct idxd_user_context * ctx = dev_to_uctx (dev );
67+ struct idxd_wq * wq = ctx -> wq ;
68+ struct idxd_device * idxd = wq -> idxd ;
69+ int rc ;
70+
71+ mutex_lock (& ida_lock );
72+ ida_free (& file_ida , ctx -> id );
73+ mutex_unlock (& ida_lock );
74+
75+ /* Wait for in-flight operations to complete. */
76+ if (wq_shared (wq )) {
77+ idxd_device_drain_pasid (idxd , ctx -> pasid );
78+ } else {
79+ if (device_user_pasid_enabled (idxd )) {
80+ /* The wq disable in the disable pasid function will drain the wq */
81+ rc = idxd_wq_disable_pasid (wq );
82+ if (rc < 0 )
83+ dev_err (dev , "wq disable pasid failed.\n" );
84+ } else {
85+ idxd_wq_drain (wq );
86+ }
87+ }
88+
89+ if (ctx -> sva ) {
90+ idxd_cdev_evl_drain_pasid (wq , ctx -> pasid );
91+ iommu_sva_unbind_device (ctx -> sva );
92+ idxd_xa_pasid_remove (ctx );
93+ }
94+ kfree (ctx );
95+ mutex_lock (& wq -> wq_lock );
96+ idxd_wq_put (wq );
97+ mutex_unlock (& wq -> wq_lock );
98+ }
99+
100+ static struct device_type idxd_cdev_file_type = {
101+ .name = "idxd_file" ,
102+ .release = idxd_file_dev_release ,
43103};
44104
45105static void idxd_cdev_dev_release (struct device * dev )
@@ -107,10 +167,11 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
107167 struct idxd_user_context * ctx ;
108168 struct idxd_device * idxd ;
109169 struct idxd_wq * wq ;
110- struct device * dev ;
170+ struct device * dev , * fdev ;
111171 int rc = 0 ;
112172 struct iommu_sva * sva ;
113173 unsigned int pasid ;
174+ struct idxd_cdev * idxd_cdev ;
114175
115176 wq = inode_wq (inode );
116177 idxd = wq -> idxd ;
@@ -166,10 +227,41 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
166227 }
167228 }
168229
230+ idxd_cdev = wq -> idxd_cdev ;
231+ mutex_lock (& ida_lock );
232+ ctx -> id = ida_alloc (& file_ida , GFP_KERNEL );
233+ mutex_unlock (& ida_lock );
234+ if (ctx -> id < 0 ) {
235+ dev_warn (dev , "ida alloc failure\n" );
236+ goto failed_ida ;
237+ }
238+ ctx -> idxd_dev .type = IDXD_DEV_CDEV_FILE ;
239+ fdev = user_ctx_dev (ctx );
240+ device_initialize (fdev );
241+ fdev -> parent = cdev_dev (idxd_cdev );
242+ fdev -> bus = & dsa_bus_type ;
243+ fdev -> type = & idxd_cdev_file_type ;
244+
245+ rc = dev_set_name (fdev , "file%d" , ctx -> id );
246+ if (rc < 0 ) {
247+ dev_warn (dev , "set name failure\n" );
248+ goto failed_dev_name ;
249+ }
250+
251+ rc = device_add (fdev );
252+ if (rc < 0 ) {
253+ dev_warn (dev , "file device add failure\n" );
254+ goto failed_dev_add ;
255+ }
256+
169257 idxd_wq_get (wq );
170258 mutex_unlock (& wq -> wq_lock );
171259 return 0 ;
172260
261+ failed_dev_add :
262+ failed_dev_name :
263+ put_device (fdev );
264+ failed_ida :
173265failed_set_pasid :
174266 if (device_user_pasid_enabled (idxd ))
175267 idxd_xa_pasid_remove (ctx );
@@ -217,34 +309,12 @@ static int idxd_cdev_release(struct inode *node, struct file *filep)
217309 struct idxd_wq * wq = ctx -> wq ;
218310 struct idxd_device * idxd = wq -> idxd ;
219311 struct device * dev = & idxd -> pdev -> dev ;
220- int rc ;
221312
222313 dev_dbg (dev , "%s called\n" , __func__ );
223314 filep -> private_data = NULL ;
224315
225- /* Wait for in-flight operations to complete. */
226- if (wq_shared (wq )) {
227- idxd_device_drain_pasid (idxd , ctx -> pasid );
228- } else {
229- if (device_user_pasid_enabled (idxd )) {
230- /* The wq disable in the disable pasid function will drain the wq */
231- rc = idxd_wq_disable_pasid (wq );
232- if (rc < 0 )
233- dev_err (dev , "wq disable pasid failed.\n" );
234- } else {
235- idxd_wq_drain (wq );
236- }
237- }
316+ device_unregister (user_ctx_dev (ctx ));
238317
239- if (ctx -> sva ) {
240- idxd_cdev_evl_drain_pasid (wq , ctx -> pasid );
241- iommu_sva_unbind_device (ctx -> sva );
242- idxd_xa_pasid_remove (ctx );
243- }
244- kfree (ctx );
245- mutex_lock (& wq -> wq_lock );
246- idxd_wq_put (wq );
247- mutex_unlock (& wq -> wq_lock );
248318 return 0 ;
249319}
250320
@@ -375,6 +445,7 @@ void idxd_wq_del_cdev(struct idxd_wq *wq)
375445 struct idxd_cdev * idxd_cdev ;
376446
377447 idxd_cdev = wq -> idxd_cdev ;
448+ ida_destroy (& file_ida );
378449 wq -> idxd_cdev = NULL ;
379450 cdev_device_del (& idxd_cdev -> cdev , cdev_dev (idxd_cdev ));
380451 put_device (cdev_dev (idxd_cdev ));
0 commit comments