in hotplug/ibmphp_res.c [575:748]
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", __func__);
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, something'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", __func__);
return 0;
}