@@ -420,41 +420,27 @@ void qxl_io_monitors_config(struct qxl_device *qdev)
int qxl_surface_id_alloc(struct qxl_device *qdev,
struct qxl_bo *surf)
{
- uint32_t handle;
- int idr_ret;
- int count = 0;
+ int ret;
again:
- idr_preload(GFP_ATOMIC);
- spin_lock(&qdev->surf_id_idr_lock);
- idr_ret = idr_alloc(&qdev->surf_id_idr, NULL, 1, 0, GFP_NOWAIT);
- spin_unlock(&qdev->surf_id_idr_lock);
- idr_preload_end();
- if (idr_ret < 0)
- return idr_ret;
- handle = idr_ret;
-
- if (handle >= qdev->rom->n_surfaces) {
- count++;
- spin_lock(&qdev->surf_id_idr_lock);
- idr_remove(&qdev->surf_id_idr, handle);
- spin_unlock(&qdev->surf_id_idr_lock);
+ ret = xa_alloc(&qdev->surfaces, &surf->surface_id, NULL,
+ XA_LIMIT(0, qdev->rom->n_surfaces - 1), GFP_ATOMIC);
+ if (ret == -EBUSY) {
qxl_reap_surface_id(qdev, 2);
goto again;
}
- surf->surface_id = handle;
+ if (ret < 0)
+ return ret;
- spin_lock(&qdev->surf_id_idr_lock);
- qdev->last_alloced_surf_id = handle;
- spin_unlock(&qdev->surf_id_idr_lock);
+ xa_lock(&qdev->surfaces);
+ qdev->last_alloced_surf_id = surf->surface_id;
+ xa_unlock(&qdev->surfaces);
return 0;
}
void qxl_surface_id_dealloc(struct qxl_device *qdev,
uint32_t surface_id)
{
- spin_lock(&qdev->surf_id_idr_lock);
- idr_remove(&qdev->surf_id_idr, surface_id);
- spin_unlock(&qdev->surf_id_idr_lock);
+ xa_erase(&qdev->surfaces, surface_id);
}
int qxl_hw_surface_alloc(struct qxl_device *qdev,
@@ -507,9 +493,7 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
qxl_release_fence_buffer_objects(release);
surf->hw_surf_alloc = true;
- spin_lock(&qdev->surf_id_idr_lock);
- idr_replace(&qdev->surf_id_idr, surf, surf->surface_id);
- spin_unlock(&qdev->surf_id_idr_lock);
+ xa_store(&qdev->surfaces, surf->surface_id, surf, GFP_KERNEL);
return 0;
}
@@ -531,10 +515,8 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev,
return ret;
surf->surf_create = NULL;
- /* remove the surface from the idr, but not the surface id yet */
- spin_lock(&qdev->surf_id_idr_lock);
- idr_replace(&qdev->surf_id_idr, NULL, surf->surface_id);
- spin_unlock(&qdev->surf_id_idr_lock);
+ /* remove the surface from the array, but don't free the surface id */
+ xa_store(&qdev->surfaces, surf->surface_id, NULL, 0);
surf->hw_surf_alloc = false;
id = surf->surface_id;
@@ -623,20 +605,20 @@ static int qxl_reap_surface_id(struct qxl_device *qdev, int max_to_reap)
mutex_lock(&qdev->surf_evict_mutex);
again:
- spin_lock(&qdev->surf_id_idr_lock);
+ xa_lock(&qdev->surfaces);
start = qdev->last_alloced_surf_id + 1;
- spin_unlock(&qdev->surf_id_idr_lock);
+ xa_unlock(&qdev->surfaces);
for (i = start; i < start + qdev->rom->n_surfaces; i++) {
void *objptr;
int surfid = i % qdev->rom->n_surfaces;
- /* this avoids the case where the objects is in the
- idr but has been evicted half way - its makes
- the idr lookup atomic with the eviction */
- spin_lock(&qdev->surf_id_idr_lock);
- objptr = idr_find(&qdev->surf_id_idr, surfid);
- spin_unlock(&qdev->surf_id_idr_lock);
+ /* this avoids the case where the object is in the
+ array but has been evicted half way - it makes
+ the array lookup atomic with the eviction */
+ xa_lock(&qdev->surfaces);
+ objptr = xa_load(&qdev->surfaces, surfid);
+ xa_unlock(&qdev->surfaces);
if (!objptr)
continue;
@@ -260,8 +260,7 @@ struct qxl_device {
struct mutex update_area_mutex;
- struct idr surf_id_idr;
- spinlock_t surf_id_idr_lock;
+ struct xarray surfaces;
int last_alloced_surf_id;
struct mutex surf_evict_mutex;
@@ -249,10 +249,7 @@ int qxl_device_init(struct qxl_device *qdev,
xa_init_flags(&qdev->releases, XA_FLAGS_ALLOC1);
spin_lock_init(&qdev->release_lock);
-
- idr_init(&qdev->surf_id_idr);
- spin_lock_init(&qdev->surf_id_idr_lock);
-
+ xa_init_flags(&qdev->surfaces, XA_FLAGS_ALLOC1);
mutex_init(&qdev->async_io_mutex);
/* reset the device into a known state - no memslots, no primary
Signed-off-by: Matthew Wilcox <willy@infradead.org> --- drivers/gpu/drm/qxl/qxl_cmd.c | 60 ++++++++++++----------------------- drivers/gpu/drm/qxl/qxl_drv.h | 3 +- drivers/gpu/drm/qxl/qxl_kms.c | 5 +-- 3 files changed, 23 insertions(+), 45 deletions(-)