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

📄 ibmphp_res.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
					}					break;				}				range = range->next;			}		}		if (res->next)			res = res->next;		else			res = res->nextRange;	}}/***************************************************************************** * This routine reassigns the range numbers to the resources that had a -1 * This case can happen only if upon initialization, resources taken by pci dev * appear in EBDA before the resources allocated for that bus, since we don't * know the range, we assign -1, and this routine is called after a new range * is assigned to see the resources with unknown range belong to the added range * * Input: current bus * Output: none, list of resources for that bus are fixed if can be *******************************************************************************/static void fix_resources (struct bus_node *bus_cur){	struct range_node *range;	struct resource_node *res;	debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno);	if (bus_cur->needIOUpdate) {		res = bus_cur->firstIO;		range = bus_cur->rangeIO;		fix_me (res, bus_cur, range);	}	if (bus_cur->needMemUpdate) {		res = bus_cur->firstMem;		range = bus_cur->rangeMem;		fix_me (res, bus_cur, range);	}	if (bus_cur->needPFMemUpdate) {		res = bus_cur->firstPFMem;		range = bus_cur->rangePFMem;		fix_me (res, bus_cur, range);	}}/******************************************************************************* * This routine adds a resource to the list of resources to the appropriate bus  * based on their resource type and sorted by their starting addresses.  It assigns * the ptrs to next and nextRange if needed. * * Input: resource ptr * Output: ptrs assigned (to the node) * 0 or -1 *******************************************************************************/int ibmphp_add_resource (struct resource_node *res){	struct resource_node *res_cur;	struct resource_node *res_prev;	struct bus_node *bus_cur;	struct range_node *range_cur = NULL;	struct resource_node *res_start = NULL;	debug ("%s - enter\n", __FUNCTION__);	if (!res) {		err ("NULL passed to add\n");		return -ENODEV;	}		bus_cur = find_bus_wprev (res->busno, NULL, 0);		if (!bus_cur) {		/* didn't find a bus, smth's wrong!!! */		debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");		return -ENODEV;	}	/* Normal case */	switch (res->type) {		case IO:			range_cur = bus_cur->rangeIO;			res_start = bus_cur->firstIO;			break;		case MEM:			range_cur = bus_cur->rangeMem;			res_start = bus_cur->firstMem;			break;		case PFMEM:			range_cur = bus_cur->rangePFMem;			res_start = bus_cur->firstPFMem;			break;		default:			err ("cannot read the type of the resource to add... problem\n");			return -EINVAL;	}	while (range_cur) {		if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) {			res->rangeno = range_cur->rangeno;			break;		}		range_cur = range_cur->next;	}	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	 * this is again the case of rangeno = -1	 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	 */	if (!range_cur) {		switch (res->type) {			case IO:				++bus_cur->needIOUpdate;									break;			case MEM:				++bus_cur->needMemUpdate;				break;			case PFMEM:				++bus_cur->needPFMemUpdate;				break;		}		res->rangeno = -1;	}		debug ("The range is %d\n", res->rangeno);	if (!res_start) {		/* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */		switch (res->type) {			case IO:				bus_cur->firstIO = res;									break;			case MEM:				bus_cur->firstMem = res;				break;			case PFMEM:				bus_cur->firstPFMem = res;				break;		}			res->next = NULL;		res->nextRange = NULL;	} else {		res_cur = res_start;		res_prev = NULL;		debug ("res_cur->rangeno is %d\n", res_cur->rangeno);		while (res_cur) {			if (res_cur->rangeno >= res->rangeno)				break;			res_prev = res_cur;			if (res_cur->next)				res_cur = res_cur->next;			else				res_cur = res_cur->nextRange;		}		if (!res_cur) {			/* at the end of the resource list */			debug ("i should be here, [%x - %x]\n", res->start, res->end);			res_prev->nextRange = res;			res->next = NULL;			res->nextRange = NULL;		} else if (res_cur->rangeno == res->rangeno) {			/* in the same range */			while (res_cur) {				if (res->start < res_cur->start)					break;				res_prev = res_cur;				res_cur = res_cur->next;			}			if (!res_cur) {				/* the last resource in this range */				res_prev->next = res;				res->next = NULL;				res->nextRange = res_prev->nextRange;				res_prev->nextRange = NULL;			} else if (res->start < res_cur->start) {				/* at the beginning or middle of the range */				if (!res_prev)	{					switch (res->type) {						case IO:							bus_cur->firstIO = res;							break;						case MEM:							bus_cur->firstMem = res;							break;						case PFMEM:							bus_cur->firstPFMem = res;							break;					}				} else if (res_prev->rangeno == res_cur->rangeno)					res_prev->next = res;				else					res_prev->nextRange = res;				res->next = res_cur;				res->nextRange = NULL;			}		} else {			/* this is the case where it is 1st occurrence of the range */			if (!res_prev) {				/* at the beginning of the resource list */				res->next = NULL;				switch (res->type) {					case IO:						res->nextRange = bus_cur->firstIO;						bus_cur->firstIO = res;						break;					case MEM:						res->nextRange = bus_cur->firstMem;						bus_cur->firstMem = res;						break;					case PFMEM:						res->nextRange = bus_cur->firstPFMem;						bus_cur->firstPFMem = res;						break;				}			} else if (res_cur->rangeno > res->rangeno) {				/* in the middle of the resource list */				res_prev->nextRange = res;				res->next = NULL;				res->nextRange = res_cur;			}		}	}	debug ("%s - exit\n", __FUNCTION__);	return 0;}/**************************************************************************** * This routine will remove the resource from the list of resources * * Input: io, mem, and/or pfmem resource to be deleted * Ouput: modified resource list *        0 or error code ****************************************************************************/int ibmphp_remove_resource (struct resource_node *res){	struct bus_node *bus_cur;	struct resource_node *res_cur = NULL;	struct resource_node *res_prev;	struct resource_node *mem_cur;	char * type = "";	if (!res)  {		err ("resource to remove is NULL\n");		return -ENODEV;	}	bus_cur = find_bus_wprev (res->busno, NULL, 0);	if (!bus_cur) {		err ("cannot find corresponding bus of the io resource to remove  "			"bailing out...\n");		return -ENODEV;	}	switch (res->type) {		case IO:			res_cur = bus_cur->firstIO;			type = "io";			break;		case MEM:			res_cur = bus_cur->firstMem;			type = "mem";			break;		case PFMEM:			res_cur = bus_cur->firstPFMem;			type = "pfmem";			break;		default:			err ("unknown type for resource to remove\n");			return -EINVAL;	}	res_prev = NULL;	while (res_cur) {		if ((res_cur->start == res->start) && (res_cur->end == res->end))			break;		res_prev = res_cur;		if (res_cur->next)			res_cur = res_cur->next;		else			res_cur = res_cur->nextRange;	}	if (!res_cur) {		if (res->type == PFMEM) {			/* 			 * case where pfmem might be in the PFMemFromMem list			 * so will also need to remove the corresponding mem			 * entry			 */			res_cur = bus_cur->firstPFMemFromMem;			res_prev = NULL;			while (res_cur) {				if ((res_cur->start == res->start) && (res_cur->end == res->end)) {					mem_cur = bus_cur->firstMem;					while (mem_cur) {						if ((mem_cur->start == res_cur->start)						    && (mem_cur->end == res_cur->end))							break;						if (mem_cur->next)							mem_cur = mem_cur->next;						else							mem_cur = mem_cur->nextRange;					}					if (!mem_cur) {						err ("cannot find corresponding mem node for pfmem...\n");						return -EINVAL;					}					ibmphp_remove_resource (mem_cur);					if (!res_prev)						bus_cur->firstPFMemFromMem = res_cur->next;					else						res_prev->next = res_cur->next;					kfree (res_cur);					return 0;				}				res_prev = res_cur;				if (res_cur->next)					res_cur = res_cur->next;				else					res_cur = res_cur->nextRange;			}			if (!res_cur) {				err ("cannot find pfmem to delete...\n");				return -EINVAL;			}		} else {			err ("the %s resource is not in the list to be deleted...\n", type);			return -EINVAL;		}	}	if (!res_prev) {		/* first device to be deleted */		if (res_cur->next) {			switch (res->type) {				case IO:					bus_cur->firstIO = res_cur->next;					break;				case MEM:					bus_cur->firstMem = res_cur->next;					break;				case PFMEM:					bus_cur->firstPFMem = res_cur->next;					break;			}		} else if (res_cur->nextRange) {			switch (res->type) {				case IO:					bus_cur->firstIO = res_cur->nextRange;					break;				case MEM:					bus_cur->firstMem = res_cur->nextRange;					break;				case PFMEM:					bus_cur->firstPFMem = res_cur->nextRange;					break;			}		} else {			switch (res->type) {				case IO:					bus_cur->firstIO = NULL;					break;				case MEM:					bus_cur->firstMem = NULL;					break;				case PFMEM:					bus_cur->firstPFMem = NULL;					break;			}		}		kfree (res_cur);		return 0;	} else {		if (res_cur->next) {			if (res_prev->rangeno == res_cur->rangeno)				res_prev->next = res_cur->next;			else				res_prev->nextRange = res_cur->next;		} else if (res_cur->nextRange) {			res_prev->next = NULL;			res_prev->nextRange = res_cur->nextRange;		} else {			res_prev->next = NULL;			res_prev->nextRange = NULL;		}		kfree (res_cur);		return 0;	}	return 0;}static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res){	struct range_node * range = NULL;	switch (res->type) {		case IO:			range = bus_cur->rangeIO;			break;		case MEM:			range = bus_cur->rangeMem;			break;		case PFMEM:			range = bus_cur->rangePFMem;			break;		default:			err ("cannot read resource type in find_range\n");	}	while (range) {		if (res->rangeno == range->rangeno)			break;		range = range->next;	}	return range;}/***************************************************************************** * This routine will check to make sure the io/mem/pfmem->len that the device asked for  * can fit w/i our list of available IO/MEM/PFMEM resources.  If cannot, returns -EINVAL, * otherwise, returns 0 * * Input: resource * Ouput: the correct start and end address are inputted into the resource node, *        0 or -EINVAL *****************************************************************************/int ibmphp_check_resource (struct resource_node *res, u8 bridge){	struct bus_node *bus_cur;	struct range_node *range = NULL;	struct resource_node *res_prev;	struct resource_node *res_cur = NULL;	u32 len_cur = 0, start_cur = 0, len_tmp = 0;	int noranges = 0;	u32 tmp_start;		/* this is to make sure start address is divisible by the length needed */	u32 tmp_divide;	u8 flag = FALSE;	if (!res)		return -EINVAL;	if (bridge) {		/* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/		if (res->type == IO)			tmp_divide = IOBRIDGE;		else			tmp_divide = MEMBRIDGE;	} else		tmp_divide = res->len;	bus_cur = find_bus_wprev (res->busno, NULL, 0);	if (!bus_cur) {		/* didn't find a bus, smth's wrong!!! */		debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");		return -EINVAL;	}	debug ("%s - enter\n", __FUNCTION__);	debug ("bus_cur->busno is %d\n", bus_cur->busno);	/* This is a quick fix to not mess up with the code very much.  i.e.,	 * 2000-2fff, len = 1000, but when we compare, we need it to be fff */	res->len -= 1;	switch (res->type) {		case IO:			res_cur = bus_cur->firstIO;			noranges = bus_cur->noIORanges;			break;		case MEM:			res_cur = bus_cur->firstMem;			noranges = bus_cur->noMemRanges;			break;		case PFMEM:			res_cur = bus_cur->firstPFMem;			noranges = bus_cur->noPFMemRanges;			break;		default:			err ("wrong type of resource to check\n");			return -EINVAL;	}	res_prev = NULL;	while (res_cur) {		range = find_range (bus_cur, res_cur);		debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno);		if (!range) {			err ("no range for the device exists... bailing out...\n");			return -EINVAL;		}		/* found our range */		if (!res_prev) {			/* first time in the loop */			if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) {				debug ("len_tmp = %x\n", len_tmp);				if ((len_tmp < len_cur) || (len_cur == 0)) {					if ((range->start % tmp_divide) == 0) {						/* just perfect, starting address is divisible by length */						flag = TRUE;						len_cur = len_tmp;						start_cur = range->start;					} else {						/* Needs adjusting */						tmp_start = range->start;						flag = FALSE;						while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {							if ((tmp_start % tmp_divide) == 0) {								flag = TRUE;								len_cur = len_tmp;								start_cur = tmp_start;								break;							}							tmp_start += tmp_divide - tmp_start % tmp_divide;							if (tmp_start >= res_cur->start - 1)								break;						}					}								if (flag && len_cur == res->len) {						debug ("but we are not here, right?\n");						res->start = start_cur;						res->len += 1; /* To restore the balance */						res->end = res->start + res->len - 1;						return 0;					}

⌨️ 快捷键说明

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