drivers/nvdimm/dimm_devs.c

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

File Facts

System
Linux kernel
Corpus path
drivers/nvdimm/dimm_devs.c
Extension
.c
Size
21686 bytes
Lines
877
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

* Security state must be initialized before device_add() for
	 * attribute visibility.
	 */
	/* get security state and extended (master) state */
	nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);
	nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
	device_initialize(dev);
	lockdep_set_class(&dev->mutex, &nvdimm_key);
	if (test_bit(NDD_REGISTER_SYNC, &flags))
		nd_device_register_sync(dev);
	else
		nd_device_register(dev);

	return nvdimm;
}
EXPORT_SYMBOL_GPL(__nvdimm_create);

void nvdimm_delete(struct nvdimm *nvdimm)
{
	struct device *dev = &nvdimm->dev;
	bool dev_put = false;

	/* We are shutting down. Make state frozen artificially. */
	scoped_guard(nvdimm_bus, dev) {
		set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags);
		dev_put = test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags);
	}
	cancel_delayed_work_sync(&nvdimm->dwork);
	if (dev_put)
		put_device(dev);
	nd_device_unregister(dev, ND_SYNC);
}
EXPORT_SYMBOL_GPL(nvdimm_delete);

static void shutdown_security_notify(void *data)
{
	struct nvdimm *nvdimm = data;

	sysfs_put(nvdimm->sec.overwrite_state);
}

int nvdimm_security_setup_events(struct device *dev)
{
	struct nvdimm *nvdimm = to_nvdimm(dev);

	if (!nvdimm->sec.flags || !nvdimm->sec.ops
			|| !nvdimm->sec.ops->overwrite)
		return 0;
	nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security");
	if (!nvdimm->sec.overwrite_state)
		return -ENOMEM;

	return devm_add_action_or_reset(dev, shutdown_security_notify, nvdimm);
}
EXPORT_SYMBOL_GPL(nvdimm_security_setup_events);

int nvdimm_in_overwrite(struct nvdimm *nvdimm)
{
	return test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
}
EXPORT_SYMBOL_GPL(nvdimm_in_overwrite);

int nvdimm_security_freeze(struct nvdimm *nvdimm)
{
	int rc;

	WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm->dev));

	if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze)
		return -EOPNOTSUPP;

	if (!nvdimm->sec.flags)
		return -EIO;

	if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
		dev_warn(&nvdimm->dev, "Overwrite operation in progress.\n");
		return -EBUSY;
	}

	rc = nvdimm->sec.ops->freeze(nvdimm);
	nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER);

	return rc;
}

static unsigned long dpa_align(struct nd_region *nd_region)
{
	struct device *dev = &nd_region->dev;

	if (dev_WARN_ONCE(dev, !is_nvdimm_bus_locked(dev),

Annotation

Implementation Notes