[PATCH v2] drm/amdgpu: add more inject control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



TA accept some options like address is in sram or vram. Most default
options are enough to use. But allow user to setup them.

reuse inject.value to place these options.

At the same time, we need translate the address to a physical/gpu
address which the pages are mapped at.

V2: add a helper to makeup TA data

Signed-off-by: xinhui pan <xinhui.pan@xxxxxxx>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 108 +++++++++++++++++++++++-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h |  20 ++++-
 2 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index 469cb6477b8e..2b7a420d5a1f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -121,6 +121,21 @@ const char *ras_block_string[] = {
 #define AMDGPU_RAS_FLAG_INIT_BY_VBIOS 1
 #define RAS_DEFAULT_FLAGS (AMDGPU_RAS_FLAG_INIT_BY_VBIOS)
 
+static int amdgpu_ras_reserve_vram(struct amdgpu_device *adev,
+		uint64_t offset, uint64_t size,
+		struct amdgpu_bo **bo_ptr);
+
+static int amdgpu_ras_release_vram(struct amdgpu_device *adev,
+		struct amdgpu_bo **bo_ptr);
+
+static int amdgpu_ras_translate_addr(struct amdgpu_device *adev,
+		u64 *gpu_addr, int addr_type)
+{
+	/* TODO */
+
+	return -EINVAL;
+}
+
 static void amdgpu_ras_self_test(struct amdgpu_device *adev)
 {
 	/* TODO */
@@ -176,6 +191,53 @@ static int amdgpu_ras_find_block_id_by_name(const char *name, int *block_id)
 	return -EINVAL;
 }
 
+static bool amdgpu_ras_extract_inject_data(const struct ras_inject_if *inject,
+		u64 *address, u64 *value, int *addr_type, int *inject_type)
+{
+	const struct inject_data *data = &inject->data;
+
+	if (data->magic != AMDGPU_RAS_INJECT_MAGIC ||
+			data->u8_reserved ||
+			data->u32_reserved) {
+		*address = inject->address;
+		*value = inject->value;
+
+		return false;
+	}
+
+	*address = inject->address;
+	*value = data->value;
+	*addr_type = data->addr_type;
+	*inject_type = data->inject_type;
+
+	return true;
+}
+
+/* The definiton of ras_inject_if's member is different in different blocks. */
+static void amdgpu_ras_makeup_ta_inject_data(struct ras_inject_if *inject,
+		u64 address, u64 value, int addr_type, int inject_type)
+{
+	switch (inject->head.block) {
+	case AMDGPU_RAS_BLOCK__UMC:
+		/* 0 is vram, 1 is sram. */
+		inject->head.sub_block_index = addr_type;
+		/* not documented yet. */
+		inject->value = inject_type;
+		inject->address = address;
+		break;
+	case AMDGPU_RAS_BLOCK__SDMA ... AMDGPU_RAS_BLOCK__FUSE:
+		inject->address = address;
+		inject->value = value;
+		break;
+	default:
+		WARN_ONCE(1, "RAS ERROR: unexpected block id %d\n",
+				inject->head.block);
+		inject->address = address;
+		inject->value = value;
+		break;
+	};
+}
+
 static int amdgpu_ras_debugfs_ctrl_parse_data(struct file *f,
 		const char __user *buf, size_t size,
 		loff_t *pos, struct ras_debug_if *data)
@@ -300,7 +362,14 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user *
 {
 	struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private;
 	struct ras_debug_if data;
+	struct amdgpu_bo *bo = NULL;
 	int ret = 0;
+	u64 address;
+	u64 value;
+	int addr_type = 0;
+	int inject_type;
+
+	BUILD_BUG_ON(sizeof(struct inject_data) > sizeof(uint64_t));
 
 	ret = amdgpu_ras_debugfs_ctrl_parse_data(f, buf, size, pos, &data);
 	if (ret)
@@ -317,7 +386,44 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user *
 		ret = amdgpu_ras_feature_enable(adev, &data.head, 1);
 		break;
 	case 2:
-		ret = amdgpu_ras_error_inject(adev, &data.inject);
+		do {
+			/* In general, user can make up this inject data
+			 * by themself. But each IP might have their own
+			 * definitions, so handle such trivial but
+			 * important things in driver. We reuse inject.value
+			 * to place these control fields. To not break old
+			 * user applications, keep its size unchanged.
+			 */
+			if (amdgpu_ras_extract_inject_data(&data.inject,
+						&address, &value,
+						&addr_type, &inject_type))
+				amdgpu_ras_makeup_ta_inject_data(&data.inject,
+						address, value,
+						addr_type, inject_type);
+			/*
+			 * Need translate address to phy address accodring to
+			 * addr_type.
+			 */
+			ret = amdgpu_ras_translate_addr(adev,
+					&address, addr_type);
+			/* address is not mapped with physical pages */
+			if (ret) {
+				if (addr_type)
+					break;
+
+				/* try to reserve vram at address for inject.*/
+				if (amdgpu_ras_reserve_vram(adev,
+							address,
+							PAGE_SIZE, &bo))
+					break;
+			}
+
+			data.inject.address = address;
+
+			ret = amdgpu_ras_error_inject(adev, &data.inject);
+			if (bo)
+				amdgpu_ras_release_vram(adev, &bo);
+		} while (0);
 		break;
 	default:
 		ret = -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
index 682f2be0d68c..adcf7d88d59d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
@@ -121,10 +121,28 @@ struct ras_query_if {
 	unsigned long ce_count;
 };
 
+#define AMDGPU_RAS_INJECT_MAGIC 0xaa55
 struct ras_inject_if {
 	struct ras_common_if head;
 	uint64_t address;
-	uint64_t value;
+	union {
+		uint64_t value;
+		struct inject_data {
+			u8 value;
+			/* 0 is vram, 1 is sram */
+			u8 addr_type:1;
+			/* TA has several inject types,
+			 * but looks like 0 is the most case.
+			 */
+			u8 inject_type:3;
+			/* must be 0 */
+			u8 u8_reserved;
+			/* identify value or inject_data. */
+			u8 magic;
+			/* must be 0 */
+			u32 u32_reserved;
+		} data;
+	};
 };
 
 struct ras_cure_if {
-- 
2.17.1

_______________________________________________
amd-gfx mailing list
amd-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/amd-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux