amdgpu_xcp_select_scheds() reads the per-XCP scheduler list.
Partition switching rebuilds the same table under xcp_lock.

Take xcp_lock around XCP scheduler selection and release.
This prevents readers from observing partially rebuilt state.

Also revalidate the selected XCP id before indexing the table.
An open file can outlive a switch to another partition mode.

Signed-off-by: Xiang Liu <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c | 37 +++++++++++++++++--------
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
index 88e6eab91bc6..1db7d2ad01fc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
@@ -469,16 +469,21 @@ void amdgpu_xcp_release_sched(struct amdgpu_device *adev,
 {
        struct drm_gpu_scheduler *sched;
        struct amdgpu_ring *ring;
+       struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr;
 
-       if (!adev->xcp_mgr)
+       if (!xcp_mgr)
                return;
 
        sched = entity->entity.rq->sched;
-       if (drm_sched_wqueue_ready(sched)) {
-               ring = to_amdgpu_ring(entity->entity.rq->sched);
-               if (ring->xcp_id < MAX_XCP)
-                       atomic_dec(&adev->xcp_mgr->xcp[ring->xcp_id].ref_cnt);
-       }
+       if (!drm_sched_wqueue_ready(sched))
+               return;
+
+       ring = to_amdgpu_ring(sched);
+
+       mutex_lock(&xcp_mgr->xcp_lock);
+       if (ring->xcp_id < xcp_mgr->num_xcps && 
xcp_mgr->xcp[ring->xcp_id].valid)
+               atomic_dec(&xcp_mgr->xcp[ring->xcp_id].ref_cnt);
+       mutex_unlock(&xcp_mgr->xcp_lock);
 }
 
 int amdgpu_xcp_select_scheds(struct amdgpu_device *adev,
@@ -490,7 +495,9 @@ int amdgpu_xcp_select_scheds(struct amdgpu_device *adev,
        u32 sel_xcp_id;
        int i;
        struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr;
+       int r = 0;
 
+       mutex_lock(&xcp_mgr->xcp_lock);
        if (fpriv->xcp_id == AMDGPU_XCP_NO_PARTITION) {
                u32 least_ref_cnt = ~0;
 
@@ -507,19 +514,27 @@ int amdgpu_xcp_select_scheds(struct amdgpu_device *adev,
        }
        sel_xcp_id = fpriv->xcp_id;
 
+       if (sel_xcp_id >= xcp_mgr->num_xcps || !xcp_mgr->xcp[sel_xcp_id].valid) 
{
+               dev_err(adev->dev, "Selected partition #%d is not valid.", 
sel_xcp_id);
+               r = -ENODEV;
+               goto out;
+       }
+
        if (xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds) {
                *num_scheds =
-                       
xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds;
+                       
xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds;
                *scheds =
-                       
xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].sched;
-               atomic_inc(&adev->xcp_mgr->xcp[sel_xcp_id].ref_cnt);
+                       
xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].sched;
+               atomic_inc(&xcp_mgr->xcp[sel_xcp_id].ref_cnt);
                dev_dbg(adev->dev, "Selected partition #%d", sel_xcp_id);
        } else {
                dev_err(adev->dev, "Failed to schedule partition #%d.", 
sel_xcp_id);
-               return -ENOENT;
+               r = -ENOENT;
        }
 
-       return 0;
+out:
+       mutex_unlock(&xcp_mgr->xcp_lock);
+       return r;
 }
 
 static void amdgpu_set_xcp_id(struct amdgpu_device *adev,
-- 
2.34.1

Reply via email to