18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Compaq Hot Plug Controller Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1995,2001 Compaq Computer Corporation
68c2ecf20Sopenharmony_ci * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
78c2ecf20Sopenharmony_ci * Copyright (C) 2001 IBM Corp.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * All rights reserved.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Send feedback to <greg@kroah.com>
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
208c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
218c2ecf20Sopenharmony_ci#include <linux/pci.h>
228c2ecf20Sopenharmony_ci#include <linux/pci_hotplug.h>
238c2ecf20Sopenharmony_ci#include "../pci.h"
248c2ecf20Sopenharmony_ci#include "cpqphp.h"
258c2ecf20Sopenharmony_ci#include "cpqphp_nvram.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciu8 cpqhp_nic_irq;
298c2ecf20Sopenharmony_ciu8 cpqhp_disk_irq;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic u16 unused_IRQ;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * detect_HRT_floating_pointer
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * find the Hot Plug Resource Table in the specified region of memory.
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_cistatic void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	void __iomem *fp;
428c2ecf20Sopenharmony_ci	void __iomem *endp;
438c2ecf20Sopenharmony_ci	u8 temp1, temp2, temp3, temp4;
448c2ecf20Sopenharmony_ci	int status = 0;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	endp = (end - sizeof(struct hrt) + 1);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	for (fp = begin; fp <= endp; fp += 16) {
498c2ecf20Sopenharmony_ci		temp1 = readb(fp + SIG0);
508c2ecf20Sopenharmony_ci		temp2 = readb(fp + SIG1);
518c2ecf20Sopenharmony_ci		temp3 = readb(fp + SIG2);
528c2ecf20Sopenharmony_ci		temp4 = readb(fp + SIG3);
538c2ecf20Sopenharmony_ci		if (temp1 == '$' &&
548c2ecf20Sopenharmony_ci		    temp2 == 'H' &&
558c2ecf20Sopenharmony_ci		    temp3 == 'R' &&
568c2ecf20Sopenharmony_ci		    temp4 == 'T') {
578c2ecf20Sopenharmony_ci			status = 1;
588c2ecf20Sopenharmony_ci			break;
598c2ecf20Sopenharmony_ci		}
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (!status)
638c2ecf20Sopenharmony_ci		fp = NULL;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	dbg("Discovered Hotplug Resource Table at %p\n", fp);
668c2ecf20Sopenharmony_ci	return fp;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciint cpqhp_configure_device(struct controller *ctrl, struct pci_func *func)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct pci_bus *child;
738c2ecf20Sopenharmony_ci	int num;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	pci_lock_rescan_remove();
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (func->pci_dev == NULL)
788c2ecf20Sopenharmony_ci		func->pci_dev = pci_get_domain_bus_and_slot(0, func->bus,
798c2ecf20Sopenharmony_ci							PCI_DEVFN(func->device,
808c2ecf20Sopenharmony_ci							func->function));
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* No pci device, we need to create it then */
838c2ecf20Sopenharmony_ci	if (func->pci_dev == NULL) {
848c2ecf20Sopenharmony_ci		dbg("INFO: pci_dev still null\n");
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function));
878c2ecf20Sopenharmony_ci		if (num)
888c2ecf20Sopenharmony_ci			pci_bus_add_devices(ctrl->pci_dev->bus);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		func->pci_dev = pci_get_domain_bus_and_slot(0, func->bus,
918c2ecf20Sopenharmony_ci							PCI_DEVFN(func->device,
928c2ecf20Sopenharmony_ci							func->function));
938c2ecf20Sopenharmony_ci		if (func->pci_dev == NULL) {
948c2ecf20Sopenharmony_ci			dbg("ERROR: pci_dev still null\n");
958c2ecf20Sopenharmony_ci			goto out;
968c2ecf20Sopenharmony_ci		}
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
1008c2ecf20Sopenharmony_ci		pci_hp_add_bridge(func->pci_dev);
1018c2ecf20Sopenharmony_ci		child = func->pci_dev->subordinate;
1028c2ecf20Sopenharmony_ci		if (child)
1038c2ecf20Sopenharmony_ci			pci_bus_add_devices(child);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	pci_dev_put(func->pci_dev);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci out:
1098c2ecf20Sopenharmony_ci	pci_unlock_rescan_remove();
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciint cpqhp_unconfigure_device(struct pci_func *func)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	int j;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	pci_lock_rescan_remove();
1218c2ecf20Sopenharmony_ci	for (j = 0; j < 8 ; j++) {
1228c2ecf20Sopenharmony_ci		struct pci_dev *temp = pci_get_domain_bus_and_slot(0,
1238c2ecf20Sopenharmony_ci							func->bus,
1248c2ecf20Sopenharmony_ci							PCI_DEVFN(func->device,
1258c2ecf20Sopenharmony_ci							j));
1268c2ecf20Sopenharmony_ci		if (temp) {
1278c2ecf20Sopenharmony_ci			pci_dev_put(temp);
1288c2ecf20Sopenharmony_ci			pci_stop_and_remove_bus_device(temp);
1298c2ecf20Sopenharmony_ci		}
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci	pci_unlock_rescan_remove();
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	u32 vendID = 0;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendID) == -1)
1408c2ecf20Sopenharmony_ci		return -1;
1418c2ecf20Sopenharmony_ci	if (vendID == 0xffffffff)
1428c2ecf20Sopenharmony_ci		return -1;
1438c2ecf20Sopenharmony_ci	return pci_bus_read_config_dword(bus, devfn, offset, value);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/*
1488c2ecf20Sopenharmony_ci * cpqhp_set_irq
1498c2ecf20Sopenharmony_ci *
1508c2ecf20Sopenharmony_ci * @bus_num: bus number of PCI device
1518c2ecf20Sopenharmony_ci * @dev_num: device number of PCI device
1528c2ecf20Sopenharmony_ci * @slot: pointer to u8 where slot number will be returned
1538c2ecf20Sopenharmony_ci */
1548c2ecf20Sopenharmony_ciint cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	int rc = 0;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (cpqhp_legacy_mode) {
1598c2ecf20Sopenharmony_ci		struct pci_dev *fakedev;
1608c2ecf20Sopenharmony_ci		struct pci_bus *fakebus;
1618c2ecf20Sopenharmony_ci		u16 temp_word;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		fakedev = kmalloc(sizeof(*fakedev), GFP_KERNEL);
1648c2ecf20Sopenharmony_ci		fakebus = kmalloc(sizeof(*fakebus), GFP_KERNEL);
1658c2ecf20Sopenharmony_ci		if (!fakedev || !fakebus) {
1668c2ecf20Sopenharmony_ci			kfree(fakedev);
1678c2ecf20Sopenharmony_ci			kfree(fakebus);
1688c2ecf20Sopenharmony_ci			return -ENOMEM;
1698c2ecf20Sopenharmony_ci		}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		fakedev->devfn = dev_num << 3;
1728c2ecf20Sopenharmony_ci		fakedev->bus = fakebus;
1738c2ecf20Sopenharmony_ci		fakebus->number = bus_num;
1748c2ecf20Sopenharmony_ci		dbg("%s: dev %d, bus %d, pin %d, num %d\n",
1758c2ecf20Sopenharmony_ci		    __func__, dev_num, bus_num, int_pin, irq_num);
1768c2ecf20Sopenharmony_ci		rc = pcibios_set_irq_routing(fakedev, int_pin - 1, irq_num);
1778c2ecf20Sopenharmony_ci		kfree(fakedev);
1788c2ecf20Sopenharmony_ci		kfree(fakebus);
1798c2ecf20Sopenharmony_ci		dbg("%s: rc %d\n", __func__, rc);
1808c2ecf20Sopenharmony_ci		if (!rc)
1818c2ecf20Sopenharmony_ci			return !rc;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		/* set the Edge Level Control Register (ELCR) */
1848c2ecf20Sopenharmony_ci		temp_word = inb(0x4d0);
1858c2ecf20Sopenharmony_ci		temp_word |= inb(0x4d1) << 8;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		temp_word |= 0x01 << irq_num;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci		/* This should only be for x86 as it sets the Edge Level
1908c2ecf20Sopenharmony_ci		 * Control Register
1918c2ecf20Sopenharmony_ci		 */
1928c2ecf20Sopenharmony_ci		outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word &
1938c2ecf20Sopenharmony_ci		0xFF00) >> 8), 0x4d1); rc = 0; }
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return rc;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_num)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	u16 tdevice;
2028c2ecf20Sopenharmony_ci	u32 work;
2038c2ecf20Sopenharmony_ci	u8 tbus;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	ctrl->pci_bus->number = bus_num;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
2088c2ecf20Sopenharmony_ci		/* Scan for access first */
2098c2ecf20Sopenharmony_ci		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
2108c2ecf20Sopenharmony_ci			continue;
2118c2ecf20Sopenharmony_ci		dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);
2128c2ecf20Sopenharmony_ci		/* Yep we got one. Not a bridge ? */
2138c2ecf20Sopenharmony_ci		if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) {
2148c2ecf20Sopenharmony_ci			*dev_num = tdevice;
2158c2ecf20Sopenharmony_ci			dbg("found it !\n");
2168c2ecf20Sopenharmony_ci			return 0;
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
2208c2ecf20Sopenharmony_ci		/* Scan for access first */
2218c2ecf20Sopenharmony_ci		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
2228c2ecf20Sopenharmony_ci			continue;
2238c2ecf20Sopenharmony_ci		dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);
2248c2ecf20Sopenharmony_ci		/* Yep we got one. bridge ? */
2258c2ecf20Sopenharmony_ci		if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
2268c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus);
2278c2ecf20Sopenharmony_ci			/* XXX: no recursion, wtf? */
2288c2ecf20Sopenharmony_ci			dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);
2298c2ecf20Sopenharmony_ci			return 0;
2308c2ecf20Sopenharmony_ci		}
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return -1;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int loop, len;
2408c2ecf20Sopenharmony_ci	u32 work;
2418c2ecf20Sopenharmony_ci	u8 tbus, tdevice, tslot;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	len = cpqhp_routing_table_length();
2448c2ecf20Sopenharmony_ci	for (loop = 0; loop < len; ++loop) {
2458c2ecf20Sopenharmony_ci		tbus = cpqhp_routing_table->slots[loop].bus;
2468c2ecf20Sopenharmony_ci		tdevice = cpqhp_routing_table->slots[loop].devfn;
2478c2ecf20Sopenharmony_ci		tslot = cpqhp_routing_table->slots[loop].slot;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		if (tslot == slot) {
2508c2ecf20Sopenharmony_ci			*bus_num = tbus;
2518c2ecf20Sopenharmony_ci			*dev_num = tdevice;
2528c2ecf20Sopenharmony_ci			ctrl->pci_bus->number = tbus;
2538c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work);
2548c2ecf20Sopenharmony_ci			if (!nobridge || (work == 0xffffffff))
2558c2ecf20Sopenharmony_ci				return 0;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci			dbg("bus_num %d devfn %d\n", *bus_num, *dev_num);
2588c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work);
2598c2ecf20Sopenharmony_ci			dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
2628c2ecf20Sopenharmony_ci				pci_bus_read_config_byte(ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus);
2638c2ecf20Sopenharmony_ci				dbg("Scan bus for Non Bridge: bus %d\n", tbus);
2648c2ecf20Sopenharmony_ci				if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) {
2658c2ecf20Sopenharmony_ci					*bus_num = tbus;
2668c2ecf20Sopenharmony_ci					return 0;
2678c2ecf20Sopenharmony_ci				}
2688c2ecf20Sopenharmony_ci			} else
2698c2ecf20Sopenharmony_ci				return 0;
2708c2ecf20Sopenharmony_ci		}
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci	return -1;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciint cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	/* plain (bridges allowed) */
2798c2ecf20Sopenharmony_ci	return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/* More PCI configuration routines; this time centered around hotplug
2848c2ecf20Sopenharmony_ci * controller
2858c2ecf20Sopenharmony_ci */
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/*
2898c2ecf20Sopenharmony_ci * cpqhp_save_config
2908c2ecf20Sopenharmony_ci *
2918c2ecf20Sopenharmony_ci * Reads configuration for all slots in a PCI bus and saves info.
2928c2ecf20Sopenharmony_ci *
2938c2ecf20Sopenharmony_ci * Note:  For non-hot plug buses, the slot # saved is the device #
2948c2ecf20Sopenharmony_ci *
2958c2ecf20Sopenharmony_ci * returns 0 if success
2968c2ecf20Sopenharmony_ci */
2978c2ecf20Sopenharmony_ciint cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	long rc;
3008c2ecf20Sopenharmony_ci	u8 class_code;
3018c2ecf20Sopenharmony_ci	u8 header_type;
3028c2ecf20Sopenharmony_ci	u32 ID;
3038c2ecf20Sopenharmony_ci	u8 secondary_bus;
3048c2ecf20Sopenharmony_ci	struct pci_func *new_slot;
3058c2ecf20Sopenharmony_ci	int sub_bus;
3068c2ecf20Sopenharmony_ci	int FirstSupported;
3078c2ecf20Sopenharmony_ci	int LastSupported;
3088c2ecf20Sopenharmony_ci	int max_functions;
3098c2ecf20Sopenharmony_ci	int function;
3108c2ecf20Sopenharmony_ci	u8 DevError;
3118c2ecf20Sopenharmony_ci	int device = 0;
3128c2ecf20Sopenharmony_ci	int cloop = 0;
3138c2ecf20Sopenharmony_ci	int stop_it;
3148c2ecf20Sopenharmony_ci	int index;
3158c2ecf20Sopenharmony_ci	u16 devfn;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* Decide which slots are supported */
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (is_hot_plug) {
3208c2ecf20Sopenharmony_ci		/*
3218c2ecf20Sopenharmony_ci		 * is_hot_plug is the slot mask
3228c2ecf20Sopenharmony_ci		 */
3238c2ecf20Sopenharmony_ci		FirstSupported = is_hot_plug >> 4;
3248c2ecf20Sopenharmony_ci		LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1;
3258c2ecf20Sopenharmony_ci	} else {
3268c2ecf20Sopenharmony_ci		FirstSupported = 0;
3278c2ecf20Sopenharmony_ci		LastSupported = 0x1F;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* Save PCI configuration space for all devices in supported slots */
3318c2ecf20Sopenharmony_ci	ctrl->pci_bus->number = busnumber;
3328c2ecf20Sopenharmony_ci	for (device = FirstSupported; device <= LastSupported; device++) {
3338c2ecf20Sopenharmony_ci		ID = 0xFFFFFFFF;
3348c2ecf20Sopenharmony_ci		rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		if (ID == 0xFFFFFFFF) {
3378c2ecf20Sopenharmony_ci			if (is_hot_plug) {
3388c2ecf20Sopenharmony_ci				/* Setup slot structure with entry for empty
3398c2ecf20Sopenharmony_ci				 * slot
3408c2ecf20Sopenharmony_ci				 */
3418c2ecf20Sopenharmony_ci				new_slot = cpqhp_slot_create(busnumber);
3428c2ecf20Sopenharmony_ci				if (new_slot == NULL)
3438c2ecf20Sopenharmony_ci					return 1;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci				new_slot->bus = (u8) busnumber;
3468c2ecf20Sopenharmony_ci				new_slot->device = (u8) device;
3478c2ecf20Sopenharmony_ci				new_slot->function = 0;
3488c2ecf20Sopenharmony_ci				new_slot->is_a_board = 0;
3498c2ecf20Sopenharmony_ci				new_slot->presence_save = 0;
3508c2ecf20Sopenharmony_ci				new_slot->switch_save = 0;
3518c2ecf20Sopenharmony_ci			}
3528c2ecf20Sopenharmony_ci			continue;
3538c2ecf20Sopenharmony_ci		}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
3568c2ecf20Sopenharmony_ci		if (rc)
3578c2ecf20Sopenharmony_ci			return rc;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
3608c2ecf20Sopenharmony_ci		if (rc)
3618c2ecf20Sopenharmony_ci			return rc;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		/* If multi-function device, set max_functions to 8 */
3648c2ecf20Sopenharmony_ci		if (header_type & 0x80)
3658c2ecf20Sopenharmony_ci			max_functions = 8;
3668c2ecf20Sopenharmony_ci		else
3678c2ecf20Sopenharmony_ci			max_functions = 1;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		function = 0;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		do {
3728c2ecf20Sopenharmony_ci			DevError = 0;
3738c2ecf20Sopenharmony_ci			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
3748c2ecf20Sopenharmony_ci				/* Recurse the subordinate bus
3758c2ecf20Sopenharmony_ci				 * get the subordinate bus number
3768c2ecf20Sopenharmony_ci				 */
3778c2ecf20Sopenharmony_ci				rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
3788c2ecf20Sopenharmony_ci				if (rc) {
3798c2ecf20Sopenharmony_ci					return rc;
3808c2ecf20Sopenharmony_ci				} else {
3818c2ecf20Sopenharmony_ci					sub_bus = (int) secondary_bus;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci					/* Save secondary bus cfg spc
3848c2ecf20Sopenharmony_ci					 * with this recursive call.
3858c2ecf20Sopenharmony_ci					 */
3868c2ecf20Sopenharmony_ci					rc = cpqhp_save_config(ctrl, sub_bus, 0);
3878c2ecf20Sopenharmony_ci					if (rc)
3888c2ecf20Sopenharmony_ci						return rc;
3898c2ecf20Sopenharmony_ci					ctrl->pci_bus->number = busnumber;
3908c2ecf20Sopenharmony_ci				}
3918c2ecf20Sopenharmony_ci			}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci			index = 0;
3948c2ecf20Sopenharmony_ci			new_slot = cpqhp_slot_find(busnumber, device, index++);
3958c2ecf20Sopenharmony_ci			while (new_slot &&
3968c2ecf20Sopenharmony_ci			       (new_slot->function != (u8) function))
3978c2ecf20Sopenharmony_ci				new_slot = cpqhp_slot_find(busnumber, device, index++);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci			if (!new_slot) {
4008c2ecf20Sopenharmony_ci				/* Setup slot structure. */
4018c2ecf20Sopenharmony_ci				new_slot = cpqhp_slot_create(busnumber);
4028c2ecf20Sopenharmony_ci				if (new_slot == NULL)
4038c2ecf20Sopenharmony_ci					return 1;
4048c2ecf20Sopenharmony_ci			}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci			new_slot->bus = (u8) busnumber;
4078c2ecf20Sopenharmony_ci			new_slot->device = (u8) device;
4088c2ecf20Sopenharmony_ci			new_slot->function = (u8) function;
4098c2ecf20Sopenharmony_ci			new_slot->is_a_board = 1;
4108c2ecf20Sopenharmony_ci			new_slot->switch_save = 0x10;
4118c2ecf20Sopenharmony_ci			/* In case of unsupported board */
4128c2ecf20Sopenharmony_ci			new_slot->status = DevError;
4138c2ecf20Sopenharmony_ci			devfn = (new_slot->device << 3) | new_slot->function;
4148c2ecf20Sopenharmony_ci			new_slot->pci_dev = pci_get_domain_bus_and_slot(0,
4158c2ecf20Sopenharmony_ci							new_slot->bus, devfn);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci			for (cloop = 0; cloop < 0x20; cloop++) {
4188c2ecf20Sopenharmony_ci				rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) &(new_slot->config_space[cloop]));
4198c2ecf20Sopenharmony_ci				if (rc)
4208c2ecf20Sopenharmony_ci					return rc;
4218c2ecf20Sopenharmony_ci			}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci			pci_dev_put(new_slot->pci_dev);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci			function++;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci			stop_it = 0;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci			/* this loop skips to the next present function
4308c2ecf20Sopenharmony_ci			 * reading in Class Code and Header type.
4318c2ecf20Sopenharmony_ci			 */
4328c2ecf20Sopenharmony_ci			while ((function < max_functions) && (!stop_it)) {
4338c2ecf20Sopenharmony_ci				rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
4348c2ecf20Sopenharmony_ci				if (ID == 0xFFFFFFFF) {
4358c2ecf20Sopenharmony_ci					function++;
4368c2ecf20Sopenharmony_ci					continue;
4378c2ecf20Sopenharmony_ci				}
4388c2ecf20Sopenharmony_ci				rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
4398c2ecf20Sopenharmony_ci				if (rc)
4408c2ecf20Sopenharmony_ci					return rc;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci				rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
4438c2ecf20Sopenharmony_ci				if (rc)
4448c2ecf20Sopenharmony_ci					return rc;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci				stop_it++;
4478c2ecf20Sopenharmony_ci			}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		} while (function < max_functions);
4508c2ecf20Sopenharmony_ci	}			/* End of FOR loop */
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	return 0;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci/*
4578c2ecf20Sopenharmony_ci * cpqhp_save_slot_config
4588c2ecf20Sopenharmony_ci *
4598c2ecf20Sopenharmony_ci * Saves configuration info for all PCI devices in a given slot
4608c2ecf20Sopenharmony_ci * including subordinate buses.
4618c2ecf20Sopenharmony_ci *
4628c2ecf20Sopenharmony_ci * returns 0 if success
4638c2ecf20Sopenharmony_ci */
4648c2ecf20Sopenharmony_ciint cpqhp_save_slot_config(struct controller *ctrl, struct pci_func *new_slot)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	long rc;
4678c2ecf20Sopenharmony_ci	u8 class_code;
4688c2ecf20Sopenharmony_ci	u8 header_type;
4698c2ecf20Sopenharmony_ci	u32 ID;
4708c2ecf20Sopenharmony_ci	u8 secondary_bus;
4718c2ecf20Sopenharmony_ci	int sub_bus;
4728c2ecf20Sopenharmony_ci	int max_functions;
4738c2ecf20Sopenharmony_ci	int function = 0;
4748c2ecf20Sopenharmony_ci	int cloop = 0;
4758c2ecf20Sopenharmony_ci	int stop_it;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ID = 0xFFFFFFFF;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	ctrl->pci_bus->number = new_slot->bus;
4808c2ecf20Sopenharmony_ci	pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	if (ID == 0xFFFFFFFF)
4838c2ecf20Sopenharmony_ci		return 2;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
4868c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (header_type & 0x80)	/* Multi-function device */
4898c2ecf20Sopenharmony_ci		max_functions = 8;
4908c2ecf20Sopenharmony_ci	else
4918c2ecf20Sopenharmony_ci		max_functions = 1;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	while (function < max_functions) {
4948c2ecf20Sopenharmony_ci		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
4958c2ecf20Sopenharmony_ci			/*  Recurse the subordinate bus */
4968c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci			sub_bus = (int) secondary_bus;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci			/* Save the config headers for the secondary
5018c2ecf20Sopenharmony_ci			 * bus.
5028c2ecf20Sopenharmony_ci			 */
5038c2ecf20Sopenharmony_ci			rc = cpqhp_save_config(ctrl, sub_bus, 0);
5048c2ecf20Sopenharmony_ci			if (rc)
5058c2ecf20Sopenharmony_ci				return(rc);
5068c2ecf20Sopenharmony_ci			ctrl->pci_bus->number = new_slot->bus;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci		new_slot->status = 0;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		for (cloop = 0; cloop < 0x20; cloop++)
5138c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) &(new_slot->config_space[cloop]));
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		function++;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		stop_it = 0;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		/* this loop skips to the next present function
5208c2ecf20Sopenharmony_ci		 * reading in the Class Code and the Header type.
5218c2ecf20Sopenharmony_ci		 */
5228c2ecf20Sopenharmony_ci		while ((function < max_functions) && (!stop_it)) {
5238c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci			if (ID == 0xFFFFFFFF)
5268c2ecf20Sopenharmony_ci				function++;
5278c2ecf20Sopenharmony_ci			else {
5288c2ecf20Sopenharmony_ci				pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
5298c2ecf20Sopenharmony_ci				pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
5308c2ecf20Sopenharmony_ci				stop_it++;
5318c2ecf20Sopenharmony_ci			}
5328c2ecf20Sopenharmony_ci		}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	return 0;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/*
5418c2ecf20Sopenharmony_ci * cpqhp_save_base_addr_length
5428c2ecf20Sopenharmony_ci *
5438c2ecf20Sopenharmony_ci * Saves the length of all base address registers for the
5448c2ecf20Sopenharmony_ci * specified slot.  this is for hot plug REPLACE
5458c2ecf20Sopenharmony_ci *
5468c2ecf20Sopenharmony_ci * returns 0 if success
5478c2ecf20Sopenharmony_ci */
5488c2ecf20Sopenharmony_ciint cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	u8 cloop;
5518c2ecf20Sopenharmony_ci	u8 header_type;
5528c2ecf20Sopenharmony_ci	u8 secondary_bus;
5538c2ecf20Sopenharmony_ci	u8 type;
5548c2ecf20Sopenharmony_ci	int sub_bus;
5558c2ecf20Sopenharmony_ci	u32 temp_register;
5568c2ecf20Sopenharmony_ci	u32 base;
5578c2ecf20Sopenharmony_ci	u32 rc;
5588c2ecf20Sopenharmony_ci	struct pci_func *next;
5598c2ecf20Sopenharmony_ci	int index = 0;
5608c2ecf20Sopenharmony_ci	struct pci_bus *pci_bus = ctrl->pci_bus;
5618c2ecf20Sopenharmony_ci	unsigned int devfn;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	func = cpqhp_slot_find(func->bus, func->device, index++);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	while (func != NULL) {
5668c2ecf20Sopenharmony_ci		pci_bus->number = func->bus;
5678c2ecf20Sopenharmony_ci		devfn = PCI_DEVFN(func->device, func->function);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		/* Check for Bridge */
5708c2ecf20Sopenharmony_ci		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
5738c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci			sub_bus = (int) secondary_bus;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci			next = cpqhp_slot_list[sub_bus];
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci			while (next != NULL) {
5808c2ecf20Sopenharmony_ci				rc = cpqhp_save_base_addr_length(ctrl, next);
5818c2ecf20Sopenharmony_ci				if (rc)
5828c2ecf20Sopenharmony_ci					return rc;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci				next = next->next;
5858c2ecf20Sopenharmony_ci			}
5868c2ecf20Sopenharmony_ci			pci_bus->number = func->bus;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci			/* FIXME: this loop is duplicated in the non-bridge
5898c2ecf20Sopenharmony_ci			 * case.  The two could be rolled together Figure out
5908c2ecf20Sopenharmony_ci			 * IO and memory base lengths
5918c2ecf20Sopenharmony_ci			 */
5928c2ecf20Sopenharmony_ci			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
5938c2ecf20Sopenharmony_ci				temp_register = 0xFFFFFFFF;
5948c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
5958c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
5968c2ecf20Sopenharmony_ci				/* If this register is implemented */
5978c2ecf20Sopenharmony_ci				if (base) {
5988c2ecf20Sopenharmony_ci					if (base & 0x01L) {
5998c2ecf20Sopenharmony_ci						/* IO base
6008c2ecf20Sopenharmony_ci						 * set base = amount of IO space
6018c2ecf20Sopenharmony_ci						 * requested
6028c2ecf20Sopenharmony_ci						 */
6038c2ecf20Sopenharmony_ci						base = base & 0xFFFFFFFE;
6048c2ecf20Sopenharmony_ci						base = (~base) + 1;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci						type = 1;
6078c2ecf20Sopenharmony_ci					} else {
6088c2ecf20Sopenharmony_ci						/* memory base */
6098c2ecf20Sopenharmony_ci						base = base & 0xFFFFFFF0;
6108c2ecf20Sopenharmony_ci						base = (~base) + 1;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci						type = 0;
6138c2ecf20Sopenharmony_ci					}
6148c2ecf20Sopenharmony_ci				} else {
6158c2ecf20Sopenharmony_ci					base = 0x0L;
6168c2ecf20Sopenharmony_ci					type = 0;
6178c2ecf20Sopenharmony_ci				}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci				/* Save information in slot structure */
6208c2ecf20Sopenharmony_ci				func->base_length[(cloop - 0x10) >> 2] =
6218c2ecf20Sopenharmony_ci				base;
6228c2ecf20Sopenharmony_ci				func->base_type[(cloop - 0x10) >> 2] = type;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci			}	/* End of base register loop */
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		} else if ((header_type & 0x7F) == 0x00) {
6278c2ecf20Sopenharmony_ci			/* Figure out IO and memory base lengths */
6288c2ecf20Sopenharmony_ci			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
6298c2ecf20Sopenharmony_ci				temp_register = 0xFFFFFFFF;
6308c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
6318c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci				/* If this register is implemented */
6348c2ecf20Sopenharmony_ci				if (base) {
6358c2ecf20Sopenharmony_ci					if (base & 0x01L) {
6368c2ecf20Sopenharmony_ci						/* IO base
6378c2ecf20Sopenharmony_ci						 * base = amount of IO space
6388c2ecf20Sopenharmony_ci						 * requested
6398c2ecf20Sopenharmony_ci						 */
6408c2ecf20Sopenharmony_ci						base = base & 0xFFFFFFFE;
6418c2ecf20Sopenharmony_ci						base = (~base) + 1;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci						type = 1;
6448c2ecf20Sopenharmony_ci					} else {
6458c2ecf20Sopenharmony_ci						/* memory base
6468c2ecf20Sopenharmony_ci						 * base = amount of memory
6478c2ecf20Sopenharmony_ci						 * space requested
6488c2ecf20Sopenharmony_ci						 */
6498c2ecf20Sopenharmony_ci						base = base & 0xFFFFFFF0;
6508c2ecf20Sopenharmony_ci						base = (~base) + 1;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci						type = 0;
6538c2ecf20Sopenharmony_ci					}
6548c2ecf20Sopenharmony_ci				} else {
6558c2ecf20Sopenharmony_ci					base = 0x0L;
6568c2ecf20Sopenharmony_ci					type = 0;
6578c2ecf20Sopenharmony_ci				}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci				/* Save information in slot structure */
6608c2ecf20Sopenharmony_ci				func->base_length[(cloop - 0x10) >> 2] = base;
6618c2ecf20Sopenharmony_ci				func->base_type[(cloop - 0x10) >> 2] = type;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci			}	/* End of base register loop */
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		} else {	  /* Some other unknown header type */
6668c2ecf20Sopenharmony_ci		}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		/* find the next device in this slot */
6698c2ecf20Sopenharmony_ci		func = cpqhp_slot_find(func->bus, func->device, index++);
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return(0);
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci/*
6778c2ecf20Sopenharmony_ci * cpqhp_save_used_resources
6788c2ecf20Sopenharmony_ci *
6798c2ecf20Sopenharmony_ci * Stores used resource information for existing boards.  this is
6808c2ecf20Sopenharmony_ci * for boards that were in the system when this driver was loaded.
6818c2ecf20Sopenharmony_ci * this function is for hot plug ADD
6828c2ecf20Sopenharmony_ci *
6838c2ecf20Sopenharmony_ci * returns 0 if success
6848c2ecf20Sopenharmony_ci */
6858c2ecf20Sopenharmony_ciint cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	u8 cloop;
6888c2ecf20Sopenharmony_ci	u8 header_type;
6898c2ecf20Sopenharmony_ci	u8 secondary_bus;
6908c2ecf20Sopenharmony_ci	u8 temp_byte;
6918c2ecf20Sopenharmony_ci	u8 b_base;
6928c2ecf20Sopenharmony_ci	u8 b_length;
6938c2ecf20Sopenharmony_ci	u16 command;
6948c2ecf20Sopenharmony_ci	u16 save_command;
6958c2ecf20Sopenharmony_ci	u16 w_base;
6968c2ecf20Sopenharmony_ci	u16 w_length;
6978c2ecf20Sopenharmony_ci	u32 temp_register;
6988c2ecf20Sopenharmony_ci	u32 save_base;
6998c2ecf20Sopenharmony_ci	u32 base;
7008c2ecf20Sopenharmony_ci	int index = 0;
7018c2ecf20Sopenharmony_ci	struct pci_resource *mem_node;
7028c2ecf20Sopenharmony_ci	struct pci_resource *p_mem_node;
7038c2ecf20Sopenharmony_ci	struct pci_resource *io_node;
7048c2ecf20Sopenharmony_ci	struct pci_resource *bus_node;
7058c2ecf20Sopenharmony_ci	struct pci_bus *pci_bus = ctrl->pci_bus;
7068c2ecf20Sopenharmony_ci	unsigned int devfn;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	func = cpqhp_slot_find(func->bus, func->device, index++);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	while ((func != NULL) && func->is_a_board) {
7118c2ecf20Sopenharmony_ci		pci_bus->number = func->bus;
7128c2ecf20Sopenharmony_ci		devfn = PCI_DEVFN(func->device, func->function);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		/* Save the command register */
7158c2ecf20Sopenharmony_ci		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci		/* disable card */
7188c2ecf20Sopenharmony_ci		command = 0x00;
7198c2ecf20Sopenharmony_ci		pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci		/* Check for Bridge */
7228c2ecf20Sopenharmony_ci		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
7258c2ecf20Sopenharmony_ci			/* Clear Bridge Control Register */
7268c2ecf20Sopenharmony_ci			command = 0x00;
7278c2ecf20Sopenharmony_ci			pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
7288c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
7298c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
7328c2ecf20Sopenharmony_ci			if (!bus_node)
7338c2ecf20Sopenharmony_ci				return -ENOMEM;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci			bus_node->base = secondary_bus;
7368c2ecf20Sopenharmony_ci			bus_node->length = temp_byte - secondary_bus + 1;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci			bus_node->next = func->bus_head;
7398c2ecf20Sopenharmony_ci			func->bus_head = bus_node;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci			/* Save IO base and Limit registers */
7428c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base);
7438c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci			if ((b_base <= b_length) && (save_command & 0x01)) {
7468c2ecf20Sopenharmony_ci				io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
7478c2ecf20Sopenharmony_ci				if (!io_node)
7488c2ecf20Sopenharmony_ci					return -ENOMEM;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci				io_node->base = (b_base & 0xF0) << 8;
7518c2ecf20Sopenharmony_ci				io_node->length = (b_length - b_base + 0x10) << 8;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci				io_node->next = func->io_head;
7548c2ecf20Sopenharmony_ci				func->io_head = io_node;
7558c2ecf20Sopenharmony_ci			}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci			/* Save memory base and Limit registers */
7588c2ecf20Sopenharmony_ci			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
7598c2ecf20Sopenharmony_ci			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci			if ((w_base <= w_length) && (save_command & 0x02)) {
7628c2ecf20Sopenharmony_ci				mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
7638c2ecf20Sopenharmony_ci				if (!mem_node)
7648c2ecf20Sopenharmony_ci					return -ENOMEM;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci				mem_node->base = w_base << 16;
7678c2ecf20Sopenharmony_ci				mem_node->length = (w_length - w_base + 0x10) << 16;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci				mem_node->next = func->mem_head;
7708c2ecf20Sopenharmony_ci				func->mem_head = mem_node;
7718c2ecf20Sopenharmony_ci			}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci			/* Save prefetchable memory base and Limit registers */
7748c2ecf20Sopenharmony_ci			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
7758c2ecf20Sopenharmony_ci			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci			if ((w_base <= w_length) && (save_command & 0x02)) {
7788c2ecf20Sopenharmony_ci				p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
7798c2ecf20Sopenharmony_ci				if (!p_mem_node)
7808c2ecf20Sopenharmony_ci					return -ENOMEM;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci				p_mem_node->base = w_base << 16;
7838c2ecf20Sopenharmony_ci				p_mem_node->length = (w_length - w_base + 0x10) << 16;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci				p_mem_node->next = func->p_mem_head;
7868c2ecf20Sopenharmony_ci				func->p_mem_head = p_mem_node;
7878c2ecf20Sopenharmony_ci			}
7888c2ecf20Sopenharmony_ci			/* Figure out IO and memory base lengths */
7898c2ecf20Sopenharmony_ci			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
7908c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci				temp_register = 0xFFFFFFFF;
7938c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
7948c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci				temp_register = base;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci				/* If this register is implemented */
7998c2ecf20Sopenharmony_ci				if (base) {
8008c2ecf20Sopenharmony_ci					if (((base & 0x03L) == 0x01)
8018c2ecf20Sopenharmony_ci					    && (save_command & 0x01)) {
8028c2ecf20Sopenharmony_ci						/* IO base
8038c2ecf20Sopenharmony_ci						 * set temp_register = amount
8048c2ecf20Sopenharmony_ci						 * of IO space requested
8058c2ecf20Sopenharmony_ci						 */
8068c2ecf20Sopenharmony_ci						temp_register = base & 0xFFFFFFFE;
8078c2ecf20Sopenharmony_ci						temp_register = (~temp_register) + 1;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci						io_node = kmalloc(sizeof(*io_node),
8108c2ecf20Sopenharmony_ci								GFP_KERNEL);
8118c2ecf20Sopenharmony_ci						if (!io_node)
8128c2ecf20Sopenharmony_ci							return -ENOMEM;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci						io_node->base =
8158c2ecf20Sopenharmony_ci						save_base & (~0x03L);
8168c2ecf20Sopenharmony_ci						io_node->length = temp_register;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci						io_node->next = func->io_head;
8198c2ecf20Sopenharmony_ci						func->io_head = io_node;
8208c2ecf20Sopenharmony_ci					} else
8218c2ecf20Sopenharmony_ci						if (((base & 0x0BL) == 0x08)
8228c2ecf20Sopenharmony_ci						    && (save_command & 0x02)) {
8238c2ecf20Sopenharmony_ci						/* prefetchable memory base */
8248c2ecf20Sopenharmony_ci						temp_register = base & 0xFFFFFFF0;
8258c2ecf20Sopenharmony_ci						temp_register = (~temp_register) + 1;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci						p_mem_node = kmalloc(sizeof(*p_mem_node),
8288c2ecf20Sopenharmony_ci								GFP_KERNEL);
8298c2ecf20Sopenharmony_ci						if (!p_mem_node)
8308c2ecf20Sopenharmony_ci							return -ENOMEM;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci						p_mem_node->base = save_base & (~0x0FL);
8338c2ecf20Sopenharmony_ci						p_mem_node->length = temp_register;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci						p_mem_node->next = func->p_mem_head;
8368c2ecf20Sopenharmony_ci						func->p_mem_head = p_mem_node;
8378c2ecf20Sopenharmony_ci					} else
8388c2ecf20Sopenharmony_ci						if (((base & 0x0BL) == 0x00)
8398c2ecf20Sopenharmony_ci						    && (save_command & 0x02)) {
8408c2ecf20Sopenharmony_ci						/* prefetchable memory base */
8418c2ecf20Sopenharmony_ci						temp_register = base & 0xFFFFFFF0;
8428c2ecf20Sopenharmony_ci						temp_register = (~temp_register) + 1;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci						mem_node = kmalloc(sizeof(*mem_node),
8458c2ecf20Sopenharmony_ci								GFP_KERNEL);
8468c2ecf20Sopenharmony_ci						if (!mem_node)
8478c2ecf20Sopenharmony_ci							return -ENOMEM;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci						mem_node->base = save_base & (~0x0FL);
8508c2ecf20Sopenharmony_ci						mem_node->length = temp_register;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci						mem_node->next = func->mem_head;
8538c2ecf20Sopenharmony_ci						func->mem_head = mem_node;
8548c2ecf20Sopenharmony_ci					} else
8558c2ecf20Sopenharmony_ci						return(1);
8568c2ecf20Sopenharmony_ci				}
8578c2ecf20Sopenharmony_ci			}	/* End of base register loop */
8588c2ecf20Sopenharmony_ci		/* Standard header */
8598c2ecf20Sopenharmony_ci		} else if ((header_type & 0x7F) == 0x00) {
8608c2ecf20Sopenharmony_ci			/* Figure out IO and memory base lengths */
8618c2ecf20Sopenharmony_ci			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
8628c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci				temp_register = 0xFFFFFFFF;
8658c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
8668c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci				temp_register = base;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci				/* If this register is implemented */
8718c2ecf20Sopenharmony_ci				if (base) {
8728c2ecf20Sopenharmony_ci					if (((base & 0x03L) == 0x01)
8738c2ecf20Sopenharmony_ci					    && (save_command & 0x01)) {
8748c2ecf20Sopenharmony_ci						/* IO base
8758c2ecf20Sopenharmony_ci						 * set temp_register = amount
8768c2ecf20Sopenharmony_ci						 * of IO space requested
8778c2ecf20Sopenharmony_ci						 */
8788c2ecf20Sopenharmony_ci						temp_register = base & 0xFFFFFFFE;
8798c2ecf20Sopenharmony_ci						temp_register = (~temp_register) + 1;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci						io_node = kmalloc(sizeof(*io_node),
8828c2ecf20Sopenharmony_ci								GFP_KERNEL);
8838c2ecf20Sopenharmony_ci						if (!io_node)
8848c2ecf20Sopenharmony_ci							return -ENOMEM;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci						io_node->base = save_base & (~0x01L);
8878c2ecf20Sopenharmony_ci						io_node->length = temp_register;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci						io_node->next = func->io_head;
8908c2ecf20Sopenharmony_ci						func->io_head = io_node;
8918c2ecf20Sopenharmony_ci					} else
8928c2ecf20Sopenharmony_ci						if (((base & 0x0BL) == 0x08)
8938c2ecf20Sopenharmony_ci						    && (save_command & 0x02)) {
8948c2ecf20Sopenharmony_ci						/* prefetchable memory base */
8958c2ecf20Sopenharmony_ci						temp_register = base & 0xFFFFFFF0;
8968c2ecf20Sopenharmony_ci						temp_register = (~temp_register) + 1;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci						p_mem_node = kmalloc(sizeof(*p_mem_node),
8998c2ecf20Sopenharmony_ci								GFP_KERNEL);
9008c2ecf20Sopenharmony_ci						if (!p_mem_node)
9018c2ecf20Sopenharmony_ci							return -ENOMEM;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci						p_mem_node->base = save_base & (~0x0FL);
9048c2ecf20Sopenharmony_ci						p_mem_node->length = temp_register;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci						p_mem_node->next = func->p_mem_head;
9078c2ecf20Sopenharmony_ci						func->p_mem_head = p_mem_node;
9088c2ecf20Sopenharmony_ci					} else
9098c2ecf20Sopenharmony_ci						if (((base & 0x0BL) == 0x00)
9108c2ecf20Sopenharmony_ci						    && (save_command & 0x02)) {
9118c2ecf20Sopenharmony_ci						/* prefetchable memory base */
9128c2ecf20Sopenharmony_ci						temp_register = base & 0xFFFFFFF0;
9138c2ecf20Sopenharmony_ci						temp_register = (~temp_register) + 1;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci						mem_node = kmalloc(sizeof(*mem_node),
9168c2ecf20Sopenharmony_ci								GFP_KERNEL);
9178c2ecf20Sopenharmony_ci						if (!mem_node)
9188c2ecf20Sopenharmony_ci							return -ENOMEM;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci						mem_node->base = save_base & (~0x0FL);
9218c2ecf20Sopenharmony_ci						mem_node->length = temp_register;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci						mem_node->next = func->mem_head;
9248c2ecf20Sopenharmony_ci						func->mem_head = mem_node;
9258c2ecf20Sopenharmony_ci					} else
9268c2ecf20Sopenharmony_ci						return(1);
9278c2ecf20Sopenharmony_ci				}
9288c2ecf20Sopenharmony_ci			}	/* End of base register loop */
9298c2ecf20Sopenharmony_ci		}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		/* find the next device in this slot */
9328c2ecf20Sopenharmony_ci		func = cpqhp_slot_find(func->bus, func->device, index++);
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	return 0;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci/*
9408c2ecf20Sopenharmony_ci * cpqhp_configure_board
9418c2ecf20Sopenharmony_ci *
9428c2ecf20Sopenharmony_ci * Copies saved configuration information to one slot.
9438c2ecf20Sopenharmony_ci * this is called recursively for bridge devices.
9448c2ecf20Sopenharmony_ci * this is for hot plug REPLACE!
9458c2ecf20Sopenharmony_ci *
9468c2ecf20Sopenharmony_ci * returns 0 if success
9478c2ecf20Sopenharmony_ci */
9488c2ecf20Sopenharmony_ciint cpqhp_configure_board(struct controller *ctrl, struct pci_func *func)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	int cloop;
9518c2ecf20Sopenharmony_ci	u8 header_type;
9528c2ecf20Sopenharmony_ci	u8 secondary_bus;
9538c2ecf20Sopenharmony_ci	int sub_bus;
9548c2ecf20Sopenharmony_ci	struct pci_func *next;
9558c2ecf20Sopenharmony_ci	u32 temp;
9568c2ecf20Sopenharmony_ci	u32 rc;
9578c2ecf20Sopenharmony_ci	int index = 0;
9588c2ecf20Sopenharmony_ci	struct pci_bus *pci_bus = ctrl->pci_bus;
9598c2ecf20Sopenharmony_ci	unsigned int devfn;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	func = cpqhp_slot_find(func->bus, func->device, index++);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	while (func != NULL) {
9648c2ecf20Sopenharmony_ci		pci_bus->number = func->bus;
9658c2ecf20Sopenharmony_ci		devfn = PCI_DEVFN(func->device, func->function);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		/* Start at the top of config space so that the control
9688c2ecf20Sopenharmony_ci		 * registers are programmed last
9698c2ecf20Sopenharmony_ci		 */
9708c2ecf20Sopenharmony_ci		for (cloop = 0x3C; cloop > 0; cloop -= 4)
9718c2ecf20Sopenharmony_ci			pci_bus_write_config_dword(pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci		/* If this is a bridge device, restore subordinate devices */
9768c2ecf20Sopenharmony_ci		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
9778c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci			sub_bus = (int) secondary_bus;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci			next = cpqhp_slot_list[sub_bus];
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci			while (next != NULL) {
9848c2ecf20Sopenharmony_ci				rc = cpqhp_configure_board(ctrl, next);
9858c2ecf20Sopenharmony_ci				if (rc)
9868c2ecf20Sopenharmony_ci					return rc;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci				next = next->next;
9898c2ecf20Sopenharmony_ci			}
9908c2ecf20Sopenharmony_ci		} else {
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci			/* Check all the base Address Registers to make sure
9938c2ecf20Sopenharmony_ci			 * they are the same.  If not, the board is different.
9948c2ecf20Sopenharmony_ci			 */
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci			for (cloop = 16; cloop < 40; cloop += 4) {
9978c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci				if (temp != func->config_space[cloop >> 2]) {
10008c2ecf20Sopenharmony_ci					dbg("Config space compare failure!!! offset = %x\n", cloop);
10018c2ecf20Sopenharmony_ci					dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function);
10028c2ecf20Sopenharmony_ci					dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]);
10038c2ecf20Sopenharmony_ci					return 1;
10048c2ecf20Sopenharmony_ci				}
10058c2ecf20Sopenharmony_ci			}
10068c2ecf20Sopenharmony_ci		}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci		func->configured = 1;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci		func = cpqhp_slot_find(func->bus, func->device, index++);
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	return 0;
10148c2ecf20Sopenharmony_ci}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci/*
10188c2ecf20Sopenharmony_ci * cpqhp_valid_replace
10198c2ecf20Sopenharmony_ci *
10208c2ecf20Sopenharmony_ci * this function checks to see if a board is the same as the
10218c2ecf20Sopenharmony_ci * one it is replacing.  this check will detect if the device's
10228c2ecf20Sopenharmony_ci * vendor or device id's are the same
10238c2ecf20Sopenharmony_ci *
10248c2ecf20Sopenharmony_ci * returns 0 if the board is the same nonzero otherwise
10258c2ecf20Sopenharmony_ci */
10268c2ecf20Sopenharmony_ciint cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	u8 cloop;
10298c2ecf20Sopenharmony_ci	u8 header_type;
10308c2ecf20Sopenharmony_ci	u8 secondary_bus;
10318c2ecf20Sopenharmony_ci	u8 type;
10328c2ecf20Sopenharmony_ci	u32 temp_register = 0;
10338c2ecf20Sopenharmony_ci	u32 base;
10348c2ecf20Sopenharmony_ci	u32 rc;
10358c2ecf20Sopenharmony_ci	struct pci_func *next;
10368c2ecf20Sopenharmony_ci	int index = 0;
10378c2ecf20Sopenharmony_ci	struct pci_bus *pci_bus = ctrl->pci_bus;
10388c2ecf20Sopenharmony_ci	unsigned int devfn;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	if (!func->is_a_board)
10418c2ecf20Sopenharmony_ci		return(ADD_NOT_SUPPORTED);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	func = cpqhp_slot_find(func->bus, func->device, index++);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	while (func != NULL) {
10468c2ecf20Sopenharmony_ci		pci_bus->number = func->bus;
10478c2ecf20Sopenharmony_ci		devfn = PCI_DEVFN(func->device, func->function);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(pci_bus, devfn, PCI_VENDOR_ID, &temp_register);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		/* No adapter present */
10528c2ecf20Sopenharmony_ci		if (temp_register == 0xFFFFFFFF)
10538c2ecf20Sopenharmony_ci			return(NO_ADAPTER_PRESENT);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci		if (temp_register != func->config_space[0])
10568c2ecf20Sopenharmony_ci			return(ADAPTER_NOT_SAME);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci		/* Check for same revision number and class code */
10598c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci		/* Adapter not the same */
10628c2ecf20Sopenharmony_ci		if (temp_register != func->config_space[0x08 >> 2])
10638c2ecf20Sopenharmony_ci			return(ADAPTER_NOT_SAME);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci		/* Check for Bridge */
10668c2ecf20Sopenharmony_ci		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
10698c2ecf20Sopenharmony_ci			/* In order to continue checking, we must program the
10708c2ecf20Sopenharmony_ci			 * bus registers in the bridge to respond to accesses
10718c2ecf20Sopenharmony_ci			 * for its subordinate bus(es)
10728c2ecf20Sopenharmony_ci			 */
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci			temp_register = func->config_space[0x18 >> 2];
10758c2ecf20Sopenharmony_ci			pci_bus_write_config_dword(pci_bus, devfn, PCI_PRIMARY_BUS, temp_register);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci			secondary_bus = (temp_register >> 8) & 0xFF;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci			next = cpqhp_slot_list[secondary_bus];
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci			while (next != NULL) {
10828c2ecf20Sopenharmony_ci				rc = cpqhp_valid_replace(ctrl, next);
10838c2ecf20Sopenharmony_ci				if (rc)
10848c2ecf20Sopenharmony_ci					return rc;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci				next = next->next;
10878c2ecf20Sopenharmony_ci			}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci		}
10908c2ecf20Sopenharmony_ci		/* Check to see if it is a standard config header */
10918c2ecf20Sopenharmony_ci		else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
10928c2ecf20Sopenharmony_ci			/* Check subsystem vendor and ID */
10938c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci			if (temp_register != func->config_space[0x2C >> 2]) {
10968c2ecf20Sopenharmony_ci				/* If it's a SMART-2 and the register isn't
10978c2ecf20Sopenharmony_ci				 * filled in, ignore the difference because
10988c2ecf20Sopenharmony_ci				 * they just have an old rev of the firmware
10998c2ecf20Sopenharmony_ci				 */
11008c2ecf20Sopenharmony_ci				if (!((func->config_space[0] == 0xAE100E11)
11018c2ecf20Sopenharmony_ci				      && (temp_register == 0x00L)))
11028c2ecf20Sopenharmony_ci					return(ADAPTER_NOT_SAME);
11038c2ecf20Sopenharmony_ci			}
11048c2ecf20Sopenharmony_ci			/* Figure out IO and memory base lengths */
11058c2ecf20Sopenharmony_ci			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
11068c2ecf20Sopenharmony_ci				temp_register = 0xFFFFFFFF;
11078c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
11088c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci				/* If this register is implemented */
11118c2ecf20Sopenharmony_ci				if (base) {
11128c2ecf20Sopenharmony_ci					if (base & 0x01L) {
11138c2ecf20Sopenharmony_ci						/* IO base
11148c2ecf20Sopenharmony_ci						 * set base = amount of IO
11158c2ecf20Sopenharmony_ci						 * space requested
11168c2ecf20Sopenharmony_ci						 */
11178c2ecf20Sopenharmony_ci						base = base & 0xFFFFFFFE;
11188c2ecf20Sopenharmony_ci						base = (~base) + 1;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci						type = 1;
11218c2ecf20Sopenharmony_ci					} else {
11228c2ecf20Sopenharmony_ci						/* memory base */
11238c2ecf20Sopenharmony_ci						base = base & 0xFFFFFFF0;
11248c2ecf20Sopenharmony_ci						base = (~base) + 1;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci						type = 0;
11278c2ecf20Sopenharmony_ci					}
11288c2ecf20Sopenharmony_ci				} else {
11298c2ecf20Sopenharmony_ci					base = 0x0L;
11308c2ecf20Sopenharmony_ci					type = 0;
11318c2ecf20Sopenharmony_ci				}
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci				/* Check information in slot structure */
11348c2ecf20Sopenharmony_ci				if (func->base_length[(cloop - 0x10) >> 2] != base)
11358c2ecf20Sopenharmony_ci					return(ADAPTER_NOT_SAME);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci				if (func->base_type[(cloop - 0x10) >> 2] != type)
11388c2ecf20Sopenharmony_ci					return(ADAPTER_NOT_SAME);
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci			}	/* End of base register loop */
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci		}		/* End of (type 0 config space) else */
11438c2ecf20Sopenharmony_ci		else {
11448c2ecf20Sopenharmony_ci			/* this is not a type 0 or 1 config space header so
11458c2ecf20Sopenharmony_ci			 * we don't know how to do it
11468c2ecf20Sopenharmony_ci			 */
11478c2ecf20Sopenharmony_ci			return(DEVICE_TYPE_NOT_SUPPORTED);
11488c2ecf20Sopenharmony_ci		}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci		/* Get the next function */
11518c2ecf20Sopenharmony_ci		func = cpqhp_slot_find(func->bus, func->device, index++);
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	return 0;
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci/*
11608c2ecf20Sopenharmony_ci * cpqhp_find_available_resources
11618c2ecf20Sopenharmony_ci *
11628c2ecf20Sopenharmony_ci * Finds available memory, IO, and IRQ resources for programming
11638c2ecf20Sopenharmony_ci * devices which may be added to the system
11648c2ecf20Sopenharmony_ci * this function is for hot plug ADD!
11658c2ecf20Sopenharmony_ci *
11668c2ecf20Sopenharmony_ci * returns 0 if success
11678c2ecf20Sopenharmony_ci */
11688c2ecf20Sopenharmony_ciint cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	u8 temp;
11718c2ecf20Sopenharmony_ci	u8 populated_slot;
11728c2ecf20Sopenharmony_ci	u8 bridged_slot;
11738c2ecf20Sopenharmony_ci	void __iomem *one_slot;
11748c2ecf20Sopenharmony_ci	void __iomem *rom_resource_table;
11758c2ecf20Sopenharmony_ci	struct pci_func *func = NULL;
11768c2ecf20Sopenharmony_ci	int i = 10, index;
11778c2ecf20Sopenharmony_ci	u32 temp_dword, rc;
11788c2ecf20Sopenharmony_ci	struct pci_resource *mem_node;
11798c2ecf20Sopenharmony_ci	struct pci_resource *p_mem_node;
11808c2ecf20Sopenharmony_ci	struct pci_resource *io_node;
11818c2ecf20Sopenharmony_ci	struct pci_resource *bus_node;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff);
11848c2ecf20Sopenharmony_ci	dbg("rom_resource_table = %p\n", rom_resource_table);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	if (rom_resource_table == NULL)
11878c2ecf20Sopenharmony_ci		return -ENODEV;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	/* Sum all resources and setup resource maps */
11908c2ecf20Sopenharmony_ci	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
11918c2ecf20Sopenharmony_ci	dbg("unused_IRQ = %x\n", unused_IRQ);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	temp = 0;
11948c2ecf20Sopenharmony_ci	while (unused_IRQ) {
11958c2ecf20Sopenharmony_ci		if (unused_IRQ & 1) {
11968c2ecf20Sopenharmony_ci			cpqhp_disk_irq = temp;
11978c2ecf20Sopenharmony_ci			break;
11988c2ecf20Sopenharmony_ci		}
11998c2ecf20Sopenharmony_ci		unused_IRQ = unused_IRQ >> 1;
12008c2ecf20Sopenharmony_ci		temp++;
12018c2ecf20Sopenharmony_ci	}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq);
12048c2ecf20Sopenharmony_ci	unused_IRQ = unused_IRQ >> 1;
12058c2ecf20Sopenharmony_ci	temp++;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	while (unused_IRQ) {
12088c2ecf20Sopenharmony_ci		if (unused_IRQ & 1) {
12098c2ecf20Sopenharmony_ci			cpqhp_nic_irq = temp;
12108c2ecf20Sopenharmony_ci			break;
12118c2ecf20Sopenharmony_ci		}
12128c2ecf20Sopenharmony_ci		unused_IRQ = unused_IRQ >> 1;
12138c2ecf20Sopenharmony_ci		temp++;
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq);
12178c2ecf20Sopenharmony_ci	unused_IRQ = readl(rom_resource_table + PCIIRQ);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	temp = 0;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (!cpqhp_nic_irq)
12228c2ecf20Sopenharmony_ci		cpqhp_nic_irq = ctrl->cfgspc_irq;
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	if (!cpqhp_disk_irq)
12258c2ecf20Sopenharmony_ci		cpqhp_disk_irq = ctrl->cfgspc_irq;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	rc = compaq_nvram_load(rom_start, ctrl);
12308c2ecf20Sopenharmony_ci	if (rc)
12318c2ecf20Sopenharmony_ci		return rc;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	one_slot = rom_resource_table + sizeof(struct hrt);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
12368c2ecf20Sopenharmony_ci	dbg("number_of_entries = %d\n", i);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	if (!readb(one_slot + SECONDARY_BUS))
12398c2ecf20Sopenharmony_ci		return 1;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n");
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	while (i && readb(one_slot + SECONDARY_BUS)) {
12448c2ecf20Sopenharmony_ci		u8 dev_func = readb(one_slot + DEV_FUNC);
12458c2ecf20Sopenharmony_ci		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
12468c2ecf20Sopenharmony_ci		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
12478c2ecf20Sopenharmony_ci		u8 max_bus = readb(one_slot + MAX_BUS);
12488c2ecf20Sopenharmony_ci		u16 io_base = readw(one_slot + IO_BASE);
12498c2ecf20Sopenharmony_ci		u16 io_length = readw(one_slot + IO_LENGTH);
12508c2ecf20Sopenharmony_ci		u16 mem_base = readw(one_slot + MEM_BASE);
12518c2ecf20Sopenharmony_ci		u16 mem_length = readw(one_slot + MEM_LENGTH);
12528c2ecf20Sopenharmony_ci		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
12538c2ecf20Sopenharmony_ci		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci		dbg("%2.2x | %4.4x  | %4.4x | %4.4x   | %4.4x | %4.4x   | %4.4x |%2.2x %2.2x %2.2x\n",
12568c2ecf20Sopenharmony_ci		    dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
12578c2ecf20Sopenharmony_ci		    primary_bus, secondary_bus, max_bus);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci		/* If this entry isn't for our controller's bus, ignore it */
12608c2ecf20Sopenharmony_ci		if (primary_bus != ctrl->bus) {
12618c2ecf20Sopenharmony_ci			i--;
12628c2ecf20Sopenharmony_ci			one_slot += sizeof(struct slot_rt);
12638c2ecf20Sopenharmony_ci			continue;
12648c2ecf20Sopenharmony_ci		}
12658c2ecf20Sopenharmony_ci		/* find out if this entry is for an occupied slot */
12668c2ecf20Sopenharmony_ci		ctrl->pci_bus->number = primary_bus;
12678c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
12688c2ecf20Sopenharmony_ci		dbg("temp_D_word = %x\n", temp_dword);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		if (temp_dword != 0xFFFFFFFF) {
12718c2ecf20Sopenharmony_ci			index = 0;
12728c2ecf20Sopenharmony_ci			func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci			while (func && (func->function != (dev_func & 0x07))) {
12758c2ecf20Sopenharmony_ci				dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index);
12768c2ecf20Sopenharmony_ci				func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++);
12778c2ecf20Sopenharmony_ci			}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci			/* If we can't find a match, skip this table entry */
12808c2ecf20Sopenharmony_ci			if (!func) {
12818c2ecf20Sopenharmony_ci				i--;
12828c2ecf20Sopenharmony_ci				one_slot += sizeof(struct slot_rt);
12838c2ecf20Sopenharmony_ci				continue;
12848c2ecf20Sopenharmony_ci			}
12858c2ecf20Sopenharmony_ci			/* this may not work and shouldn't be used */
12868c2ecf20Sopenharmony_ci			if (secondary_bus != primary_bus)
12878c2ecf20Sopenharmony_ci				bridged_slot = 1;
12888c2ecf20Sopenharmony_ci			else
12898c2ecf20Sopenharmony_ci				bridged_slot = 0;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci			populated_slot = 1;
12928c2ecf20Sopenharmony_ci		} else {
12938c2ecf20Sopenharmony_ci			populated_slot = 0;
12948c2ecf20Sopenharmony_ci			bridged_slot = 0;
12958c2ecf20Sopenharmony_ci		}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci		/* If we've got a valid IO base, use it */
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci		temp_dword = io_base + io_length;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci		if ((io_base) && (temp_dword < 0x10000)) {
13038c2ecf20Sopenharmony_ci			io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
13048c2ecf20Sopenharmony_ci			if (!io_node)
13058c2ecf20Sopenharmony_ci				return -ENOMEM;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci			io_node->base = io_base;
13088c2ecf20Sopenharmony_ci			io_node->length = io_length;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci			dbg("found io_node(base, length) = %x, %x\n",
13118c2ecf20Sopenharmony_ci					io_node->base, io_node->length);
13128c2ecf20Sopenharmony_ci			dbg("populated slot =%d \n", populated_slot);
13138c2ecf20Sopenharmony_ci			if (!populated_slot) {
13148c2ecf20Sopenharmony_ci				io_node->next = ctrl->io_head;
13158c2ecf20Sopenharmony_ci				ctrl->io_head = io_node;
13168c2ecf20Sopenharmony_ci			} else {
13178c2ecf20Sopenharmony_ci				io_node->next = func->io_head;
13188c2ecf20Sopenharmony_ci				func->io_head = io_node;
13198c2ecf20Sopenharmony_ci			}
13208c2ecf20Sopenharmony_ci		}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		/* If we've got a valid memory base, use it */
13238c2ecf20Sopenharmony_ci		temp_dword = mem_base + mem_length;
13248c2ecf20Sopenharmony_ci		if ((mem_base) && (temp_dword < 0x10000)) {
13258c2ecf20Sopenharmony_ci			mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
13268c2ecf20Sopenharmony_ci			if (!mem_node)
13278c2ecf20Sopenharmony_ci				return -ENOMEM;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci			mem_node->base = mem_base << 16;
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci			mem_node->length = mem_length << 16;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci			dbg("found mem_node(base, length) = %x, %x\n",
13348c2ecf20Sopenharmony_ci					mem_node->base, mem_node->length);
13358c2ecf20Sopenharmony_ci			dbg("populated slot =%d \n", populated_slot);
13368c2ecf20Sopenharmony_ci			if (!populated_slot) {
13378c2ecf20Sopenharmony_ci				mem_node->next = ctrl->mem_head;
13388c2ecf20Sopenharmony_ci				ctrl->mem_head = mem_node;
13398c2ecf20Sopenharmony_ci			} else {
13408c2ecf20Sopenharmony_ci				mem_node->next = func->mem_head;
13418c2ecf20Sopenharmony_ci				func->mem_head = mem_node;
13428c2ecf20Sopenharmony_ci			}
13438c2ecf20Sopenharmony_ci		}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci		/* If we've got a valid prefetchable memory base, and
13468c2ecf20Sopenharmony_ci		 * the base + length isn't greater than 0xFFFF
13478c2ecf20Sopenharmony_ci		 */
13488c2ecf20Sopenharmony_ci		temp_dword = pre_mem_base + pre_mem_length;
13498c2ecf20Sopenharmony_ci		if ((pre_mem_base) && (temp_dword < 0x10000)) {
13508c2ecf20Sopenharmony_ci			p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
13518c2ecf20Sopenharmony_ci			if (!p_mem_node)
13528c2ecf20Sopenharmony_ci				return -ENOMEM;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci			p_mem_node->base = pre_mem_base << 16;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci			p_mem_node->length = pre_mem_length << 16;
13578c2ecf20Sopenharmony_ci			dbg("found p_mem_node(base, length) = %x, %x\n",
13588c2ecf20Sopenharmony_ci					p_mem_node->base, p_mem_node->length);
13598c2ecf20Sopenharmony_ci			dbg("populated slot =%d \n", populated_slot);
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci			if (!populated_slot) {
13628c2ecf20Sopenharmony_ci				p_mem_node->next = ctrl->p_mem_head;
13638c2ecf20Sopenharmony_ci				ctrl->p_mem_head = p_mem_node;
13648c2ecf20Sopenharmony_ci			} else {
13658c2ecf20Sopenharmony_ci				p_mem_node->next = func->p_mem_head;
13668c2ecf20Sopenharmony_ci				func->p_mem_head = p_mem_node;
13678c2ecf20Sopenharmony_ci			}
13688c2ecf20Sopenharmony_ci		}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		/* If we've got a valid bus number, use it
13718c2ecf20Sopenharmony_ci		 * The second condition is to ignore bus numbers on
13728c2ecf20Sopenharmony_ci		 * populated slots that don't have PCI-PCI bridges
13738c2ecf20Sopenharmony_ci		 */
13748c2ecf20Sopenharmony_ci		if (secondary_bus && (secondary_bus != primary_bus)) {
13758c2ecf20Sopenharmony_ci			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
13768c2ecf20Sopenharmony_ci			if (!bus_node)
13778c2ecf20Sopenharmony_ci				return -ENOMEM;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci			bus_node->base = secondary_bus;
13808c2ecf20Sopenharmony_ci			bus_node->length = max_bus - secondary_bus + 1;
13818c2ecf20Sopenharmony_ci			dbg("found bus_node(base, length) = %x, %x\n",
13828c2ecf20Sopenharmony_ci					bus_node->base, bus_node->length);
13838c2ecf20Sopenharmony_ci			dbg("populated slot =%d \n", populated_slot);
13848c2ecf20Sopenharmony_ci			if (!populated_slot) {
13858c2ecf20Sopenharmony_ci				bus_node->next = ctrl->bus_head;
13868c2ecf20Sopenharmony_ci				ctrl->bus_head = bus_node;
13878c2ecf20Sopenharmony_ci			} else {
13888c2ecf20Sopenharmony_ci				bus_node->next = func->bus_head;
13898c2ecf20Sopenharmony_ci				func->bus_head = bus_node;
13908c2ecf20Sopenharmony_ci			}
13918c2ecf20Sopenharmony_ci		}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci		i--;
13948c2ecf20Sopenharmony_ci		one_slot += sizeof(struct slot_rt);
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	/* If all of the following fail, we don't have any resources for
13988c2ecf20Sopenharmony_ci	 * hot plug add
13998c2ecf20Sopenharmony_ci	 */
14008c2ecf20Sopenharmony_ci	rc = 1;
14018c2ecf20Sopenharmony_ci	rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
14028c2ecf20Sopenharmony_ci	rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
14038c2ecf20Sopenharmony_ci	rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
14048c2ecf20Sopenharmony_ci	rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	return rc;
14078c2ecf20Sopenharmony_ci}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci/*
14118c2ecf20Sopenharmony_ci * cpqhp_return_board_resources
14128c2ecf20Sopenharmony_ci *
14138c2ecf20Sopenharmony_ci * this routine returns all resources allocated to a board to
14148c2ecf20Sopenharmony_ci * the available pool.
14158c2ecf20Sopenharmony_ci *
14168c2ecf20Sopenharmony_ci * returns 0 if success
14178c2ecf20Sopenharmony_ci */
14188c2ecf20Sopenharmony_ciint cpqhp_return_board_resources(struct pci_func *func, struct resource_lists *resources)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	int rc = 0;
14218c2ecf20Sopenharmony_ci	struct pci_resource *node;
14228c2ecf20Sopenharmony_ci	struct pci_resource *t_node;
14238c2ecf20Sopenharmony_ci	dbg("%s\n", __func__);
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	if (!func)
14268c2ecf20Sopenharmony_ci		return 1;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	node = func->io_head;
14298c2ecf20Sopenharmony_ci	func->io_head = NULL;
14308c2ecf20Sopenharmony_ci	while (node) {
14318c2ecf20Sopenharmony_ci		t_node = node->next;
14328c2ecf20Sopenharmony_ci		return_resource(&(resources->io_head), node);
14338c2ecf20Sopenharmony_ci		node = t_node;
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	node = func->mem_head;
14378c2ecf20Sopenharmony_ci	func->mem_head = NULL;
14388c2ecf20Sopenharmony_ci	while (node) {
14398c2ecf20Sopenharmony_ci		t_node = node->next;
14408c2ecf20Sopenharmony_ci		return_resource(&(resources->mem_head), node);
14418c2ecf20Sopenharmony_ci		node = t_node;
14428c2ecf20Sopenharmony_ci	}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	node = func->p_mem_head;
14458c2ecf20Sopenharmony_ci	func->p_mem_head = NULL;
14468c2ecf20Sopenharmony_ci	while (node) {
14478c2ecf20Sopenharmony_ci		t_node = node->next;
14488c2ecf20Sopenharmony_ci		return_resource(&(resources->p_mem_head), node);
14498c2ecf20Sopenharmony_ci		node = t_node;
14508c2ecf20Sopenharmony_ci	}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	node = func->bus_head;
14538c2ecf20Sopenharmony_ci	func->bus_head = NULL;
14548c2ecf20Sopenharmony_ci	while (node) {
14558c2ecf20Sopenharmony_ci		t_node = node->next;
14568c2ecf20Sopenharmony_ci		return_resource(&(resources->bus_head), node);
14578c2ecf20Sopenharmony_ci		node = t_node;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head));
14618c2ecf20Sopenharmony_ci	rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head));
14628c2ecf20Sopenharmony_ci	rc |= cpqhp_resource_sort_and_combine(&(resources->io_head));
14638c2ecf20Sopenharmony_ci	rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head));
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	return rc;
14668c2ecf20Sopenharmony_ci}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci/*
14708c2ecf20Sopenharmony_ci * cpqhp_destroy_resource_list
14718c2ecf20Sopenharmony_ci *
14728c2ecf20Sopenharmony_ci * Puts node back in the resource list pointed to by head
14738c2ecf20Sopenharmony_ci */
14748c2ecf20Sopenharmony_civoid cpqhp_destroy_resource_list(struct resource_lists *resources)
14758c2ecf20Sopenharmony_ci{
14768c2ecf20Sopenharmony_ci	struct pci_resource *res, *tres;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	res = resources->io_head;
14798c2ecf20Sopenharmony_ci	resources->io_head = NULL;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	while (res) {
14828c2ecf20Sopenharmony_ci		tres = res;
14838c2ecf20Sopenharmony_ci		res = res->next;
14848c2ecf20Sopenharmony_ci		kfree(tres);
14858c2ecf20Sopenharmony_ci	}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	res = resources->mem_head;
14888c2ecf20Sopenharmony_ci	resources->mem_head = NULL;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	while (res) {
14918c2ecf20Sopenharmony_ci		tres = res;
14928c2ecf20Sopenharmony_ci		res = res->next;
14938c2ecf20Sopenharmony_ci		kfree(tres);
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	res = resources->p_mem_head;
14978c2ecf20Sopenharmony_ci	resources->p_mem_head = NULL;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	while (res) {
15008c2ecf20Sopenharmony_ci		tres = res;
15018c2ecf20Sopenharmony_ci		res = res->next;
15028c2ecf20Sopenharmony_ci		kfree(tres);
15038c2ecf20Sopenharmony_ci	}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	res = resources->bus_head;
15068c2ecf20Sopenharmony_ci	resources->bus_head = NULL;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	while (res) {
15098c2ecf20Sopenharmony_ci		tres = res;
15108c2ecf20Sopenharmony_ci		res = res->next;
15118c2ecf20Sopenharmony_ci		kfree(tres);
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci/*
15178c2ecf20Sopenharmony_ci * cpqhp_destroy_board_resources
15188c2ecf20Sopenharmony_ci *
15198c2ecf20Sopenharmony_ci * Puts node back in the resource list pointed to by head
15208c2ecf20Sopenharmony_ci */
15218c2ecf20Sopenharmony_civoid cpqhp_destroy_board_resources(struct pci_func *func)
15228c2ecf20Sopenharmony_ci{
15238c2ecf20Sopenharmony_ci	struct pci_resource *res, *tres;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	res = func->io_head;
15268c2ecf20Sopenharmony_ci	func->io_head = NULL;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	while (res) {
15298c2ecf20Sopenharmony_ci		tres = res;
15308c2ecf20Sopenharmony_ci		res = res->next;
15318c2ecf20Sopenharmony_ci		kfree(tres);
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	res = func->mem_head;
15358c2ecf20Sopenharmony_ci	func->mem_head = NULL;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	while (res) {
15388c2ecf20Sopenharmony_ci		tres = res;
15398c2ecf20Sopenharmony_ci		res = res->next;
15408c2ecf20Sopenharmony_ci		kfree(tres);
15418c2ecf20Sopenharmony_ci	}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	res = func->p_mem_head;
15448c2ecf20Sopenharmony_ci	func->p_mem_head = NULL;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	while (res) {
15478c2ecf20Sopenharmony_ci		tres = res;
15488c2ecf20Sopenharmony_ci		res = res->next;
15498c2ecf20Sopenharmony_ci		kfree(tres);
15508c2ecf20Sopenharmony_ci	}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	res = func->bus_head;
15538c2ecf20Sopenharmony_ci	func->bus_head = NULL;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	while (res) {
15568c2ecf20Sopenharmony_ci		tres = res;
15578c2ecf20Sopenharmony_ci		res = res->next;
15588c2ecf20Sopenharmony_ci		kfree(tres);
15598c2ecf20Sopenharmony_ci	}
15608c2ecf20Sopenharmony_ci}
1561