3434#include <linux/pseudo_fs.h>
3535#include <linux/slab.h>
3636#include <linux/srcu.h>
37+ #include <linux/xarray.h>
3738
3839#include <drm/drm_accel.h>
3940#include <drm/drm_cache.h>
@@ -54,8 +55,7 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
5455MODULE_DESCRIPTION ("DRM shared core routines" );
5556MODULE_LICENSE ("GPL and additional rights" );
5657
57- static DEFINE_SPINLOCK (drm_minor_lock );
58- static struct idr drm_minors_idr ;
58+ static DEFINE_XARRAY_ALLOC (drm_minors_xa );
5959
6060/*
6161 * If the drm core fails to init for whatever reason,
@@ -101,26 +101,23 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
101101static void drm_minor_alloc_release (struct drm_device * dev , void * data )
102102{
103103 struct drm_minor * minor = data ;
104- unsigned long flags ;
105104
106105 WARN_ON (dev != minor -> dev );
107106
108107 put_device (minor -> kdev );
109108
110- if (minor -> type == DRM_MINOR_ACCEL ) {
109+ if (minor -> type == DRM_MINOR_ACCEL )
111110 accel_minor_remove (minor -> index );
112- } else {
113- spin_lock_irqsave (& drm_minor_lock , flags );
114- idr_remove (& drm_minors_idr , minor -> index );
115- spin_unlock_irqrestore (& drm_minor_lock , flags );
116- }
111+ else
112+ xa_erase (& drm_minors_xa , minor -> index );
117113}
118114
115+ #define DRM_MINOR_LIMIT (t ) ({ typeof(t) _t = (t); XA_LIMIT(64 * _t, 64 * _t + 63); })
116+
119117static int drm_minor_alloc (struct drm_device * dev , enum drm_minor_type type )
120118{
121119 struct drm_minor * minor ;
122- unsigned long flags ;
123- int r ;
120+ int index , r ;
124121
125122 minor = drmm_kzalloc (dev , sizeof (* minor ), GFP_KERNEL );
126123 if (!minor )
@@ -129,24 +126,17 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
129126 minor -> type = type ;
130127 minor -> dev = dev ;
131128
132- idr_preload (GFP_KERNEL );
133129 if (type == DRM_MINOR_ACCEL ) {
134130 r = accel_minor_alloc ();
131+ index = r ;
135132 } else {
136- spin_lock_irqsave (& drm_minor_lock , flags );
137- r = idr_alloc (& drm_minors_idr ,
138- NULL ,
139- 64 * type ,
140- 64 * (type + 1 ),
141- GFP_NOWAIT );
142- spin_unlock_irqrestore (& drm_minor_lock , flags );
133+ r = xa_alloc (& drm_minors_xa , & index , NULL , DRM_MINOR_LIMIT (type ), GFP_KERNEL );
143134 }
144- idr_preload_end ();
145135
146136 if (r < 0 )
147137 return r ;
148138
149- minor -> index = r ;
139+ minor -> index = index ;
150140
151141 r = drmm_add_action_or_reset (dev , drm_minor_alloc_release , minor );
152142 if (r )
@@ -163,7 +153,7 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
163153static int drm_minor_register (struct drm_device * dev , enum drm_minor_type type )
164154{
165155 struct drm_minor * minor ;
166- unsigned long flags ;
156+ void * entry ;
167157 int ret ;
168158
169159 DRM_DEBUG ("\n" );
@@ -189,9 +179,12 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
189179 if (minor -> type == DRM_MINOR_ACCEL ) {
190180 accel_minor_replace (minor , minor -> index );
191181 } else {
192- spin_lock_irqsave (& drm_minor_lock , flags );
193- idr_replace (& drm_minors_idr , minor , minor -> index );
194- spin_unlock_irqrestore (& drm_minor_lock , flags );
182+ entry = xa_store (& drm_minors_xa , minor -> index , minor , GFP_KERNEL );
183+ if (xa_is_err (entry )) {
184+ ret = xa_err (entry );
185+ goto err_debugfs ;
186+ }
187+ WARN_ON (entry );
195188 }
196189
197190 DRM_DEBUG ("new minor registered %d\n" , minor -> index );
@@ -205,20 +198,16 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
205198static void drm_minor_unregister (struct drm_device * dev , enum drm_minor_type type )
206199{
207200 struct drm_minor * minor ;
208- unsigned long flags ;
209201
210202 minor = * drm_minor_get_slot (dev , type );
211203 if (!minor || !device_is_registered (minor -> kdev ))
212204 return ;
213205
214206 /* replace @minor with NULL so lookups will fail from now on */
215- if (minor -> type == DRM_MINOR_ACCEL ) {
207+ if (minor -> type == DRM_MINOR_ACCEL )
216208 accel_minor_replace (NULL , minor -> index );
217- } else {
218- spin_lock_irqsave (& drm_minor_lock , flags );
219- idr_replace (& drm_minors_idr , NULL , minor -> index );
220- spin_unlock_irqrestore (& drm_minor_lock , flags );
221- }
209+ else
210+ xa_store (& drm_minors_xa , minor -> index , NULL , GFP_KERNEL );
222211
223212 device_del (minor -> kdev );
224213 dev_set_drvdata (minor -> kdev , NULL ); /* safety belt */
@@ -237,13 +226,12 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ
237226struct drm_minor * drm_minor_acquire (unsigned int minor_id )
238227{
239228 struct drm_minor * minor ;
240- unsigned long flags ;
241229
242- spin_lock_irqsave ( & drm_minor_lock , flags );
243- minor = idr_find ( & drm_minors_idr , minor_id );
230+ xa_lock ( & drm_minors_xa );
231+ minor = xa_load ( & drm_minors_xa , minor_id );
244232 if (minor )
245233 drm_dev_get (minor -> dev );
246- spin_unlock_irqrestore ( & drm_minor_lock , flags );
234+ xa_unlock ( & drm_minors_xa );
247235
248236 if (!minor ) {
249237 return ERR_PTR (- ENODEV );
@@ -1071,7 +1059,7 @@ static void drm_core_exit(void)
10711059 unregister_chrdev (DRM_MAJOR , "drm" );
10721060 debugfs_remove (drm_debugfs_root );
10731061 drm_sysfs_destroy ();
1074- idr_destroy ( & drm_minors_idr );
1062+ WARN_ON (! xa_empty ( & drm_minors_xa ) );
10751063 drm_connector_ida_destroy ();
10761064}
10771065
@@ -1080,7 +1068,6 @@ static int __init drm_core_init(void)
10801068 int ret ;
10811069
10821070 drm_connector_ida_init ();
1083- idr_init (& drm_minors_idr );
10841071 drm_memcpy_init_early ();
10851072
10861073 ret = drm_sysfs_init ();
0 commit comments