drivers/nvdimm/pmem.c

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

File Facts

System
Linux kernel
Corpus path
drivers/nvdimm/pmem.c
Extension
.c
Size
19857 bytes
Lines
767
Domain
Driver Families
Bucket
drivers/nvdimm
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 (rc) {
			bio->bi_status = rc;
			break;
		}
	}
	if (do_acct)
		bio_end_io_acct(bio, start);

	if (bio->bi_opf & REQ_FUA)
		ret = nvdimm_flush(nd_region, bio);

	if (ret)
		bio->bi_status = errno_to_blk_status(ret);

	bio_endio(bio);
}

/* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */
__weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
		long nr_pages, enum dax_access_mode mode, void **kaddr,
		unsigned long *pfn)
{
	resource_size_t offset = PFN_PHYS(pgoff) + pmem->data_offset;
	sector_t sector = PFN_PHYS(pgoff) >> SECTOR_SHIFT;
	unsigned int num = PFN_PHYS(nr_pages) >> SECTOR_SHIFT;
	struct badblocks *bb = &pmem->bb;
	sector_t first_bad;
	sector_t num_bad;

	if (kaddr)
		*kaddr = pmem->virt_addr + offset;
	if (pfn)
		*pfn = PHYS_PFN(pmem->phys_addr + offset);

	if (bb->count &&
	    badblocks_check(bb, sector, num, &first_bad, &num_bad)) {
		long actual_nr;

		if (mode != DAX_RECOVERY_WRITE)
			return -EHWPOISON;

		/*
		 * Set the recovery stride is set to kernel page size because
		 * the underlying driver and firmware clear poison functions
		 * don't appear to handle large chunk(such as 2MiB) reliably.
		 */
		actual_nr = PHYS_PFN(
			PAGE_ALIGN((first_bad - sector) << SECTOR_SHIFT));
		dev_dbg(pmem->bb.dev, "start sector(%llu), nr_pages(%ld), first_bad(%llu), actual_nr(%ld)\n",
				sector, nr_pages, first_bad, actual_nr);
		if (actual_nr)
			return actual_nr;
		return 1;
	}

	/*
	 * If badblocks are present but not in the range, limit known good range
	 * to the requested range.
	 */
	if (bb->count)
		return nr_pages;
	return PHYS_PFN(pmem->size - pmem->pfn_pad - offset);
}

static const struct block_device_operations pmem_fops = {
	.owner =		THIS_MODULE,
	.submit_bio =		pmem_submit_bio,
};

static int pmem_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
				    size_t nr_pages)
{
	struct pmem_device *pmem = dax_get_private(dax_dev);

	return blk_status_to_errno(pmem_do_write(pmem, ZERO_PAGE(0), 0,
				   PFN_PHYS(pgoff) >> SECTOR_SHIFT,
				   PAGE_SIZE));
}

static long pmem_dax_direct_access(struct dax_device *dax_dev,
		pgoff_t pgoff, long nr_pages, enum dax_access_mode mode,
		void **kaddr, unsigned long *pfn)
{
	struct pmem_device *pmem = dax_get_private(dax_dev);

	return __pmem_direct_access(pmem, pgoff, nr_pages, mode, kaddr, pfn);
}

/*
 * The recovery write thread started out as a normal pwrite thread and

Annotation

Implementation Notes