Skip to content

Commit

Permalink
drm/amdgpu: clean up init sequence for failures
Browse files Browse the repository at this point in the history
If we fail during device init, record what state each
block is in so that we can tear down clearly.

Fixes various problems on device init failure.

Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Alex Deucher committed Jul 29, 2015
1 parent 0a90a0c commit 8faf0e0
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 19 deletions.
8 changes: 7 additions & 1 deletion drivers/gpu/drm/amd/amdgpu/amdgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,12 @@ typedef void (*amdgpu_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
typedef uint32_t (*amdgpu_block_rreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
typedef void (*amdgpu_block_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t, uint32_t);

struct amdgpu_ip_block_status {
bool valid;
bool sw;
bool hw;
};

struct amdgpu_device {
struct device *dev;
struct drm_device *ddev;
Expand Down Expand Up @@ -2008,7 +2014,7 @@ struct amdgpu_device {

const struct amdgpu_ip_block_version *ip_blocks;
int num_ip_blocks;
bool *ip_block_enabled;
struct amdgpu_ip_block_status *ip_block_status;
struct mutex mn_lock;
DECLARE_HASHTABLE(mn_hash, 7);

Expand Down
38 changes: 22 additions & 16 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -1191,8 +1191,9 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
return -EINVAL;
}

adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL);
if (adev->ip_block_enabled == NULL)
adev->ip_block_status = kcalloc(adev->num_ip_blocks,
sizeof(struct amdgpu_ip_block_status), GFP_KERNEL);
if (adev->ip_block_status == NULL)
return -ENOMEM;

if (adev->ip_blocks == NULL) {
Expand All @@ -1203,18 +1204,18 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
for (i = 0; i < adev->num_ip_blocks; i++) {
if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
DRM_ERROR("disabled ip block: %d\n", i);
adev->ip_block_enabled[i] = false;
adev->ip_block_status[i].valid = false;
} else {
if (adev->ip_blocks[i].funcs->early_init) {
r = adev->ip_blocks[i].funcs->early_init((void *)adev);
if (r == -ENOENT)
adev->ip_block_enabled[i] = false;
adev->ip_block_status[i].valid = false;
else if (r)
return r;
else
adev->ip_block_enabled[i] = true;
adev->ip_block_status[i].valid = true;
} else {
adev->ip_block_enabled[i] = true;
adev->ip_block_status[i].valid = true;
}
}
}
Expand All @@ -1227,11 +1228,12 @@ static int amdgpu_init(struct amdgpu_device *adev)
int i, r;

for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_block_enabled[i])
if (!adev->ip_block_status[i].valid)
continue;
r = adev->ip_blocks[i].funcs->sw_init((void *)adev);
if (r)
return r;
adev->ip_block_status[i].sw = true;
/* need to do gmc hw init early so we can allocate gpu mem */
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
r = amdgpu_vram_scratch_init(adev);
Expand All @@ -1243,18 +1245,20 @@ static int amdgpu_init(struct amdgpu_device *adev)
r = amdgpu_wb_init(adev);
if (r)
return r;
adev->ip_block_status[i].hw = true;
}
}

for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_block_enabled[i])
if (!adev->ip_block_status[i].sw)
continue;
/* gmc hw init is done early */
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC)
continue;
r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
if (r)
return r;
adev->ip_block_status[i].hw = true;
}

return 0;
Expand All @@ -1265,7 +1269,7 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
int i = 0, r;

for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_block_enabled[i])
if (!adev->ip_block_status[i].valid)
continue;
/* enable clockgating to save power */
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
Expand All @@ -1287,7 +1291,7 @@ static int amdgpu_fini(struct amdgpu_device *adev)
int i, r;

for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
if (!adev->ip_block_enabled[i])
if (!adev->ip_block_status[i].hw)
continue;
if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
amdgpu_wb_fini(adev);
Expand All @@ -1300,14 +1304,16 @@ static int amdgpu_fini(struct amdgpu_device *adev)
return r;
r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
/* XXX handle errors */
adev->ip_block_status[i].hw = false;
}

for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
if (!adev->ip_block_enabled[i])
if (!adev->ip_block_status[i].sw)
continue;
r = adev->ip_blocks[i].funcs->sw_fini((void *)adev);
/* XXX handle errors */
adev->ip_block_enabled[i] = false;
adev->ip_block_status[i].sw = false;
adev->ip_block_status[i].valid = false;
}

return 0;
Expand All @@ -1318,7 +1324,7 @@ static int amdgpu_suspend(struct amdgpu_device *adev)
int i, r;

for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
if (!adev->ip_block_enabled[i])
if (!adev->ip_block_status[i].valid)
continue;
/* ungate blocks so that suspend can properly shut them down */
r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
Expand All @@ -1336,7 +1342,7 @@ static int amdgpu_resume(struct amdgpu_device *adev)
int i, r;

for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_block_enabled[i])
if (!adev->ip_block_status[i].valid)
continue;
r = adev->ip_blocks[i].funcs->resume(adev);
if (r)
Expand Down Expand Up @@ -1582,8 +1588,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
amdgpu_fence_driver_fini(adev);
amdgpu_fbdev_fini(adev);
r = amdgpu_fini(adev);
kfree(adev->ip_block_enabled);
adev->ip_block_enabled = NULL;
kfree(adev->ip_block_status);
adev->ip_block_status = NULL;
adev->accel_working = false;
/* free i2c buses */
amdgpu_i2c_fini(adev);
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file

for (i = 0; i < adev->num_ip_blocks; i++) {
if (adev->ip_blocks[i].type == type &&
adev->ip_block_enabled[i]) {
adev->ip_block_status[i].valid) {
ip.hw_ip_version_major = adev->ip_blocks[i].major;
ip.hw_ip_version_minor = adev->ip_blocks[i].minor;
ip.capabilities_flags = 0;
Expand Down Expand Up @@ -274,7 +274,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file

for (i = 0; i < adev->num_ip_blocks; i++)
if (adev->ip_blocks[i].type == type &&
adev->ip_block_enabled[i] &&
adev->ip_block_status[i].valid &&
count < AMDGPU_HW_IP_INSTANCE_MAX_COUNT)
count++;

Expand Down

0 comments on commit 8faf0e0

Please sign in to comment.