📄 ibmphp_res.c
字号:
res_tmp = NULL; } bus_cur->firstIO = NULL; } if (bus_cur->firstMem) { res_cur = bus_cur->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_cur->firstMem = NULL; } if (bus_cur->firstPFMem) { res_cur = bus_cur->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_cur->firstPFMem = NULL; } if (bus_cur->firstPFMemFromMem) { res_cur = bus_cur->firstPFMemFromMem; while (res_cur) { res_tmp = res_cur; res_cur = res_cur->next; kfree (res_tmp); res_tmp = NULL; } bus_cur->firstPFMemFromMem = NULL; } bus_tmp = bus_cur; list_del (&bus_cur->bus_list); kfree (bus_tmp); bus_tmp = NULL; }}/********************************************************************************* * This function will go over the PFmem resources to check if the EBDA allocated * pfmem out of memory buckets of the bus. If so, it will change the range numbers * and a flag to indicate that this resource is out of memory. It will also move the * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create * a new Mem node * This routine is called right after initialization *******************************************************************************/static int __init once_over (void){ struct resource_node *pfmem_cur; struct resource_node *pfmem_prev; struct resource_node *mem; struct bus_node *bus_cur; struct list_head *tmp; list_for_each (tmp, &gbuses) { bus_cur = list_entry (tmp, struct bus_node, bus_list); if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { pfmem_cur->fromMem = TRUE; if (pfmem_prev) pfmem_prev->next = pfmem_cur->next; else bus_cur->firstPFMem = pfmem_cur->next; if (!bus_cur->firstPFMemFromMem) pfmem_cur->next = NULL; else /* we don't need to sort PFMemFromMem since we're using mem node for all the real work anyways, so just insert at the beginning of the list */ pfmem_cur->next = bus_cur->firstPFMemFromMem; bus_cur->firstPFMemFromMem = pfmem_cur; mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); if (!mem) { err ("out of system memory\n"); return -ENOMEM; } memset (mem, 0, sizeof (struct resource_node)); mem->type = MEM; mem->busno = pfmem_cur->busno; mem->devfunc = pfmem_cur->devfunc; mem->start = pfmem_cur->start; mem->end = pfmem_cur->end; mem->len = pfmem_cur->len; if (ibmphp_add_resource (mem) < 0) err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n"); pfmem_cur->rangeno = mem->rangeno; } /* end for pfmem */ } /* end if */ } /* end list_for_each bus */ return 0; }int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem){ struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0); if (!bus_cur) { err ("cannot find bus of pfmem to add...\n"); return -ENODEV; } if (bus_cur->firstPFMemFromMem) pfmem->next = bus_cur->firstPFMemFromMem; else pfmem->next = NULL; bus_cur->firstPFMemFromMem = pfmem; return 0;}/* This routine just goes through the buses to see if the bus already exists. * It is called from ibmphp_find_sec_number, to find out a secondary bus number for * bridged cards * Parameters: bus_number * Returns: Bus pointer or NULL */struct bus_node *ibmphp_find_res_bus (u8 bus_number){ return find_bus_wprev (bus_number, NULL, 0);}static struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag){ struct bus_node *bus_cur; struct list_head *tmp; struct list_head *tmp_prev; list_for_each (tmp, &gbuses) { tmp_prev = tmp->prev; bus_cur = list_entry (tmp, struct bus_node, bus_list); if (flag) *prev = list_entry (tmp_prev, struct bus_node, bus_list); if (bus_cur->busno == bus_number) return bus_cur; } return NULL;}void ibmphp_print_test (void){ int i = 0; struct bus_node *bus_cur = NULL; struct range_node *range; struct resource_node *res; struct list_head *tmp; debug_pci ("*****************START**********************\n"); if ((!list_empty(&gbuses)) && flags) { err ("The GBUSES is not NULL?!?!?!?!?\n"); return; } list_for_each (tmp, &gbuses) { bus_cur = list_entry (tmp, struct bus_node, bus_list); debug_pci ("This is bus # %d. There are\n", bus_cur->busno); debug_pci ("IORanges = %d\t", bus_cur->noIORanges); debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges); debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges); debug_pci ("The IO Ranges are as follows:\n"); if (bus_cur->rangeIO) { range = bus_cur->rangeIO; for (i = 0; i < bus_cur->noIORanges; i++) { debug_pci ("rangeno is %d\n", range->rangeno); debug_pci ("[%x - %x]\n", range->start, range->end); range = range->next; } } debug_pci ("The Mem Ranges are as follows:\n"); if (bus_cur->rangeMem) { range = bus_cur->rangeMem; for (i = 0; i < bus_cur->noMemRanges; i++) { debug_pci ("rangeno is %d\n", range->rangeno); debug_pci ("[%x - %x]\n", range->start, range->end); range = range->next; } } debug_pci ("The PFMem Ranges are as follows:\n"); if (bus_cur->rangePFMem) { range = bus_cur->rangePFMem; for (i = 0; i < bus_cur->noPFMemRanges; i++) { debug_pci ("rangeno is %d\n", range->rangeno); debug_pci ("[%x - %x]\n", range->start, range->end); range = range->next; } } debug_pci ("The resources on this bus are as follows\n"); debug_pci ("IO...\n"); if (bus_cur->firstIO) { res = bus_cur->firstIO; while (res) { debug_pci ("The range # is %d\n", res->rangeno); debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); if (res->next) res = res->next; else if (res->nextRange) res = res->nextRange; else break; } } debug_pci ("Mem...\n"); if (bus_cur->firstMem) { res = bus_cur->firstMem; while (res) { debug_pci ("The range # is %d\n", res->rangeno); debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); if (res->next) res = res->next; else if (res->nextRange) res = res->nextRange; else break; } } debug_pci ("PFMem...\n"); if (bus_cur->firstPFMem) { res = bus_cur->firstPFMem; while (res) { debug_pci ("The range # is %d\n", res->rangeno); debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); if (res->next) res = res->next; else if (res->nextRange) res = res->nextRange; else break; } } debug_pci ("PFMemFromMem...\n"); if (bus_cur->firstPFMemFromMem) { res = bus_cur->firstPFMemFromMem; while (res) { debug_pci ("The range # is %d\n", res->rangeno); debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); res = res->next; } } } debug_pci ("***********************END***********************\n");}static int range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type){ struct range_node * range_cur = NULL; switch (type) { case IO: range_cur = bus_cur->rangeIO; break; case MEM: range_cur = bus_cur->rangeMem; break; case PFMEM: range_cur = bus_cur->rangePFMem; break; default: err ("wrong type passed to find out if range already exists\n"); return -ENODEV; } while (range_cur) { if ((range_cur->start == range->start) && (range_cur->end == range->end)) return 1; range_cur = range_cur->next; } return 0;}/* This routine will read the windows for any PPB we have and update the * range info for the secondary bus, and will also input this info into * primary bus, since BIOS doesn't. This is for PPB that are in the system * on bootup. For bridged cards that were added during previous load of the * driver, only the ranges and the bus structure are added, the devices are * added from NVRAM * Input: primary busno * Returns: none * Note: this function doesn't take into account IO restrictions etc, * so will only work for bridges with no video/ISA devices behind them It * also will not work for onboard PPB's that can have more than 1 *bus * behind them All these are TO DO. * Also need to add more error checkings... (from fnc returns etc) */static int __init update_bridge_ranges (struct bus_node **bus){ u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address; u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; u32 start_address, end_address, upper_start, upper_end; struct bus_node *bus_sec; struct bus_node *bus_cur; struct resource_node *io; struct resource_node *mem; struct resource_node *pfmem; struct range_node *range; unsigned int devfn; bus_cur = *bus; if (!bus_cur) return -ENODEV; ibmphp_pci_bus->number = bus_cur->busno; debug ("inside %s\n", __FUNCTION__); debug ("bus_cur->busno = %x\n", bus_cur->busno); for (device = 0; device < 32; device++) { for (function = 0x00; function < 0x08; function++) { devfn = PCI_DEVFN(device, function); pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); if (vendor_id != PCI_VENDOR_ID_NOTVALID) { /* found correct device!!! */ pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); switch (hdr_type) { case PCI_HEADER_TYPE_NORMAL: function = 0x8; break; case PCI_HEADER_TYPE_MULTIDEVICE: break; case PCI_HEADER_TYPE_BRIDGE: function = 0x8; case PCI_HEADER_TYPE_MULTIBRIDGE: /* We assume here that only 1 bus behind the bridge TO DO: add functionality for several: temp = secondary; while (temp < subordinate) { ... temp++; } */ pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno); bus_sec = find_bus_wprev (sec_busno, NULL, 0); /* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */ if (!bus_sec) { bus_sec = alloc_error_bus (NULL, sec_busno, 1); /* the rest will be populated during NVRAM call */ return 0; } pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address); pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address); pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start); pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end); start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8; start_address |= (upper_io_start << 16); end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8; end_address |= (upper_io_end << 16); if ((start_address) && (start_address <= end_address)) { range = kmalloc (sizeof (struct range_node), GFP_KERNEL); if (!range) { err ("out of system memory\n"); return -ENOMEM; } memset (range, 0, sizeof (struct range_node)); range->start = start_address; range->end = end_address + 0xfff; if (bus_sec->noIORanges > 0) { if (!range_exists_already (range, bus_sec, IO)) { add_range (IO, range, bus_sec); ++bus_sec->noIORanges; } else { kfree (range); range = NULL; } } else { /* 1st IO Range on the bus */ range->rangeno = 1; bus_sec->rangeIO = range; ++bus_sec->noIORanges; } fix_resources (bus_sec); if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) { io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); if (!io) { kfree (range); err ("out of system memory\n"); return -ENOMEM; } memset (io, 0, sizeof (struct resource_node)); io->type = IO; io->busno = bus_cur->busno; io->devfunc = ((device << 3) | (function & 0x7)); io->start = start_address; io->end = end_address + 0xfff; io->len = io->end - io->start + 1; ibmphp_add_resource (io); } } pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address); pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address); start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; if ((start_address) && (start_address <= end_address)) { range = kmalloc (sizeof (struct range_node), GFP_KERNEL); if (!range) { err ("out of system memory\n"); return -ENOMEM; } memset (range, 0, sizeof (struct range_node)); range->start = start_address; range->end = end_address + 0xfffff; if (bus_sec->noMemRanges > 0) { if (!range_exists_already (range, bus_sec, MEM)) { add_range (MEM, range, bus_sec); ++bus_sec->noMemRanges; } else { kfree (range); range = NULL; } } else { /* 1st Mem Range on the bus */ range->rangeno = 1; bus_sec->rangeMem = range; ++bus_sec->noMemRanges; } fix_resources (bus_sec); if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) { mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); if (!mem) { kfree (range); err ("out of system memory\n"); return -ENOMEM; } memset (mem, 0, sizeof (struct resource_node)); mem->type = MEM; mem->busno = bus_cur->busno; mem->devfunc = ((device << 3) | (function & 0x7)); mem->start = start_address; mem->end = end_address + 0xfffff; mem->len = mem->end - mem->start + 1; ibmphp_add_resource (mem); } } pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address); pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address); pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start); pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end); start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;#if BITS_PER_LONG == 64 start_address |= ((long) upper_start) << 32; end_address |= ((long) upper_end) << 32;#endif if ((start_address) && (start_address <= end_address)) { range = kmalloc (sizeof (struct range_node), GFP_KERNEL); if (!range) { err ("out of system memory\n"); return -ENOMEM; } memset (range, 0, sizeof (struct range_node)); range->start = start_address; range->end = end_address + 0xfffff; if (bus_sec->noPFMemRanges > 0) { if (!range_exists_already (range, bus_sec, PFMEM)) { add_range (PFMEM, range, bus_sec); ++bus_sec->noPFMemRanges; } else { kfree (range); range = NULL; } } else { /* 1st PFMem Range on the bus */ range->rangeno = 1; bus_sec->rangePFMem = range; ++bus_sec->noPFMemRanges; } fix_resources (bus_sec); if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) { pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); if (!pfmem) { kfree (range); err ("out of system memory\n"); return -ENOMEM; } memset (pfmem, 0, sizeof (struct resource_node)); pfmem->type = PFMEM; pfmem->busno = bus_cur->busno; pfmem->devfunc = ((device << 3) | (function & 0x7)); pfmem->start = start_address; pfmem->end = end_address + 0xfffff; pfmem->len = pfmem->end - pfmem->start + 1; pfmem->fromMem = FALSE; ibmphp_add_resource (pfmem); } } break; } /* end of switch */ } /* end if vendor */ } /* end for function */ } /* end for device */ bus = &bus_cur; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -