drivers/gpu/drm/amd/ras/rascore/ras_umc.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/ras/rascore/ras_umc.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/ras/rascore/ras_umc.c
Extension
.c
Size
21403 bytes
Lines
783
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 (!ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) {
			list_del(&ecc_node->node);
			kfree(ecc_node);
			if (ras_umc->pending_ecc_count)
				ras_umc->pending_ecc_count--;
		}
	}
	if (ras_umc->pending_ecc_dropped) {
		RAS_DEV_WARN(ras_core->dev,
			"%u pending ECC bad-bank events were dropped during GPU reset\n",
			ras_umc->pending_ecc_dropped);
		ras_umc->pending_ecc_dropped = 0;
	}
	mutex_unlock(&ras_umc->pending_ecc_lock);

	return 0;
}

int ras_umc_log_bad_bank(struct ras_core_context *ras_core, struct ras_bank_ecc *bank)
{
	struct ras_umc *ras_umc = &ras_core->ras_umc;
	struct eeprom_umc_record umc_rec;
	struct eeprom_umc_record *err_rec;
	int ret;

	memset(&umc_rec, 0, sizeof(umc_rec));

	mutex_lock(&ras_umc->bank_log_lock);
	ret = ras_umc->ip_func->bank_to_eeprom_record(ras_core, bank, &umc_rec);
	if (ret)
		goto out;

	err_rec = kzalloc_obj(*err_rec);
	if (!err_rec) {
		ret = -ENOMEM;
		goto out;
	}

	memcpy(err_rec, &umc_rec, sizeof(umc_rec));
	ret = ras_umc_log_ecc(ras_core, err_rec->cur_nps_retired_row_pfn, err_rec);
	if (ret) {
		if (ret == -EEXIST) {
			RAS_DEV_INFO(ras_core->dev, "The bad pages have been logged before.\n");
			ret = 0;
		}

		kfree(err_rec);
		goto out;
	}

	ras_umc_reserve_eeprom_record(ras_core, err_rec);

	ret = ras_core_event_notify(ras_core,
			RAS_EVENT_ID__BAD_PAGE_DETECTED, NULL);

out:
	mutex_unlock(&ras_umc->bank_log_lock);
	return ret;
}

static int ras_umc_get_new_records(struct ras_core_context *ras_core,
			struct eeprom_umc_record *records, u32 num)
{
	struct ras_umc *ras_umc = &ras_core->ras_umc;
	struct eeprom_umc_record *entries[MAX_ECC_NUM_PER_RETIREMENT];
	u32 entry_num = num < MAX_ECC_NUM_PER_RETIREMENT ? num : MAX_ECC_NUM_PER_RETIREMENT;
	int count = 0;
	int new_detected, i;

	mutex_lock(&ras_umc->tree_lock);
	new_detected = radix_tree_gang_lookup_tag(&ras_umc->root, (void **)entries,
			0, entry_num, UMC_ECC_NEW_DETECTED_TAG);
	for (i = 0; i < new_detected; i++) {
		if (!entries[i])
			continue;

		memcpy(&records[i], entries[i], sizeof(struct eeprom_umc_record));
		count++;
		radix_tree_tag_clear(&ras_umc->root,
				entries[i]->cur_nps_retired_row_pfn, UMC_ECC_NEW_DETECTED_TAG);
	}
	mutex_unlock(&ras_umc->tree_lock);

	return count;
}

static bool ras_umc_check_retired_record(struct ras_core_context *ras_core,
				struct eeprom_umc_record *record, bool from_eeprom)
{
	struct ras_umc *ras_umc = &ras_core->ras_umc;

Annotation

Implementation Notes