📄 acpiphp_res.c
字号:
* larger than "size" it will split it up. * * size must be a power of two. * */struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size){ struct pci_resource *prevnode; struct pci_resource *node; struct pci_resource *split_node; u64 temp_qword; if (!(*head)) return NULL; if (acpiphp_resource_sort_and_combine(head)) return NULL; if (sort_by_size(head)) return NULL; for (node = *head; node; node = node->next) { dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", __FUNCTION__, size, node, (u32)node->base, node->length); if (node->length < size) continue; if (node->base & (size - 1)) { dbg("%s: not aligned\n", __FUNCTION__); /* this one isn't base aligned properly so we'll make a new entry and split it up */ temp_qword = (node->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ if ((node->length - (temp_qword - node->base)) < size) continue; split_node = acpiphp_make_resource(node->base, temp_qword - node->base); if (!split_node) return NULL; node->base = temp_qword; node->length -= split_node->length; /* Put it in the list */ split_node->next = node->next; node->next = split_node; } /* End of non-aligned base */ /* Don't need to check if too small since we already did */ if (node->length > size) { dbg("%s: too big\n", __FUNCTION__); /* this one is longer than we need so we'll make a new entry and split it up */ split_node = acpiphp_make_resource(node->base + size, node->length - size); if (!split_node) return NULL; node->length = size; /* Put it in the list */ split_node->next = node->next; node->next = split_node; } /* End of too big on top end */ dbg("%s: got one!!!\n", __FUNCTION__); /* If we got here, then it is the right size Now take it out of the list */ if (*head == node) { *head = node->next; } else { prevnode = *head; while (prevnode->next != node) prevnode = prevnode->next; prevnode->next = node->next; } node->next = NULL; /* Stop looping */ break; } return node;}/** * get_resource_with_base - get resource with specific base address * * this function * returns the first node of "size" length located at specified base address. * If it finds a node larger than "size" it will split it up. * * size must be a power of two. * */struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size){ struct pci_resource *prevnode; struct pci_resource *node; struct pci_resource *split_node; u64 temp_qword; if (!(*head)) return NULL; if (acpiphp_resource_sort_and_combine(head)) return NULL; for (node = *head; node; node = node->next) { dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", (u32)base, size, node, (u32)node->base, node->length); if (node->base > base) continue; if ((node->base + node->length) < (base + size)) continue; if (node->base < base) { dbg(": split 1\n"); /* this one isn't base aligned properly so we'll make a new entry and split it up */ temp_qword = base; /* Short circuit if adjusted size is too small */ if ((node->length - (temp_qword - node->base)) < size) continue; split_node = acpiphp_make_resource(node->base, temp_qword - node->base); if (!split_node) return NULL; node->base = temp_qword; node->length -= split_node->length; /* Put it in the list */ split_node->next = node->next; node->next = split_node; } dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", (u32)base, size, node, (u32)node->base, node->length); /* Don't need to check if too small since we already did */ if (node->length > size) { dbg(": split 2\n"); /* this one is longer than we need so we'll make a new entry and split it up */ split_node = acpiphp_make_resource(node->base + size, node->length - size); if (!split_node) return NULL; node->length = size; /* Put it in the list */ split_node->next = node->next; node->next = split_node; } /* End of too big on top end */ dbg(": got one!!!\n"); /* If we got here, then it is the right size Now take it out of the list */ if (*head == node) { *head = node->next; } else { prevnode = *head; while (prevnode->next != node) prevnode = prevnode->next; prevnode->next = node->next; } node->next = NULL; /* Stop looping */ break; } return node;}/** * acpiphp_resource_sort_and_combine * * Sorts all of the nodes in the list in ascending order by * their base addresses. Also does garbage collection by * combining adjacent nodes. * * returns 0 if success */int acpiphp_resource_sort_and_combine (struct pci_resource **head){ struct pci_resource *node1; struct pci_resource *node2; int out_of_order = 1; if (!(*head)) return 1; dbg("*head->next = %p\n",(*head)->next); if (!(*head)->next) return 0; /* only one item on the list, already sorted! */ dbg("*head->base = 0x%x\n",(u32)(*head)->base); dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); while (out_of_order) { out_of_order = 0; /* Special case for swapping list head */ if (((*head)->next) && ((*head)->base > (*head)->next->base)) { node1 = *head; (*head) = (*head)->next; node1->next = (*head)->next; (*head)->next = node1; out_of_order++; } node1 = (*head); while (node1->next && node1->next->next) { if (node1->next->base > node1->next->next->base) { out_of_order++; node2 = node1->next; node1->next = node1->next->next; node1 = node1->next; node2->next = node1->next; node1->next = node2; } else node1 = node1->next; } } /* End of out_of_order loop */ node1 = *head; while (node1 && node1->next) { if ((node1->base + node1->length) == node1->next->base) { /* Combine */ dbg("8..\n"); node1->length += node1->next->length; node2 = node1->next; node1->next = node1->next->next; kfree(node2); } else node1 = node1->next; } return 0;}/** * acpiphp_make_resource - make resource structure * @base: base address of a resource * @length: length of a resource */struct pci_resource *acpiphp_make_resource (u64 base, u32 length){ struct pci_resource *res; res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); if (res) { memset(res, 0, sizeof(struct pci_resource)); res->base = base; res->length = length; } return res;}/** * acpiphp_move_resource - move linked resources from one to another * @from: head of linked resource list * @to: head of linked resource list */void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to){ struct pci_resource *tmp; while (*from) { tmp = (*from)->next; (*from)->next = *to; *to = *from; *from = tmp; } /* *from = NULL is guaranteed */}/** * acpiphp_free_resource - free all linked resources * @res: head of linked resource list */void acpiphp_free_resource (struct pci_resource **res){ struct pci_resource *tmp; while (*res) { tmp = (*res)->next; kfree(*res); *res = tmp; } /* *res = NULL is guaranteed */}/* debug support functions; will go away sometime :) */static void dump_resource(struct pci_resource *head){ struct pci_resource *p; int cnt; p = head; cnt = 0; while (p) { dbg("[%02d] %08x - %08x\n", cnt++, (u32)p->base, (u32)p->base + p->length - 1); p = p->next; }}void acpiphp_dump_resource(struct acpiphp_bridge *bridge){ dbg("I/O resource:\n"); dump_resource(bridge->io_head); dbg("MEM resource:\n"); dump_resource(bridge->mem_head); dbg("PMEM resource:\n"); dump_resource(bridge->p_mem_head); dbg("BUS resource:\n"); dump_resource(bridge->bus_head);}void acpiphp_dump_func_resource(struct acpiphp_func *func){ dbg("I/O resource:\n"); dump_resource(func->io_head); dbg("MEM resource:\n"); dump_resource(func->mem_head); dbg("PMEM resource:\n"); dump_resource(func->p_mem_head); dbg("BUS resource:\n"); dump_resource(func->bus_head);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -