欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

prom.c

底层驱动开发
C
第 1 页 / 共 4 页
字号:
	DBG("Command line is: %s\n", cmd_line);	DBG(" <- unflatten_device_tree()\n");}static int __init early_init_dt_scan_cpus(unsigned long node,					  const char *uname, int depth, void *data){	char *type = get_flat_dt_prop(node, "device_type", NULL);	u32 *prop;	unsigned long size;	/* We are scanning "cpu" nodes only */	if (type == NULL || strcmp(type, "cpu") != 0)		return 0;	/* On LPAR, look for the first ibm,pft-size property for the  hash table size	 */	if (systemcfg->platform == PLATFORM_PSERIES_LPAR && ppc64_pft_size == 0) {		u32 *pft_size;		pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL);		if (pft_size != NULL) {			/* pft_size[0] is the NUMA CEC cookie */			ppc64_pft_size = pft_size[1];		}	}	if (initial_boot_params && initial_boot_params->version >= 2) {		/* version 2 of the kexec param format adds the phys cpuid		 * of booted proc.		 */		boot_cpuid_phys = initial_boot_params->boot_cpuid_phys;		boot_cpuid = 0;	} else {		/* Check if it's the boot-cpu, set it's hw index in paca now */		if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) {			u32 *prop = get_flat_dt_prop(node, "reg", NULL);			set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop);			boot_cpuid_phys = get_hard_smp_processor_id(0);		}	}#ifdef CONFIG_ALTIVEC	/* Check if we have a VMX and eventually update CPU features */	prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", NULL);	if (prop && (*prop) > 0) {		cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;		cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;	}	/* Same goes for Apple's "altivec" property */	prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL);	if (prop) {		cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;		cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;	}#endif /* CONFIG_ALTIVEC */	/*	 * Check for an SMT capable CPU and set the CPU feature. We do	 * this by looking at the size of the ibm,ppc-interrupt-server#s	 * property	 */	prop = (u32 *)get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s",				       &size);	cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;	if (prop && ((size / sizeof(u32)) > 1))		cur_cpu_spec->cpu_features |= CPU_FTR_SMT;	return 0;}static int __init early_init_dt_scan_chosen(unsigned long node,					    const char *uname, int depth, void *data){	u32 *prop;	u64 *prop64;	extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;	DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);	if (depth != 1 || strcmp(uname, "chosen") != 0)		return 0;	/* get platform type */	prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL);	if (prop == NULL)		return 0;	systemcfg->platform = *prop;	/* check if iommu is forced on or off */	if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)		iommu_is_off = 1;	if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL)		iommu_force_on = 1; 	prop64 = (u64*)get_flat_dt_prop(node, "linux,memory-limit", NULL); 	if (prop64) 		memory_limit = *prop64; 	prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-start", NULL); 	if (prop64) 		tce_alloc_start = *prop64; 	prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-end", NULL); 	if (prop64) 		tce_alloc_end = *prop64;#ifdef CONFIG_PPC_RTAS	/* To help early debugging via the front panel, we retreive a minimal	 * set of RTAS infos now if available	 */	{		u64 *basep, *entryp;		basep = (u64*)get_flat_dt_prop(node, "linux,rtas-base", NULL);		entryp = (u64*)get_flat_dt_prop(node, "linux,rtas-entry", NULL);		prop = (u32*)get_flat_dt_prop(node, "linux,rtas-size", NULL);		if (basep && entryp && prop) {			rtas.base = *basep;			rtas.entry = *entryp;			rtas.size = *prop;		}	}#endif /* CONFIG_PPC_RTAS */	/* break now */	return 1;}static int __init early_init_dt_scan_root(unsigned long node,					  const char *uname, int depth, void *data){	u32 *prop;	if (depth != 0)		return 0;	prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);	dt_root_size_cells = (prop == NULL) ? 1 : *prop;	DBG("dt_root_size_cells = %x\n", dt_root_size_cells);	prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);	dt_root_addr_cells = (prop == NULL) ? 2 : *prop;	DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);		/* break now */	return 1;}static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp){	cell_t *p = *cellp;	unsigned long r = 0;	/* Ignore more than 2 cells */	while (s > 2) {		p++;		s--;	}	while (s) {		r <<= 32;		r |= *(p++);		s--;	}	*cellp = p;	return r;}static int __init early_init_dt_scan_memory(unsigned long node,					    const char *uname, int depth, void *data){	char *type = get_flat_dt_prop(node, "device_type", NULL);	cell_t *reg, *endp;	unsigned long l;	/* We are scanning "memory" nodes only */	if (type == NULL || strcmp(type, "memory") != 0)		return 0;	reg = (cell_t *)get_flat_dt_prop(node, "reg", &l);	if (reg == NULL)		return 0;	endp = reg + (l / sizeof(cell_t));	DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",	    uname, l, reg[0], reg[1], reg[2], reg[3]);	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {		unsigned long base, size;		base = dt_mem_next_cell(dt_root_addr_cells, &reg);		size = dt_mem_next_cell(dt_root_size_cells, &reg);		if (size == 0)			continue;		DBG(" - %lx ,  %lx\n", base, size);		if (iommu_is_off) {			if (base >= 0x80000000ul)				continue;			if ((base + size) > 0x80000000ul)				size = 0x80000000ul - base;		}		lmb_add(base, size);	}	return 0;}static void __init early_reserve_mem(void){	u64 base, size;	u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) +				   initial_boot_params->off_mem_rsvmap);	while (1) {		base = *(reserve_map++);		size = *(reserve_map++);		if (size == 0)			break;		DBG("reserving: %lx -> %lx\n", base, size);		lmb_reserve(base, size);	}#if 0	DBG("memory reserved, lmbs :\n");      	lmb_dump_all();#endif}void __init early_init_devtree(void *params){	DBG(" -> early_init_devtree()\n");	/* Setup flat device-tree pointer */	initial_boot_params = params;	/* By default, hash size is not set */	ppc64_pft_size = 0;	/* Retreive various informations from the /chosen node of the	 * device-tree, including the platform type, initrd location and	 * size, TCE reserve, and more ...	 */	scan_flat_dt(early_init_dt_scan_chosen, NULL);	/* Scan memory nodes and rebuild LMBs */	lmb_init();	scan_flat_dt(early_init_dt_scan_root, NULL);	scan_flat_dt(early_init_dt_scan_memory, NULL);	lmb_enforce_memory_limit();	lmb_analyze();	systemcfg->physicalMemorySize = lmb_phys_mem_size();	lmb_reserve(0, __pa(klimit));	DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize);	/* Reserve LMB regions used by kernel, initrd, dt, etc... */	early_reserve_mem();	DBG("Scanning CPUs ...\n");	/* Retreive hash table size from flattened tree plus other	 * CPU related informations (altivec support, boot CPU ID, ...)	 */	scan_flat_dt(early_init_dt_scan_cpus, NULL);	/* If hash size wasn't obtained above, we calculate it now based on	 * the total RAM size	 */	if (ppc64_pft_size == 0) {		unsigned long rnd_mem_size, pteg_count;		/* round mem_size up to next power of 2 */		rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize);		if (rnd_mem_size < systemcfg->physicalMemorySize)			rnd_mem_size <<= 1;		/* # pages / 2 */		pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11);		ppc64_pft_size = __ilog2(pteg_count << 7);	}	DBG("Hash pftSize: %x\n", (int)ppc64_pft_size);	DBG(" <- early_init_devtree()\n");}#undef printkintprom_n_addr_cells(struct device_node* np){	int* ip;	do {		if (np->parent)			np = np->parent;		ip = (int *) get_property(np, "#address-cells", NULL);		if (ip != NULL)			return *ip;	} while (np->parent);	/* No #address-cells property for the root node, default to 1 */	return 1;}intprom_n_size_cells(struct device_node* np){	int* ip;	do {		if (np->parent)			np = np->parent;		ip = (int *) get_property(np, "#size-cells", NULL);		if (ip != NULL)			return *ip;	} while (np->parent);	/* No #size-cells property for the root node, default to 1 */	return 1;}/** * Work out the sense (active-low level / active-high edge) * of each interrupt from the device tree. */void __init prom_get_irq_senses(unsigned char *senses, int off, int max){	struct device_node *np;	int i, j;	/* default to level-triggered */	memset(senses, 1, max - off);	for (np = allnodes; np != 0; np = np->allnext) {		for (j = 0; j < np->n_intrs; j++) {			i = np->intrs[j].line;			if (i >= off && i < max)				senses[i-off] = np->intrs[j].sense ?					IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE :					IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE;		}	}}/** * Construct and return a list of the device_nodes with a given name. */struct device_node *find_devices(const char *name){	struct device_node *head, **prevp, *np;	prevp = &head;	for (np = allnodes; np != 0; np = np->allnext) {		if (np->name != 0 && strcasecmp(np->name, name) == 0) {			*prevp = np;			prevp = &np->next;		}	}	*prevp = NULL;	return head;}EXPORT_SYMBOL(find_devices);/** * Construct and return a list of the device_nodes with a given type. */struct device_node *find_type_devices(const char *type){	struct device_node *head, **prevp, *np;	prevp = &head;	for (np = allnodes; np != 0; np = np->allnext) {		if (np->type != 0 && strcasecmp(np->type, type) == 0) {			*prevp = np;			prevp = &np->next;		}	}	*prevp = NULL;	return head;}EXPORT_SYMBOL(find_type_devices);/** * Returns all nodes linked together */struct device_node *find_all_nodes(void){	struct device_node *head, **prevp, *np;	prevp = &head;	for (np = allnodes; np != 0; np = np->allnext) {		*prevp = np;		prevp = &np->next;	}	*prevp = NULL;	return head;}EXPORT_SYMBOL(find_all_nodes);/** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */intdevice_is_compatible(struct device_node *device, const char *compat){	const char* cp;	int cplen, l;	cp = (char *) get_property(device, "compatible", &cplen);	if (cp == NULL)		return 0;	while (cplen > 0) {		if (strncasecmp(cp, compat, strlen(compat)) == 0)			return 1;		l = strlen(cp) + 1;		cp += l;		cplen -= l;	}	return 0;}EXPORT_SYMBOL(device_is_compatible);/** * Indicates whether the root node has a given value in its * compatible property. */intmachine_is_compatible(const char *compat){	struct device_node *root;	int rc = 0;	root = of_find_node_by_path("/");	if (root) {		rc = device_is_compatible(root, compat);		of_node_put(root);	}	return rc;}EXPORT_SYMBOL(machine_is_compatible);/** * Construct and return a list of the device_nodes with a given type * and compatible property. */struct device_node *find_compatible_devices(const char *type, const char *compat){	struct device_node *head, **prevp, *np;	prevp = &head;	for (np = allnodes; np != 0; np = np->allnext) {		if (type != NULL		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))			continue;		if (device_is_compatible(np, compat)) {			*prevp = np;			prevp = &np->next;		}	}	*prevp = NULL;	return head;}EXPORT_SYMBOL(find_compatible_devices);/** * Find the device_node with a given full_name. */struct device_node *find_path_device(const char *path){	struct device_node *np;	for (np = allnodes; np != 0; np = np->allnext)		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)			return np;	return NULL;}EXPORT_SYMBOL(find_path_device);/******* * * New implementation of the OF "find" APIs, return a refcounted * object, call of_node_put() when done.  The device tree and list * are protected by a rw_lock. *

⌨️ 快捷键说明

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