Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8faf0e08 authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/amdgpu: clean up init sequence for failures



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: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0a90a0cf
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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);

+22 −16
Original line number Diff line number Diff line
@@ -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) {
@@ -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;
			}
		}
	}
@@ -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);
@@ -1243,11 +1245,12 @@ 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)
@@ -1255,6 +1258,7 @@ static int amdgpu_init(struct amdgpu_device *adev)
		r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
		if (r)
			return r;
		adev->ip_block_status[i].hw = true;
	}

	return 0;
@@ -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,
@@ -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);
@@ -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;
@@ -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,
@@ -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)
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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++;