📄 ibmphp_res.c
字号:
} 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 + -