⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 discontig.c

📁 linux-2.4.29操作系统的源码
💻 C
字号:
/* * Copyright (c) 2000, 2003 Silicon Graphics, Inc.  All rights reserved. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Tony Luck <tony.luck@intel.com> * Copyright (c) 2002 NEC Corp. * Copyright (c) 2002 Kimio Suganuma <k-suganuma@da.jp.nec.com> *//* * Platform initialization for Discontig Memory */#include <linux/kernel.h>#include <linux/mm.h>#include <linux/bootmem.h>#include <linux/mmzone.h>#include <linux/acpi.h>#include <linux/efi.h>#include <asm/pgalloc.h>#include <asm/tlb.h>/* * Round an address upward to the next multiple of GRANULE size. */#define GRANULEROUNDDOWN(n) ((n) & ~(IA64_GRANULE_SIZE-1))#define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))/* * Used to locate BOOT_DATA prior to initializing the node data area. */#define BOOT_NODE_DATA(node)	pg_data_ptr[node]/* * To prevent cache aliasing effects, align per-node structures so that they  * start at addresses that are strided by node number. */#define NODEDATA_ALIGN(addr, node)	((((addr) + 1024*1024-1) & ~(1024*1024-1)) + (node)*PAGE_SIZE)static struct ia64_node_data	*boot_node_data[NR_NODES] __initdata;static pg_data_t		*pg_data_ptr[NR_NODES] __initdata;static bootmem_data_t		bdata[NR_NODES] __initdata;static unsigned long		boot_pernode[NR_NODES] __initdata;static unsigned long		boot_pernodesize[NR_NODES] __initdata;extern int  filter_rsvd_memory (unsigned long start, unsigned long end, void *arg);extern struct cpuinfo_ia64 *_cpu_data[NR_CPUS];/* * We allocate one of the bootmem_data_t structs for each piece of memory * that we wish to treat as a contiguous block.  Each such block must start * on a GRANULE boundary.  Multiple banks per node is not supported. *   (Note: on SN2, all memory on a node is trated as a single bank. *   Holes within the bank are supported. This works because memory *   from different banks is not interleaved. The bootmap bitmap *   for the node is somewhat large but not too large). */static int __initbuild_maps(unsigned long start, unsigned long end, int node){	bootmem_data_t	*bdp;	unsigned long cstart, epfn;	bdp = &bdata[node];	epfn = GRANULEROUNDUP(__pa(end)) >> PAGE_SHIFT;	cstart = GRANULEROUNDDOWN(__pa(start));	if (!bdp->node_low_pfn) {		bdp->node_boot_start = cstart;		bdp->node_low_pfn = epfn;	} else {		bdp->node_boot_start = min(cstart, bdp->node_boot_start);		bdp->node_low_pfn = max(epfn, bdp->node_low_pfn);	}	min_low_pfn = min(min_low_pfn, bdp->node_boot_start>>PAGE_SHIFT);	max_low_pfn = max(max_low_pfn, bdp->node_low_pfn);	return 0;}/* * Count the number of cpus on the node */static __inline__ intcount_cpus(int node){	int cpu, n=0;	for (cpu=0; cpu < NR_CPUS; cpu++)		if (node == node_cpuid[cpu].nid)			n++;	return n;}/* * Find space on each node for the bootmem map & other per-node data structures. * * Called by efi_memmap_walk to find boot memory on each node. Note that * only blocks that are free are passed to this routine (currently filtered by * free_available_memory). */static int __initfind_pernode_space(unsigned long start, unsigned long end, int node){	unsigned long	mapsize, pages, epfn, map=0, cpu, cpus;	unsigned long	pernodesize=0, pernode;	unsigned long	cpu_data, mmu_gathers;	unsigned long	pstart, length;	bootmem_data_t	*bdp;	pstart = __pa(start);	length = end - start;	epfn = (pstart + length) >> PAGE_SHIFT;	bdp = &bdata[node];	if (pstart < bdp->node_boot_start || epfn > bdp->node_low_pfn)		return 0;	if (!boot_pernode[node]) {		cpus = count_cpus(node);		pernodesize += PAGE_ALIGN(sizeof(struct cpuinfo_ia64)) * cpus;		pernodesize += L1_CACHE_ALIGN(sizeof(mmu_gather_t)) * cpus;		pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));		pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));		pernodesize = PAGE_ALIGN(pernodesize);		pernode = NODEDATA_ALIGN(pstart, node);			if (pstart + length > (pernode + pernodesize)) {			boot_pernode[node] = pernode;			boot_pernodesize[node] = pernodesize;			memset(__va(pernode), 0, pernodesize);			cpu_data = pernode;			pernode += PAGE_ALIGN(sizeof(struct cpuinfo_ia64)) * cpus;			mmu_gathers = pernode;			pernode += L1_CACHE_ALIGN(sizeof(mmu_gather_t)) * cpus;			pg_data_ptr[node] = __va(pernode);			pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));			boot_node_data[node] = __va(pernode);			pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));			pg_data_ptr[node]->bdata = &bdata[node];			pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));			for (cpu=0; cpu < NR_CPUS; cpu++) {				if (node == node_cpuid[cpu].nid) {					_cpu_data[cpu] = __va(cpu_data);					_cpu_data[cpu]->node_data = boot_node_data[node];					_cpu_data[cpu]->nodeid = node;					_cpu_data[cpu]->mmu_gathers = __va(mmu_gathers);					cpu_data +=  PAGE_ALIGN(sizeof(struct cpuinfo_ia64));					mmu_gathers += L1_CACHE_ALIGN(sizeof(mmu_gather_t));				}			}		}	}	pernode = boot_pernode[node];	pernodesize = boot_pernodesize[node];	if (pernode && !bdp->node_bootmem_map) {		pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);		mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;		if (pernode - pstart > mapsize)			map = pstart;		else if (pstart + length - pernode - pernodesize > mapsize)			map = pernode + pernodesize;		if (map) {			init_bootmem_node(				BOOT_NODE_DATA(node),				map>>PAGE_SHIFT, 				bdp->node_boot_start>>PAGE_SHIFT,				bdp->node_low_pfn);		}	}	return 0;}/* * Free available memory to the bootmem allocator. * * Note that only blocks that are free are passed to this routine (currently  * filtered by free_available_memory). * */static int __initdiscontig_free_bootmem_node(unsigned long start, unsigned long end, int node){	free_bootmem_node(BOOT_NODE_DATA(node), __pa(start), end - start);	return 0;}/* * Reserve the space used by the bootmem maps. */static void __initdiscontig_reserve_bootmem(void){	int		node;	unsigned long	base, size, pages;	bootmem_data_t	*bdp;	for (node = 0; node < numnodes; node++) {		bdp = BOOT_NODE_DATA(node)->bdata;		pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);		size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;		base = __pa(bdp->node_bootmem_map);		reserve_bootmem_node(BOOT_NODE_DATA(node), base, size);		size = boot_pernodesize[node];		base = __pa(boot_pernode[node]);		reserve_bootmem_node(BOOT_NODE_DATA(node), base, size);	}}/* * Initialize per-node data * * Finish setting up the node data for this node, then copy it to the other nodes. * */static void __initinitialize_pernode_data(void){	int	cpu, node;	memcpy(boot_node_data[0]->pg_data_ptrs, pg_data_ptr, sizeof(pg_data_ptr));	memcpy(boot_node_data[0]->node_data_ptrs, boot_node_data, sizeof(boot_node_data));	for (node=1; node < numnodes; node++) {		memcpy(boot_node_data[node], boot_node_data[0], sizeof(struct ia64_node_data));		boot_node_data[node]->node = node;	}	for (cpu=0; cpu < NR_CPUS; cpu++) {		node = node_cpuid[cpu].nid;		_cpu_data[cpu]->node_data = boot_node_data[node];		_cpu_data[cpu]->nodeid = node;	}}/* * Called early in boot to setup the boot memory allocator, and to * allocate the node-local pg_data & node-directory data structures.. */void __initdiscontig_mem_init(void){	if (numnodes == 0) {		printk("node info missing!\n");		numnodes = 1;	}	min_low_pfn = -1;	max_low_pfn = 0;        efi_memmap_walk(filter_rsvd_memory, build_maps);        efi_memmap_walk(filter_rsvd_memory, find_pernode_space);        efi_memmap_walk(filter_rsvd_memory, discontig_free_bootmem_node);	discontig_reserve_bootmem();	initialize_pernode_data();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -