int ibmphp_remove_resource()

in hotplug/ibmphp_res.c [757:915]


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;
}