int cpqhp_find_available_resources()

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;
}