arch/powerpc/platforms/powernv/memtrace.c

Source file repositories/reference/linux-study-clean/arch/powerpc/platforms/powernv/memtrace.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/powernv/memtrace.c
Extension
.c
Size
7819 bytes
Lines
324
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations memtrace_fops = {
	.llseek = default_llseek,
	.read	= memtrace_read,
	.open	= simple_open,
	.mmap   = memtrace_mmap,
};

#define FLUSH_CHUNK_SIZE SZ_1G
/**
 * flush_dcache_range_chunked(): Write any modified data cache blocks out to
 * memory and invalidate them, in chunks of up to FLUSH_CHUNK_SIZE
 * Does not invalidate the corresponding instruction cache blocks.
 *
 * @start: the start address
 * @stop: the stop address (exclusive)
 * @chunk: the max size of the chunks
 */
static void flush_dcache_range_chunked(unsigned long start, unsigned long stop,
				       unsigned long chunk)
{
	unsigned long i;

	for (i = start; i < stop; i += chunk) {
		flush_dcache_range(i, min(stop, i + chunk));
		cond_resched();
	}
}

static u64 memtrace_alloc_node(u32 nid, u64 size)
{
	const unsigned long nr_pages = PHYS_PFN(size);
	unsigned long pfn, start_pfn;
	struct page *page;

	/*
	 * Trace memory needs to be aligned to the size, which is guaranteed
	 * by alloc_contig_pages().
	 */
	page = alloc_contig_pages(nr_pages, GFP_KERNEL | __GFP_THISNODE |
				  __GFP_NOWARN | __GFP_ZERO, nid, NULL);
	if (!page)
		return 0;
	start_pfn = page_to_pfn(page);

	/*
	 * Before we go ahead and use this range as cache inhibited range
	 * flush the cache.
	 */
	flush_dcache_range_chunked((unsigned long)pfn_to_kaddr(start_pfn),
				   (unsigned long)pfn_to_kaddr(start_pfn + nr_pages),
				   FLUSH_CHUNK_SIZE);

	/*
	 * Set pages PageOffline(), to indicate that nobody (e.g., hibernation,
	 * dumping, ...) should be touching these pages.
	 */
	for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++)
		__SetPageOffline(pfn_to_page(pfn));

	arch_remove_linear_mapping(PFN_PHYS(start_pfn), size);

	return PFN_PHYS(start_pfn);
}

static int memtrace_init_regions_runtime(u64 size)
{
	u32 nid;
	u64 m;

	memtrace_array = kzalloc_objs(struct memtrace_entry, num_online_nodes());
	if (!memtrace_array) {
		pr_err("Failed to allocate memtrace_array\n");
		return -EINVAL;
	}

	for_each_online_node(nid) {
		m = memtrace_alloc_node(nid, size);

		/*
		 * A node might not have any local memory, so warn but
		 * continue on.
		 */
		if (!m) {
			pr_err("Failed to allocate trace memory on node %d\n", nid);
			continue;
		}

		pr_info("Allocated trace memory on node %d at 0x%016llx\n", nid, m);

		memtrace_array[memtrace_array_nr].start = m;

Annotation

Implementation Notes