in hotplug/cpqphp_pci.c [299:455]
int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
{
long rc;
u8 class_code;
u8 header_type;
u32 ID;
u8 secondary_bus;
struct pci_func *new_slot;
int sub_bus;
int FirstSupported;
int LastSupported;
int max_functions;
int function;
u8 DevError;
int device = 0;
int cloop = 0;
int stop_it;
int index;
u16 devfn;
/* Decide which slots are supported */
if (is_hot_plug) {
/*
* is_hot_plug is the slot mask
*/
FirstSupported = is_hot_plug >> 4;
LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1;
} else {
FirstSupported = 0;
LastSupported = 0x1F;
}
/* Save PCI configuration space for all devices in supported slots */
ctrl->pci_bus->number = busnumber;
for (device = FirstSupported; device <= LastSupported; device++) {
ID = 0xFFFFFFFF;
rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
if (ID == 0xFFFFFFFF) {
if (is_hot_plug) {
/* Setup slot structure with entry for empty
* slot
*/
new_slot = cpqhp_slot_create(busnumber);
if (new_slot == NULL)
return 1;
new_slot->bus = (u8) busnumber;
new_slot->device = (u8) device;
new_slot->function = 0;
new_slot->is_a_board = 0;
new_slot->presence_save = 0;
new_slot->switch_save = 0;
}
continue;
}
rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
if (rc)
return rc;
rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
if (rc)
return rc;
/* If multi-function device, set max_functions to 8 */
if (header_type & 0x80)
max_functions = 8;
else
max_functions = 1;
function = 0;
do {
DevError = 0;
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
/* Recurse the subordinate bus
* get the subordinate bus number
*/
rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
if (rc) {
return rc;
} else {
sub_bus = (int) secondary_bus;
/* Save secondary bus cfg spc
* with this recursive call.
*/
rc = cpqhp_save_config(ctrl, sub_bus, 0);
if (rc)
return rc;
ctrl->pci_bus->number = busnumber;
}
}
index = 0;
new_slot = cpqhp_slot_find(busnumber, device, index++);
while (new_slot &&
(new_slot->function != (u8) function))
new_slot = cpqhp_slot_find(busnumber, device, index++);
if (!new_slot) {
/* Setup slot structure. */
new_slot = cpqhp_slot_create(busnumber);
if (new_slot == NULL)
return 1;
}
new_slot->bus = (u8) busnumber;
new_slot->device = (u8) device;
new_slot->function = (u8) function;
new_slot->is_a_board = 1;
new_slot->switch_save = 0x10;
/* In case of unsupported board */
new_slot->status = DevError;
devfn = (new_slot->device << 3) | new_slot->function;
new_slot->pci_dev = pci_get_domain_bus_and_slot(0,
new_slot->bus, devfn);
for (cloop = 0; cloop < 0x20; cloop++) {
rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) &(new_slot->config_space[cloop]));
if (rc)
return rc;
}
pci_dev_put(new_slot->pci_dev);
function++;
stop_it = 0;
/* this loop skips to the next present function
* reading in Class Code and Header type.
*/
while ((function < max_functions) && (!stop_it)) {
rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
if (ID == 0xFFFFFFFF) {
function++;
continue;
}
rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
if (rc)
return rc;
rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
if (rc)
return rc;
stop_it++;
}
} while (function < max_functions);
} /* End of FOR loop */
return 0;
}