📄 ibmphp_pci.c
字号:
if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ count += 1; } } else { /* regular memory */ start_address &= PCI_BASE_ADDRESS_MEM_MASK; debug ("start address of mem is %x\n", start_address); if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { err ("cannot find corresponding MEM resource to remove\n"); return -EIO; } if (mem) debug ("mem->start = %x\n", mem->start); ibmphp_remove_resource (mem); if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ count += 1; } } } /* end of mem */ } /* end of for */ return 0;}static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function){ int count; int bus_no, pri_no, sub_no, sec_no = 0; u32 start_address, tmp_address; u8 sec_number, sub_number, pri_number; struct resource_node *io = NULL; struct resource_node *mem = NULL; struct resource_node *pfmem = NULL; struct bus_node *bus; u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, 0 }; unsigned int devfn; devfn = PCI_DEVFN(device, function); ibmphp_pci_bus->number = busno; bus_no = (int) busno; debug ("busno is %x\n", busno); pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); debug ("sec_number is %x\n", sec_number); sec_no = (int) sec_number; pri_no = (int) pri_number; if (pri_no != bus_no) { err ("primary numbers in our structures and pci config space don't match.\n"); return -EINVAL; } pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); sec_no = (int) sec_no; pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number); sub_no = (int) sub_number; debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no); if (sec_no != sub_number) { err ("there're more buses behind this bridge. Hot removal is not supported. Please choose another card\n"); return -ENODEV; } bus = ibmphp_find_res_bus (sec_number); debug ("bus->busno is %x\n", bus->busno); debug ("sec_number is %x\n", sec_number); if (!bus) { err ("cannot find Bus structure for the bridged device\n"); return -EINVAL; } ibmphp_remove_bus (bus, busno); for (count = 0; address[count]; count++) { /* for 2 BARs */ pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); if (!start_address) { /* This BAR is not implemented */ continue; } tmp_address = start_address; if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ start_address &= PCI_BASE_ADDRESS_IO_MASK; if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { err ("cannot find corresponding IO resource to remove\n"); return -EIO; } if (io) debug ("io->start = %x\n", io->start); ibmphp_remove_resource (io); /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ } else { /* This is Memory */ if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { /* pfmem */ start_address &= PCI_BASE_ADDRESS_MEM_MASK; if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { err ("cannot find corresponding PFMEM resource to remove\n"); return -EINVAL; } if (pfmem) debug ("pfmem->start = %x\n", pfmem->start); ibmphp_remove_resource (pfmem); if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ count += 1; } } else { /* regular memory */ start_address &= PCI_BASE_ADDRESS_MEM_MASK; if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { err ("cannot find corresponding MEM resource to remove\n"); return -EINVAL; } if (mem) debug ("mem->start = %x\n", mem->start); ibmphp_remove_resource (mem); if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ count += 1; } } } /* end of mem */ } /* end of for */ debug ("%s - exiting, returning success\n", __FUNCTION__); return 0;}static int unconfigure_boot_card (struct slot *slot_cur){ u16 vendor_id; u32 class; u8 hdr_type; u8 device; u8 busno; u8 function; int rc; unsigned int devfn; u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ debug ("%s - enter\n", __FUNCTION__); device = slot_cur->device; busno = slot_cur->bus; debug ("b4 for loop, device is %x\n", device); /* For every function on the card */ for (function = 0x0; function < 0x08; function++) { devfn = PCI_DEVFN(device, function); ibmphp_pci_bus->number = busno; pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); if (vendor_id != PCI_VENDOR_ID_NOTVALID) { /* found correct device!!! */ ++valid_device; debug ("%s - found correct device\n", __FUNCTION__); /* header: x x x x x x x x * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge * |_=> 0 = single function device, 1 = multi-function device */ pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); debug ("hdr_type %x, class %x\n", hdr_type, class); class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ if (class == PCI_CLASS_NOT_DEFINED_VGA) { err ("The device %x function %x is VGA compatible and is not supported for hot removing. " "Please choose another device.\n", device, function); return -ENODEV; } else if (class == PCI_CLASS_DISPLAY_VGA) { err ("The device %x function %x is not supported for hot removing. " "Please choose another device.\n", device, function); return -ENODEV; } switch (hdr_type) { case PCI_HEADER_TYPE_NORMAL: rc = unconfigure_boot_device (busno, device, function); if (rc) { err ("was not able to unconfigure device %x func %x on bus %x. bailing out...\n", device, function, busno); return rc; } function = 0x8; break; case PCI_HEADER_TYPE_MULTIDEVICE: rc = unconfigure_boot_device (busno, device, function); if (rc) { err ("was not able to unconfigure device %x func %x on bus %x. bailing out...\n", device, function, busno); return rc; } break; case PCI_HEADER_TYPE_BRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { err ("This device %x function %x is not PCI-to-PCI bridge, " "and is not supported for hot-removing. " "Please try another card.\n", device, function); return -ENODEV; } rc = unconfigure_boot_bridge (busno, device, function); if (rc != 0) { err ("was not able to hot-remove PPB properly.\n"); return rc; } function = 0x8; break; case PCI_HEADER_TYPE_MULTIBRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { err ("This device %x function %x is not PCI-to-PCI bridge, " "and is not supported for hot-removing. " "Please try another card.\n", device, function); return -ENODEV; } rc = unconfigure_boot_bridge (busno, device, function); if (rc != 0) { err ("was not able to hot-remove PPB properly.\n"); return rc; } break; default: err ("MAJOR PROBLEM!!!! Cannot read device's header\n"); return -1; break; } /* end of switch */ } /* end of valid device */ } /* end of for */ if (!valid_device) { err ("Could not find device to unconfigure. Or could not read the card.\n"); return -1; } return 0;}/* * free the resources of the card (multi, single, or bridged) * Parameters: slot, flag to say if this is for removing entire module or just * unconfiguring the device * TO DO: will probably need to add some code in case there was some resource, * to remove it... this is from when we have errors in the configure_card... * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! * Returns: 0, -1, -ENODEV */int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end){ int i; int count; int rc; struct slot *sl = *slot_cur; struct pci_func *cur_func = NULL; struct pci_func *temp_func; debug ("%s - enter\n", __FUNCTION__); if (!the_end) { /* Need to unconfigure the card */ rc = unconfigure_boot_card (sl); if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) { /* In all other cases, will still need to get rid of func structure if it exists */ return rc; } } if (sl->func) { cur_func = sl->func; while (cur_func) { /* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */ if (cur_func->bus) { /* in other words, it's a PPB */ count = 2; } else { count = 6; } for (i = 0; i < count; i++) { if (cur_func->io[i]) { debug ("io[%d] exists\n", i); if (the_end > 0) ibmphp_remove_resource (cur_func->io[i]); cur_func->io[i] = NULL; } if (cur_func->mem[i]) { debug ("mem[%d] exists\n", i); if (the_end > 0) ibmphp_remove_resource (cur_func->mem[i]); cur_func->mem[i] = NULL; } if (cur_func->pfmem[i]) { debug ("pfmem[%d] exists\n", i); if (the_end > 0) ibmphp_remove_resource (cur_func->pfmem[i]); cur_func->pfmem[i] = NULL; } } temp_func = cur_func->next; kfree (cur_func); cur_func = temp_func; } } sl->func = NULL; *slot_cur = sl; debug ("%s - exit\n", __FUNCTION__); return 0;}/* * add a new bus resulting from hot-plugging a PPB bridge with devices * * Input: bus and the amount of resources needed (we know we can assign those, * since they've been checked already * Output: bus added to the correct spot * 0, -1, error */static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno){ struct range_node *io_range = NULL; struct range_node *mem_range = NULL; struct range_node *pfmem_range = NULL; struct bus_node *cur_bus = NULL; /* Trying to find the parent bus number */ if (parent_busno != 0xFF) { cur_bus = ibmphp_find_res_bus (parent_busno); if (!cur_bus) { err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); return -ENODEV; } list_add (&bus->bus_list, &cur_bus->bus_list); } if (io) { io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); if (!io_range) { err ("out of system memory\n"); return -ENOMEM; } memset (io_range, 0, sizeof (struct range_node)); io_range->start = io->start; io_range->end = io->end; io_range->rangeno = 1; bus->noIORanges = 1; bus->rangeIO = io_range; } if (mem) { mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); if (!mem_range) { err ("out of system memory\n"); return -ENOMEM; } memset (mem_range, 0, sizeof (struct range_node)); mem_range->start = mem->start; mem_range->end = mem->end; mem_range->rangeno = 1; bus->noMemRanges = 1; bus->rangeMem = mem_range; } if (pfmem) { pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); if (!pfmem_range) { err ("out of system memory\n"); return -ENOMEM; } memset (pfmem_range, 0, sizeof (struct range_node)); pfmem_range->start = pfmem->start; pfmem_range->end = pfmem->end; pfmem_range->rangeno = 1; bus->noPFMemRanges = 1; bus->rangePFMem = pfmem_range; } return 0;}/* * find the 1st available bus number for PPB to set as its secondary bus * Parameters: bus_number of the primary bus * Returns: bus_number of the secondary bus or 0xff in case of failure */static u8 find_sec_number (u8 primary_busno, u8 slotno){ int min, max; u8 busno; struct bus_info *bus; struct bus_node *bus_cur; bus = ibmphp_find_same_bus_num (primary_busno); if (!bus) { err ("cannot get slot range of the bus from the BIOS\n"); return 0xff; } max = bus->slot_max; min = bus->slot_min; if ((slotno > max) || (slotno < min)) { err ("got the wrong range\n"); return 0xff; } busno = (u8) (slotno - (u8) min); busno += primary_busno + 0x01; bus_cur = ibmphp_find_res_bus (busno); /* either there is no such bus number, or there are no ranges, which * can only happen if we removed the bridged device in previous load * of the driver, and now only have the skeleton bus struct */ if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem))) return busno; return 0xff;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -