📄 cpqphp_pci.c
字号:
rc = cpqhp_save_config(ctrl, sub_bus, 0); if (rc) return(rc); ctrl->pci_bus->number = new_slot->bus; } // End of IF new_slot->status = 0; for (cloop = 0; cloop < 0x20; cloop++) { pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); } function++; stop_it = 0; // this loop skips to the next present function // reading in the Class Code and the Header type. while ((function < max_functions) && (!stop_it)) { pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); if (ID == 0xFFFFFFFF) { // nothing there. function++; } else { // Something there pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); stop_it++; } } } while (function < max_functions); } // End of IF (device in slot?) else { return 2; } return 0;}/* * cpqhp_save_base_addr_length * * Saves the length of all base address registers for the * specified slot. this is for hot plug REPLACE * * returns 0 if success */int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func){ u8 cloop; u8 header_type; u8 secondary_bus; u8 type; int sub_bus; u32 temp_register; u32 base; u32 rc; struct pci_func *next; int index = 0; struct pci_bus *pci_bus = ctrl->pci_bus; unsigned int devfn; func = cpqhp_slot_find(func->bus, func->device, index++); while (func != NULL) { pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); // Check for Bridge pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; next = cpqhp_slot_list[sub_bus]; while (next != NULL) { rc = cpqhp_save_base_addr_length(ctrl, next); if (rc) return rc; next = next->next; } pci_bus->number = func->bus; //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together // Figure out IO and memory base lengths for (cloop = 0x10; cloop <= 0x14; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); if (base) { // If this register is implemented if (base & 0x01L) { // IO base // set base = amount of IO space requested base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { // memory base base = base & 0xFFFFFFF0; base = (~base) + 1; type = 0; } } else { base = 0x0L; type = 0; } // Save information in slot structure func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; } // End of base register loop } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge // Figure out IO and memory base lengths for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); if (base) { // If this register is implemented if (base & 0x01L) { // IO base // base = amount of IO space requested base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { // memory base // base = amount of memory space requested base = base & 0xFFFFFFF0; base = (~base) + 1; type = 0; } } else { base = 0x0L; type = 0; } // Save information in slot structure func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; } // End of base register loop } else { // Some other unknown header type } // find the next device in this slot func = cpqhp_slot_find(func->bus, func->device, index++); } return(0);}/* * cpqhp_save_used_resources * * Stores used resource information for existing boards. this is * for boards that were in the system when this driver was loaded. * this function is for hot plug ADD * * returns 0 if success */int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func){ u8 cloop; u8 header_type; u8 secondary_bus; u8 temp_byte; u8 b_base; u8 b_length; u16 command; u16 save_command; u16 w_base; u16 w_length; u32 temp_register; u32 save_base; u32 base; int index = 0; struct pci_resource *mem_node; struct pci_resource *p_mem_node; struct pci_resource *io_node; struct pci_resource *bus_node; struct pci_bus *pci_bus = ctrl->pci_bus; unsigned int devfn; func = cpqhp_slot_find(func->bus, func->device, index++); while ((func != NULL) && func->is_a_board) { pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); // Save the command register pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); // disable card command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); // Check for Bridge pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge // Clear Bridge Control Register command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL); if (!bus_node) return -ENOMEM; bus_node->base = secondary_bus; bus_node->length = temp_byte - secondary_bus + 1; bus_node->next = func->bus_head; func->bus_head = bus_node; // Save IO base and Limit registers pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base); pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length); if ((b_base <= b_length) && (save_command & 0x01)) { io_node = kmalloc(sizeof(*io_node), GFP_KERNEL); if (!io_node) return -ENOMEM; io_node->base = (b_base & 0xF0) << 8; io_node->length = (b_length - b_base + 0x10) << 8; io_node->next = func->io_head; func->io_head = io_node; } // Save memory base and Limit registers pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); if ((w_base <= w_length) && (save_command & 0x02)) { mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); if (!mem_node) return -ENOMEM; mem_node->base = w_base << 16; mem_node->length = (w_length - w_base + 0x10) << 16; mem_node->next = func->mem_head; func->mem_head = mem_node; } // Save prefetchable memory base and Limit registers pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); if ((w_base <= w_length) && (save_command & 0x02)) { p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); if (!p_mem_node) return -ENOMEM; p_mem_node->base = w_base << 16; p_mem_node->length = (w_length - w_base + 0x10) << 16; p_mem_node->next = func->p_mem_head; func->p_mem_head = p_mem_node; } // Figure out IO and memory base lengths for (cloop = 0x10; cloop <= 0x14; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); temp_register = 0xFFFFFFFF; pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword(pci_bus, devfn, cloop, &base); temp_register = base; if (base) { // If this register is implemented if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { // IO base // set temp_register = amount of IO space requested temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; io_node = kmalloc(sizeof(*io_node), GFP_KERNEL); if (!io_node) return -ENOMEM; io_node->base = save_base & (~0x03L); io_node->length = temp_register; io_node->next = func->io_head; func->io_head = io_node; } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { // prefetchable memory base temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); if (!p_mem_node) return -ENOMEM; p_mem_node->base = save_base & (~0x0FL); p_mem_node->length = temp_register; p_mem_node->next = func->p_mem_head; func->p_mem_head = p_mem_node; } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { // prefetchable memory base temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); if (!mem_node) return -ENOMEM; mem_node->base = save_base & (~0x0FL); mem_node->length = temp_register; mem_node->next = func->mem_head; func->mem_head = mem_node; } else return(1); } } // End of base register loop } else if ((header_type & 0x7F) == 0x00) { // Standard header // Figure out IO and memory base lengths for (cloop = 0x10; cloop <= 0x24; cloop += 4) { pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); temp_register = 0xFFFFFFFF; pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword(pci_bus, devfn, cloop, &base); temp_register = base; if (base) { // If this register is implemented if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { // IO base // set temp_register = amount of IO space requested temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; io_node = kmalloc(sizeof(*io_node), GFP_KERNEL); if (!io_node) return -ENOMEM; io_node->base = save_base & (~0x01L); io_node->length = temp_register; io_node->next = func->io_head; func->io_head = io_node; } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { // prefetchable memory base temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); if (!p_mem_node) return -ENOMEM; p_mem_node->base = save_base & (~0x0FL); p_mem_node->length = temp_register; p_mem_node->next = func->p_mem_head; func->p_mem_head = p_mem_node; } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { // prefetchable memory base temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); if (!mem_node) return -ENOMEM; mem_node->base = save_base & (~0x0FL); mem_node->length = temp_register; mem_node->next = func->mem_head; func->mem_head = mem_node; } else return(1); } } // End of base register loop } else { // Some other unknown header type } // find the next device in this slot func = cpqhp_slot_find(func->bus, func->device, index++); } return(0);}/* * cpqhp_configure_board * * Copies saved configuration information to one slot. * this is called recursively for bridge devices. * this is for hot plug REPLACE! * * returns 0 if success */int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func){ int cloop; u8 header_type; u8 secondary_bus; int sub_bus; struct pci_func *next; u32 temp; u32 rc; int index = 0; struct pci_bus *pci_bus = ctrl->pci_bus; unsigned int devfn; func = cpqhp_slot_find(func->bus, func->device, index++); while (func != NULL) { pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); // Start at the top of config space so that the control // registers are programmed last for (cloop = 0x3C; cloop > 0; cloop -= 4) { pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); } pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); // If this is a bridge device, restore subordinate devices if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; next = cpqhp_slot_list[sub_bus]; while (next != NULL) { rc = cpqhp_configure_board(ctrl, next); if (rc) return rc; next = next->next; } } else { // Check all the base Address Registers to make sure // they are the same. If not, the board is different. for (cloop = 16; cloop < 40; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); if (temp != func->config_space[cloop >> 2]) { dbg("Config space compare failure!!! offset = %x\n", cloop); dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]); return 1; } } } func->configured = 1; func = cpqhp_slot_find(func->bus, func->device, index++); } return 0;}/* * cpqhp_valid_replace * * this function checks to see if a board is the same as the * one it is replacing. this check will detect if the device's * vendor or device id's are the same * * returns 0 if the board is the same nonzero otherwise */int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func){ u8 cloop; u8 header_type; u8 secondary_bus; u8 type; u32 temp_register = 0; u32 base;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -