in hotplug/cpqphp_pci.c [1170:1409]
int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start)
{
u8 temp;
u8 populated_slot;
u8 bridged_slot;
void __iomem *one_slot;
void __iomem *rom_resource_table;
struct pci_func *func = NULL;
int i = 10, index;
u32 temp_dword, rc;
struct pci_resource *mem_node;
struct pci_resource *p_mem_node;
struct pci_resource *io_node;
struct pci_resource *bus_node;
rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff);
dbg("rom_resource_table = %p\n", rom_resource_table);
if (rom_resource_table == NULL)
return -ENODEV;
/* Sum all resources and setup resource maps */
unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
dbg("unused_IRQ = %x\n", unused_IRQ);
temp = 0;
while (unused_IRQ) {
if (unused_IRQ & 1) {
cpqhp_disk_irq = temp;
break;
}
unused_IRQ = unused_IRQ >> 1;
temp++;
}
dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq);
unused_IRQ = unused_IRQ >> 1;
temp++;
while (unused_IRQ) {
if (unused_IRQ & 1) {
cpqhp_nic_irq = temp;
break;
}
unused_IRQ = unused_IRQ >> 1;
temp++;
}
dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq);
unused_IRQ = readl(rom_resource_table + PCIIRQ);
temp = 0;
if (!cpqhp_nic_irq)
cpqhp_nic_irq = ctrl->cfgspc_irq;
if (!cpqhp_disk_irq)
cpqhp_disk_irq = ctrl->cfgspc_irq;
dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
rc = compaq_nvram_load(rom_start, ctrl);
if (rc)
return rc;
one_slot = rom_resource_table + sizeof(struct hrt);
i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
dbg("number_of_entries = %d\n", i);
if (!readb(one_slot + SECONDARY_BUS))
return 1;
dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n");
while (i && readb(one_slot + SECONDARY_BUS)) {
u8 dev_func = readb(one_slot + DEV_FUNC);
u8 primary_bus = readb(one_slot + PRIMARY_BUS);
u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
u8 max_bus = readb(one_slot + MAX_BUS);
u16 io_base = readw(one_slot + IO_BASE);
u16 io_length = readw(one_slot + IO_LENGTH);
u16 mem_base = readw(one_slot + MEM_BASE);
u16 mem_length = readw(one_slot + MEM_LENGTH);
u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n",
dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
primary_bus, secondary_bus, max_bus);
/* If this entry isn't for our controller's bus, ignore it */
if (primary_bus != ctrl->bus) {
i--;
one_slot += sizeof(struct slot_rt);
continue;
}
/* find out if this entry is for an occupied slot */
ctrl->pci_bus->number = primary_bus;
pci_bus_read_config_dword(ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
dbg("temp_D_word = %x\n", temp_dword);
if (temp_dword != 0xFFFFFFFF) {
index = 0;
func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
while (func && (func->function != (dev_func & 0x07))) {
dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index);
func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++);
}
/* If we can't find a match, skip this table entry */
if (!func) {
i--;
one_slot += sizeof(struct slot_rt);
continue;
}
/* this may not work and shouldn't be used */
if (secondary_bus != primary_bus)
bridged_slot = 1;
else
bridged_slot = 0;
populated_slot = 1;
} else {
populated_slot = 0;
bridged_slot = 0;
}
/* If we've got a valid IO base, use it */
temp_dword = io_base + io_length;
if ((io_base) && (temp_dword < 0x10000)) {
io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
if (!io_node)
return -ENOMEM;
io_node->base = io_base;
io_node->length = io_length;
dbg("found io_node(base, length) = %x, %x\n",
io_node->base, io_node->length);
dbg("populated slot =%d \n", populated_slot);
if (!populated_slot) {
io_node->next = ctrl->io_head;
ctrl->io_head = io_node;
} else {
io_node->next = func->io_head;
func->io_head = io_node;
}
}
/* If we've got a valid memory base, use it */
temp_dword = mem_base + mem_length;
if ((mem_base) && (temp_dword < 0x10000)) {
mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
if (!mem_node)
return -ENOMEM;
mem_node->base = mem_base << 16;
mem_node->length = mem_length << 16;
dbg("found mem_node(base, length) = %x, %x\n",
mem_node->base, mem_node->length);
dbg("populated slot =%d \n", populated_slot);
if (!populated_slot) {
mem_node->next = ctrl->mem_head;
ctrl->mem_head = mem_node;
} else {
mem_node->next = func->mem_head;
func->mem_head = mem_node;
}
}
/* If we've got a valid prefetchable memory base, and
* the base + length isn't greater than 0xFFFF
*/
temp_dword = pre_mem_base + pre_mem_length;
if ((pre_mem_base) && (temp_dword < 0x10000)) {
p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
if (!p_mem_node)
return -ENOMEM;
p_mem_node->base = pre_mem_base << 16;
p_mem_node->length = pre_mem_length << 16;
dbg("found p_mem_node(base, length) = %x, %x\n",
p_mem_node->base, p_mem_node->length);
dbg("populated slot =%d \n", populated_slot);
if (!populated_slot) {
p_mem_node->next = ctrl->p_mem_head;
ctrl->p_mem_head = p_mem_node;
} else {
p_mem_node->next = func->p_mem_head;
func->p_mem_head = p_mem_node;
}
}
/* If we've got a valid bus number, use it
* The second condition is to ignore bus numbers on
* populated slots that don't have PCI-PCI bridges
*/
if (secondary_bus && (secondary_bus != primary_bus)) {
bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
if (!bus_node)
return -ENOMEM;
bus_node->base = secondary_bus;
bus_node->length = max_bus - secondary_bus + 1;
dbg("found bus_node(base, length) = %x, %x\n",
bus_node->base, bus_node->length);
dbg("populated slot =%d \n", populated_slot);
if (!populated_slot) {
bus_node->next = ctrl->bus_head;
ctrl->bus_head = bus_node;
} else {
bus_node->next = func->bus_head;
func->bus_head = bus_node;
}
}
i--;
one_slot += sizeof(struct slot_rt);
}
/* If all of the following fail, we don't have any resources for
* hot plug add
*/
rc = 1;
rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
return rc;
}