📄 ibmphp_res.c
字号:
} } } if (!res_cur->next) { /* last device on the range */ if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) { debug ("len_tmp = %x\n", len_tmp); if ((len_tmp < len_cur) || (len_cur == 0)) { if (((res_cur->end + 1) % tmp_divide) == 0) { /* just perfect, starting address is divisible by length */ flag = TRUE; len_cur = len_tmp; start_cur = res_cur->end + 1; } else { /* Needs adjusting */ tmp_start = res_cur->end + 1; flag = FALSE; while ((len_tmp = range->end - 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 >= range->end) break; } } if (flag && len_cur == res->len) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } } } } if (res_prev) { if (res_prev->rangeno != res_cur->rangeno) { /* 1st device on this range */ if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { 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) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } } } } else { /* in the same range */ if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) { if ((len_tmp < len_cur) || (len_cur == 0)) { if (((res_prev->end + 1) % tmp_divide) == 0) { /* just perfect, starting address's divisible by length */ flag = TRUE; len_cur = len_tmp; start_cur = res_prev->end + 1; } else { /* Needs adjusting */ tmp_start = res_prev->end + 1; 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) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } } } } } /* end if (res_prev) */ res_prev = res_cur; if (res_cur->next) res_cur = res_cur->next; else res_cur = res_cur->nextRange; } /* end of while */ if (!res_prev) { /* 1st device ever */ /* need to find appropriate range */ switch (res->type) { case IO: range = bus_cur->rangeIO; break; case MEM: range = bus_cur->rangeMem; break; case PFMEM: range = bus_cur->rangePFMem; break; } while (range) { if ((len_tmp = range->end - range->start) >= res->len) { if ((len_tmp < len_cur) || (len_cur == 0)) { if ((range->start % tmp_divide) == 0) { /* just perfect, starting address's 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 = range->end - 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 >= range->end) break; } } if (flag && len_cur == res->len) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } } } range = range->next; } /* end of while */ if ((!range) && (len_cur == 0)) { /* have gone through the list of devices and ranges and haven't found n.e.thing */ err ("no appropriate range.. bailing out...\n"); return -EINVAL; } else if (len_cur) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } } if (!res_cur) { debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges); if (res_prev->rangeno < noranges) { /* if there're more ranges out there to check */ switch (res->type) { case IO: range = bus_cur->rangeIO; break; case MEM: range = bus_cur->rangeMem; break; case PFMEM: range = bus_cur->rangePFMem; break; } while (range) { if ((len_tmp = range->end - range->start) >= res->len) { if ((len_tmp < len_cur) || (len_cur == 0)) { if ((range->start % tmp_divide) == 0) { /* just perfect, starting address's 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 = range->end - 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 >= range->end) break; } } if (flag && len_cur == res->len) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } } } range = range->next; } /* end of while */ if ((!range) && (len_cur == 0)) { /* have gone through the list of devices and ranges and haven't found n.e.thing */ err ("no appropriate range.. bailing out...\n"); return -EINVAL; } else if (len_cur) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } } else { /* no more ranges to check on */ if (len_cur) { res->start = start_cur; res->len += 1; /* To restore the balance */ res->end = res->start + res->len - 1; return 0; } else { /* have gone through the list of devices and haven't found n.e.thing */ err ("no appropriate range.. bailing out...\n"); return -EINVAL; } } } /* end if(!res_cur) */ return -EINVAL;}/******************************************************************************** * This routine is called from remove_card if the card contained PPB. * It will remove all the resources on the bus as well as the bus itself * Input: Bus * Ouput: 0, -ENODEV ********************************************************************************/int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno){ struct resource_node *res_cur; struct resource_node *res_tmp; struct bus_node *prev_bus; int rc; prev_bus = find_bus_wprev (parent_busno, NULL, 0); if (!prev_bus) { debug ("something terribly wrong. Cannot find parent bus to the one to remove\n"); return -ENODEV; } debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno); rc = remove_ranges (bus, prev_bus); if (rc) return rc; if (bus->firstIO) { res_cur = bus->firstIO; while (res_cur) { res_tmp = res_cur; if (res_cur->next) res_cur = res_cur->next; else res_cur = res_cur->nextRange; kfree (res_tmp); res_tmp = NULL; } bus->firstIO = NULL; } if (bus->firstMem) { res_cur = bus->firstMem; while (res_cur) { res_tmp = res_cur; if (res_cur->next) res_cur = res_cur->next; else res_cur = res_cur->nextRange; kfree (res_tmp); res_tmp = NULL; } bus->firstMem = NULL; } if (bus->firstPFMem) { res_cur = bus->firstPFMem; while (res_cur) { res_tmp = res_cur; if (res_cur->next) res_cur = res_cur->next; else res_cur = res_cur->nextRange; kfree (res_tmp); res_tmp = NULL; } bus->firstPFMem = NULL; } if (bus->firstPFMemFromMem) { res_cur = bus->firstPFMemFromMem; while (res_cur) { res_tmp = res_cur; res_cur = res_cur->next; kfree (res_tmp); res_tmp = NULL; } bus->firstPFMemFromMem = NULL; } list_del (&bus->bus_list); kfree (bus); return 0;}/****************************************************************************** * This routine deletes the ranges from a given bus, and the entries from the * parent's bus in the resources * Input: current bus, previous bus * Output: 0, -EINVAL ******************************************************************************/static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev){ struct range_node *range_cur; struct range_node *range_tmp; int i; struct resource_node *res = NULL; if (bus_cur->noIORanges) { range_cur = bus_cur->rangeIO; for (i = 0; i < bus_cur->noIORanges; i++) { if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0) return -EINVAL; ibmphp_remove_resource (res); range_tmp = range_cur; range_cur = range_cur->next; kfree (range_tmp); range_tmp = NULL; } bus_cur->rangeIO = NULL; } if (bus_cur->noMemRanges) { range_cur = bus_cur->rangeMem; for (i = 0; i < bus_cur->noMemRanges; i++) { if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) return -EINVAL; ibmphp_remove_resource (res); range_tmp = range_cur; range_cur = range_cur->next; kfree (range_tmp); range_tmp = NULL; } bus_cur->rangeMem = NULL; } if (bus_cur->noPFMemRanges) { range_cur = bus_cur->rangePFMem; for (i = 0; i < bus_cur->noPFMemRanges; i++) { if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) return -EINVAL; ibmphp_remove_resource (res); range_tmp = range_cur; range_cur = range_cur->next; kfree (range_tmp); range_tmp = NULL; } bus_cur->rangePFMem = NULL; } return 0;}/* * find the resource node in the bus * Input: Resource needed, start address of the resource, type of resource */int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag){ struct resource_node *res_cur = NULL; char * type = ""; if (!bus) { err ("The bus passed in NULL to find resource\n"); return -ENODEV; } switch (flag) { case IO: res_cur = bus->firstIO; type = "io"; break; case MEM: res_cur = bus->firstMem; type = "mem"; break; case PFMEM: res_cur = bus->firstPFMem; type = "pfmem"; break; default: err ("wrong type of flag\n"); return -EINVAL; } while (res_cur) { if (res_cur->start == start_address) { *res = res_cur; break; } if (res_cur->next) res_cur = res_cur->next; else res_cur = res_cur->nextRange; } if (!res_cur) { if (flag == PFMEM) { res_cur = bus->firstPFMemFromMem; while (res_cur) { if (res_cur->start == start_address) { *res = res_cur; break; } res_cur = res_cur->next; } if (!res_cur) { debug ("SOS...cannot find %s resource in the bus.\n", type); return -EINVAL; } } else { debug ("SOS... cannot find %s resource in the bus.\n", type); return -EINVAL; } } if (*res) debug ("*res->start = %x\n", (*res)->start); return 0;}/*********************************************************************** * This routine will free the resource structures used by the * system. It is called from cleanup routine for the module * Parameters: none * Returns: none ***********************************************************************/void ibmphp_free_resources (void){ struct bus_node *bus_cur = NULL; struct bus_node *bus_tmp; struct range_node *range_cur; struct range_node *range_tmp; struct resource_node *res_cur; struct resource_node *res_tmp; struct list_head *tmp; struct list_head *next; int i = 0; flags = 1; list_for_each_safe (tmp, next, &gbuses) { bus_cur = list_entry (tmp, struct bus_node, bus_list); if (bus_cur->noIORanges) { range_cur = bus_cur->rangeIO; for (i = 0; i < bus_cur->noIORanges; i++) { if (!range_cur) break; range_tmp = range_cur; range_cur = range_cur->next; kfree (range_tmp); range_tmp = NULL; } } if (bus_cur->noMemRanges) { range_cur = bus_cur->rangeMem; for (i = 0; i < bus_cur->noMemRanges; i++) { if (!range_cur) break; range_tmp = range_cur; range_cur = range_cur->next; kfree (range_tmp); range_tmp = NULL; } } if (bus_cur->noPFMemRanges) { range_cur = bus_cur->rangePFMem; for (i = 0; i < bus_cur->noPFMemRanges; i++) { if (!range_cur) break; range_tmp = range_cur; range_cur = range_cur->next; kfree (range_tmp); range_tmp = NULL; } } if (bus_cur->firstIO) { res_cur = bus_cur->firstIO; while (res_cur) { res_tmp = res_cur; if (res_cur->next) res_cur = res_cur->next; else res_cur = res_cur->nextRange; kfree (res_tmp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -