drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c
Extension
.c
Size
18773 bytes
Lines
626
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (bank->aca_err_type == ACA_ERROR_TYPE_DEFERRED) {
			sev = CPER_SEV_NON_FATAL_UNCORRECTED;
			break;
		}
	}

	amdgpu_cper_entry_fill_hdr(adev, corrected, AMDGPU_CPER_TYPE_RUNTIME, sev);

	/* Combine CE and DE in cper record */
	list_for_each_entry(node, &banks->list, node) {
		bank = &node->bank;
		reg_data[CPER_ACA_REG_CTL_LO]    = lower_32_bits(bank->regs[ACA_REG_IDX_CTL]);
		reg_data[CPER_ACA_REG_CTL_HI]    = upper_32_bits(bank->regs[ACA_REG_IDX_CTL]);
		reg_data[CPER_ACA_REG_STATUS_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_STATUS]);
		reg_data[CPER_ACA_REG_STATUS_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_STATUS]);
		reg_data[CPER_ACA_REG_ADDR_LO]   = lower_32_bits(bank->regs[ACA_REG_IDX_ADDR]);
		reg_data[CPER_ACA_REG_ADDR_HI]   = upper_32_bits(bank->regs[ACA_REG_IDX_ADDR]);
		reg_data[CPER_ACA_REG_MISC0_LO]  = lower_32_bits(bank->regs[ACA_REG_IDX_MISC0]);
		reg_data[CPER_ACA_REG_MISC0_HI]  = upper_32_bits(bank->regs[ACA_REG_IDX_MISC0]);
		reg_data[CPER_ACA_REG_CONFIG_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_CONFIG]);
		reg_data[CPER_ACA_REG_CONFIG_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_CONFIG]);
		reg_data[CPER_ACA_REG_IPID_LO]   = lower_32_bits(bank->regs[ACA_REG_IDX_IPID]);
		reg_data[CPER_ACA_REG_IPID_HI]   = upper_32_bits(bank->regs[ACA_REG_IDX_IPID]);
		reg_data[CPER_ACA_REG_SYND_LO]   = lower_32_bits(bank->regs[ACA_REG_IDX_SYND]);
		reg_data[CPER_ACA_REG_SYND_HI]   = upper_32_bits(bank->regs[ACA_REG_IDX_SYND]);

		ret = amdgpu_cper_entry_fill_runtime_section(adev, corrected, i++,
				amdgpu_aca_err_type_to_cper_sev(adev, bank->aca_err_type),
				reg_data, CPER_ACA_REG_COUNT);
		if (ret)
			return ret;
	}

	amdgpu_cper_ring_write(ring, corrected, corrected->record_length);
	kfree(corrected);

	return 0;
}

static bool amdgpu_cper_is_hdr(struct amdgpu_ring *ring, u64 pos)
{
	char signature[CPER_SIGNATURE_SZ];

	if ((pos << 2) >= ring->ring_size)
		return false;

	if ((pos << 2) + CPER_SIGNATURE_SZ <= ring->ring_size) {
		memcpy(signature, &ring->ring[pos], CPER_SIGNATURE_SZ);
	} else {
		u32 chunk = ring->ring_size - (pos << 2);

		memcpy(signature, &ring->ring[pos], chunk);
		memcpy(signature + chunk, ring->ring, CPER_SIGNATURE_SZ - chunk);
	}

	return !memcmp(signature, "CPER", CPER_SIGNATURE_SZ);
}

static u32 amdgpu_cper_ring_get_ent_sz(struct amdgpu_ring *ring, u64 pos)
{
	struct cper_hdr chdr;
	u64 p;
	u32 chunk, rec_len = 0;

	chunk = ring->ring_size - (pos << 2);

	if (amdgpu_cper_is_hdr(ring, pos)) {
		if (chunk >= sizeof(chdr)) {
			memcpy(&chdr, &ring->ring[pos], sizeof(chdr));
		} else {
			memcpy(&chdr, &ring->ring[pos], chunk);
			memcpy((u8 *)&chdr + chunk, ring->ring, sizeof(chdr) - chunk);
		}

		rec_len = chdr.record_length;
		goto calc;
	}

	/* ring buffer is not full, no cper data after ring->wptr */
	if (ring->count_dw)
		goto calc;

	for (p = pos + 1; p <= ring->buf_mask; p++) {
		if (amdgpu_cper_is_hdr(ring, p)) {
			rec_len = (p - pos) << 2;
			goto calc;
		}
	}

calc:

Annotation

Implementation Notes