drivers/nvdimm/region_devs.c

Source file repositories/reference/linux-study-clean/drivers/nvdimm/region_devs.c

File Facts

System
Linux kernel
Corpus path
drivers/nvdimm/region_devs.c
Extension
.c
Size
30712 bytes
Lines
1192
Domain
Driver Families
Bucket
drivers/nvdimm
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (test_bit(NDD_INCOHERENT, &nvdimm->flags)) {
			incoherent++;
			break;
		}
	}

	if (!incoherent)
		return 0;

	if (!cpu_cache_has_invalidate_memregion()) {
		if (IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST)) {
			dev_warn(
				&nd_region->dev,
				"Bypassing cpu_cache_invalidate_memergion() for testing!\n");
			goto out;
		} else {
			dev_err(&nd_region->dev,
				"Failed to synchronize CPU cache state\n");
			return -ENXIO;
		}
	}

	cpu_cache_invalidate_all();
out:
	for (i = 0; i < nd_region->ndr_mappings; i++) {
		struct nd_mapping *nd_mapping = &nd_region->mapping[i];
		struct nvdimm *nvdimm = nd_mapping->nvdimm;

		clear_bit(NDD_INCOHERENT, &nvdimm->flags);
	}

	return 0;
}

static int get_flush_data(struct nd_region *nd_region, size_t *size, int *num_flush)
{
	size_t flush_data_size = sizeof(void *);
	int _num_flush = 0;
	int i;

	guard(nvdimm_bus)(&nd_region->dev);
	for (i = 0; i < nd_region->ndr_mappings; i++) {
		struct nd_mapping *nd_mapping = &nd_region->mapping[i];
		struct nvdimm *nvdimm = nd_mapping->nvdimm;

		if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags))
			return -EBUSY;

		/* at least one null hint slot per-dimm for the "no-hint" case */
		flush_data_size += sizeof(void *);
		_num_flush = min_not_zero(_num_flush, nvdimm->num_flush);
		if (!nvdimm->num_flush)
			continue;
		flush_data_size += nvdimm->num_flush * sizeof(void *);
	}

	*size = flush_data_size;
	*num_flush = _num_flush;

	return 0;
}

int nd_region_activate(struct nd_region *nd_region)
{
	int i, j, rc, num_flush;
	struct nd_region_data *ndrd;
	struct device *dev = &nd_region->dev;
	size_t flush_data_size;

	rc = get_flush_data(nd_region, &flush_data_size, &num_flush);
	if (rc)
		return rc;

	rc = nd_region_invalidate_memregion(nd_region);
	if (rc)
		return rc;

	ndrd = devm_kzalloc(dev, sizeof(*ndrd) + flush_data_size, GFP_KERNEL);
	if (!ndrd)
		return -ENOMEM;
	dev_set_drvdata(dev, ndrd);

	if (!num_flush)
		return 0;

	ndrd->hints_shift = ilog2(num_flush);
	for (i = 0; i < nd_region->ndr_mappings; i++) {
		struct nd_mapping *nd_mapping = &nd_region->mapping[i];
		struct nvdimm *nvdimm = nd_mapping->nvdimm;
		int rc = nvdimm_map_flush(&nd_region->dev, nvdimm, i, ndrd);

Annotation

Implementation Notes