11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compaq Hot Plug Controller Driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1995,2001 Compaq Computer Corporation
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001 IBM Corp.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NON INFRINGEMENT.  See the GNU General Public License for more
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * details.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send feedback to <greg@kroah.com>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
367a54f25cef6c763f16c9fd49ae382de162147873Greg Kroah-Hartman#include <linux/pci_hotplug.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../pci.h"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cpqphp.h"
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cpqphp_nvram.h"
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 cpqhp_nic_irq;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 cpqhp_disk_irq;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 unused_IRQ;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * detect_HRT_floating_pointer
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * find the Hot Plug Resource Table in the specified region of memory.
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *fp;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *endp;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp1, temp2, temp3, temp4;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status = 0;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	endp = (end - sizeof(struct hrt) + 1);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (fp = begin; fp <= endp; fp += 16) {
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp1 = readb(fp + SIG0);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp2 = readb(fp + SIG1);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp3 = readb(fp + SIG2);
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp4 = readb(fp + SIG3);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp1 == '$' &&
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    temp2 == 'H' &&
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    temp3 == 'R' &&
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    temp4 == 'T') {
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			status = 1;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!status)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fp = NULL;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("Discovered Hotplug Resource Table at %p\n", fp);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fp;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
84861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiangint cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char bus;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *child;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int num;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (func->pci_dev == NULL)
9112a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang		func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function));
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* No pci device, we need to create it then */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (func->pci_dev == NULL) {
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("INFO: pci_dev still null\n");
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function));
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (num)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_add_devices(ctrl->pci_dev->bus);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10112a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang		func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function));
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (func->pci_dev == NULL) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("ERROR: pci_dev still null\n");
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_do_scan_bus(child);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11412a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang	pci_dev_put(func->pci_dev);
11512a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
120861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiangint cpqhp_unconfigure_device(struct pci_func* func)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int j;
123861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiang
12466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison	dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j=0; j<8 ; j++) {
12712a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang		struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
12812a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang		if (temp) {
12912a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang			pci_dev_put(temp);
130210647af897af8ef2d00828aa2a6b1b42206aae6Yinghai Lu			pci_stop_and_remove_bus_device(temp);
13112a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang		}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 vendID = 0;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vendID == 0xffffffff)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pci_bus_read_config_dword (bus, devfn, offset, value);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_set_irq
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bus_num: bus number of PCI device
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev_num: device number of PCI device
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slot: pointer to u8 where slot number will be returned
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpqhp_legacy_mode) {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pci_dev *fakedev;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pci_bus *fakebus;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 temp_word;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakedev = kmalloc(sizeof(*fakedev), GFP_KERNEL);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakebus = kmalloc(sizeof(*fakebus), GFP_KERNEL);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!fakedev || !fakebus) {
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(fakedev);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(fakebus);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakedev->devfn = dev_num << 3;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakedev->bus = fakebus;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakebus->number = bus_num;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s: dev %d, bus %d, pin %d, num %d\n",
17666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		    __func__, dev_num, bus_num, int_pin, irq_num);
17798d3333a13029ab07ca1d1bfb9bfa138ea76c3c0Bjorn Helgaas		rc = pcibios_set_irq_routing(fakedev, int_pin - 1, irq_num);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(fakedev);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(fakebus);
18066bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: rc %d\n", __func__, rc);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!rc)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return !rc;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
184427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* set the Edge Level Control Register (ELCR) */
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_word = inb(0x4d0);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_word |= inb(0x4d1) << 8;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_word |= 0x01 << irq_num;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
190427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* This should only be for x86 as it sets the Edge Level
191427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * Control Register
192427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
193427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word &
194427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		0xFF00) >> 8), 0x4d1); rc = 0; }
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 tdevice;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 work;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tbus;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = bus_num;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
209427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Scan for access first */
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);
213427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Yep we got one. Not a bridge ? */
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) {
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*dev_num = tdevice;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found it !\n");
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
221427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Scan for access first */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);
225427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Yep we got one. bridge ? */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus);
228e3265ea364c7ed5accc9955f8b805c380149870fAlex Chiang			/* XXX: no recursion, wtf? */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);
230e3265ea364c7ed5accc9955f8b805c380149870fAlex Chiang			return 0;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
240b019ee679afde950f2d01b1af0530453aa60af3fAlex Chiang	int loop, len;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 work;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tbus, tdevice, tslot;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
244b019ee679afde950f2d01b1af0530453aa60af3fAlex Chiang	len = cpqhp_routing_table_length();
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (loop = 0; loop < len; ++loop) {
246b019ee679afde950f2d01b1af0530453aa60af3fAlex Chiang		tbus = cpqhp_routing_table->slots[loop].bus;
247b019ee679afde950f2d01b1af0530453aa60af3fAlex Chiang		tdevice = cpqhp_routing_table->slots[loop].devfn;
248b019ee679afde950f2d01b1af0530453aa60af3fAlex Chiang		tslot = cpqhp_routing_table->slots[loop].slot;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tslot == slot) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*bus_num = tbus;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*dev_num = tdevice;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctrl->pci_bus->number = tbus;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work);
255b019ee679afde950f2d01b1af0530453aa60af3fAlex Chiang			if (!nobridge || (work == 0xffffffff))
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("bus_num %d devfn %d\n", *bus_num, *dev_num);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dbg("Scan bus for Non Bridge: bus %d\n", tbus);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) {
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					*bus_num = tbus;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 0;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
269b019ee679afde950f2d01b1af0530453aa60af3fAlex Chiang			} else
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
279427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* plain (bridges allowed) */
280427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
284427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang/* More PCI configuration routines; this time centered around hotplug
285427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang * controller
286427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang */
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_config
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reads configuration for all slots in a PCI bus and saves info.
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note:  For non-hot plug busses, the slot # saved is the device #
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long rc;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 class_code;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ID;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *new_slot;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int FirstSupported;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int LastSupported;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_functions;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int function;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 DevError;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int device = 0;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop = 0;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int stop_it;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
317427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* Decide which slots are supported */
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (is_hot_plug) {
320427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/*
321427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * is_hot_plug is the slot mask
322427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FirstSupported = is_hot_plug >> 4;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FirstSupported = 0;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LastSupported = 0x1F;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
330427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* Save PCI configuration space for all devices in supported slots */
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = busnumber;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (device = FirstSupported; device <= LastSupported; device++) {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ID = 0xFFFFFFFF;
3341d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		if (ID == 0xFFFFFFFF) {
3371d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			if (is_hot_plug) {
3381d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				/* Setup slot structure with entry for empty
3391d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				 * slot
3401d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				 */
3411d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				new_slot = cpqhp_slot_create(busnumber);
3421d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				if (new_slot == NULL)
3431d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					return 1;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->bus = (u8) busnumber;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->device = (u8) device;
3471d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				new_slot->function = 0;
3481d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				new_slot->is_a_board = 0;
3491d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				new_slot->presence_save = 0;
3501d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				new_slot->switch_save = 0;
3511d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			}
3521d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			continue;
3531d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		}
3541d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
3551d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
3561d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		if (rc)
3571d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			return rc;
3581d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
3591d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
3601d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		if (rc)
3611d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			return rc;
3621d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
3631d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		/* If multi-function device, set max_functions to 8 */
3641d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		if (header_type & 0x80)
3651d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			max_functions = 8;
3661d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		else
3671d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			max_functions = 1;
3681d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
3691d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		function = 0;
3701d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
3711d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		do {
3721d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			DevError = 0;
3731d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
3741d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				/* Recurse the subordinate bus
3751d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				 * get the subordinate bus number
3761d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				 */
3771d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
3781d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				if (rc) {
3791d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					return rc;
3801d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				} else {
3811d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					sub_bus = (int) secondary_bus;
3821d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
3831d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					/* Save secondary bus cfg spc
3841d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					 * with this recursive call.
3851d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					 */
3861d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					rc = cpqhp_save_config(ctrl, sub_bus, 0);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (rc)
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return rc;
3891d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					ctrl->pci_bus->number = busnumber;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3911d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			}
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			index = 0;
3941d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			new_slot = cpqhp_slot_find(busnumber, device, index++);
3951d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			while (new_slot &&
3961d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			       (new_slot->function != (u8) function))
3971d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				new_slot = cpqhp_slot_find(busnumber, device, index++);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			if (!new_slot) {
4001d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				/* Setup slot structure. */
4011d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				new_slot = cpqhp_slot_create(busnumber);
4021d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				if (new_slot == NULL)
4031d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					return 1;
4041d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			new_slot->bus = (u8) busnumber;
4071d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			new_slot->device = (u8) device;
4081d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			new_slot->function = (u8) function;
4091d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			new_slot->is_a_board = 1;
4101d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			new_slot->switch_save = 0x10;
4111d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			/* In case of unsupported board */
4121d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			new_slot->status = DevError;
41312a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang			new_slot->pci_dev = pci_get_bus_and_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
4141d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
4151d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			for (cloop = 0; cloop < 0x20; cloop++) {
4161d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
4171d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				if (rc)
4181d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					return rc;
4191d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			}
4201d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
42112a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang			pci_dev_put(new_slot->pci_dev);
42212a9da0fcb147b46de33bb919b1de2bb92c9e2a9Alex Chiang
4231d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			function++;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			stop_it = 0;
4261d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang
4271d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			/* this loop skips to the next present function
4281d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			 * reading in Class Code and Header type.
4291d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			 */
4301d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang			while ((function < max_functions) && (!stop_it)) {
4311d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
4321d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				if (ID == 0xFFFFFFFF) {
4331d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					function++;
4341d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					continue;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4361d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
4371d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				if (rc)
4381d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					return rc;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
4411d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				if (rc)
4421d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang					return rc;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang				stop_it++;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang		} while (function < max_functions);
448427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	}			/* End of FOR loop */
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501d2e8b1c58ef96b8834b139caf4357effedcb5abAlex Chiang	return 0;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_slot_config
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Saves configuration info for all PCI devices in a given slot
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including subordinate busses.
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long rc;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 class_code;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ID;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_functions;
471de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	int function = 0;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop = 0;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int stop_it;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ID = 0xFFFFFFFF;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = new_slot->bus;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
480de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	if (ID == 0xFFFFFFFF)
481de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		return 2;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
483de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
484de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
486de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	if (header_type & 0x80)	/* Multi-function device */
487de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		max_functions = 8;
488de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	else
489de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		max_functions = 1;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	while (function < max_functions) {
492de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
493de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			/*  Recurse the subordinate bus */
494de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
496de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			sub_bus = (int) secondary_bus;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
498de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			/* Save the config headers for the secondary
499de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			 * bus.
500de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			 */
501de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			rc = cpqhp_save_config(ctrl, sub_bus, 0);
502de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			if (rc)
503de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				return(rc);
504de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			ctrl->pci_bus->number = new_slot->bus;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
506de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
508de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		new_slot->status = 0;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
510de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		for (cloop = 0; cloop < 0x20; cloop++)
511de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
513de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		function++;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
515de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		stop_it = 0;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
517de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		/* this loop skips to the next present function
518de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		 * reading in the Class Code and the Header type.
519de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		 */
520de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		while ((function < max_functions) && (!stop_it)) {
521de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
523de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			if (ID == 0xFFFFFFFF)
524de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				function++;
525de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			else {
526de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
527de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
528de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				stop_it++;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
530de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		}
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_base_addr_length
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Saves the length of all base address registers for the
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specified slot.  this is for hot plug REPLACE
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
567427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check for Bridge */
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sub_bus = (int) secondary_bus;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[sub_bus];
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_save_base_addr_length(ctrl, next);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus->number = func->bus;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
586427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* FIXME: this loop is duplicated in the non-bridge
587427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * case.  The two could be rolled together Figure out
588427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * IO and memory base lengths
589427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
594427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
595427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
597427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
598427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set base = amount of IO space
599427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * requested
600427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
606427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* memory base */
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
617427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* Save information in slot structure */
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_length[(cloop - 0x10) >> 2] =
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				base;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_type[(cloop - 0x10) >> 2] = type;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
622427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
624427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		} else if ((header_type & 0x7F) == 0x00) {
625427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
632427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
634427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
635427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * base = amount of IO space
636427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * requested
637427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
643427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* memory base
644427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * base = amount of memory
645427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * space requested
646427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
657427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* Save information in slot structure */
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_length[(cloop - 0x10) >> 2] = base;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_type[(cloop - 0x10) >> 2] = type;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
663427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		} else {	  /* Some other unknown header type */
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
666427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* find the next device in this slot */
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_used_resources
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stores used resource information for existing boards.  this is
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for boards that were in the system when this driver was loaded.
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function is for hot plug ADD
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func)
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_byte;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b_base;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b_length;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 command;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 save_command;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 w_base;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 w_length;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 save_base;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *mem_node;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *p_mem_node;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *io_node;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *bus_node;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((func != NULL) && func->is_a_board) {
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
712427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Save the command register */
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
715427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* disable card */
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		command = 0x00;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
719427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check for Bridge */
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
722427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
723427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Clear Bridge Control Register */
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			command = 0x00;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bus_node)
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->base = secondary_bus;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->length = temp_byte - secondary_bus + 1;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->next = func->bus_head;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func->bus_head = bus_node;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
739427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Save IO base and Limit registers */
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((b_base <= b_length) && (save_command & 0x01)) {
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!io_node)
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->base = (b_base & 0xF0) << 8;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->length = (b_length - b_base + 0x10) << 8;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = func->io_head;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->io_head = io_node;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
755427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Save memory base and Limit registers */
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((w_base <= w_length) && (save_command & 0x02)) {
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!mem_node)
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->base = w_base << 16;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->length = (w_length - w_base + 0x10) << 16;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = func->mem_head;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->mem_head = mem_node;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Save prefetchable memory base and Limit registers */
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((w_base <= w_length) && (save_command & 0x02)) {
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!p_mem_node)
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->base = w_base << 16;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->length = (w_length - w_base + 0x10) << 16;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = func->p_mem_head;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->p_mem_head = p_mem_node;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
786427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = base;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
796427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
797427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (((base & 0x03L) == 0x01)
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    && (save_command & 0x01)) {
800427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
801427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set temp_register = amount
802427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * of IO space requested
803427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFFE;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node = kmalloc(sizeof(*io_node),
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!io_node)
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->base =
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						save_base & (~0x03L);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->length = temp_register;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->next = func->io_head;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->io_head = io_node;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x08)
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
821427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node = kmalloc(sizeof(*p_mem_node),
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!p_mem_node)
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->base = save_base & (~0x0FL);
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->length = temp_register;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->next = func->p_mem_head;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->p_mem_head = p_mem_node;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x00)
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
838427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node = kmalloc(sizeof(*mem_node),
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!mem_node)
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->base = save_base & (~0x0FL);
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->length = temp_register;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->next = func->mem_head;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->mem_head = mem_node;
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
855427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
856427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Standard header */
857427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		} else if ((header_type & 0x7F) == 0x00) {
858427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = base;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
868427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
869427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (((base & 0x03L) == 0x01)
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    && (save_command & 0x01)) {
872427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
873427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set temp_register = amount
874427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * of IO space requested
875427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFFE;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node = kmalloc(sizeof(*io_node),
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!io_node)
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->base = save_base & (~0x01L);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->length = temp_register;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->next = func->io_head;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->io_head = io_node;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x08)
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
892427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node = kmalloc(sizeof(*p_mem_node),
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!p_mem_node)
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->base = save_base & (~0x0FL);
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->length = temp_register;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->next = func->p_mem_head;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->p_mem_head = p_mem_node;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x00)
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
909427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node = kmalloc(sizeof(*mem_node),
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!mem_node)
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->base = save_base & (~0x0FL);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->length = temp_register;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->next = func->mem_head;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->mem_head = mem_node;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
926427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
929427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* find the next device in this slot */
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9334aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	return 0;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_configure_board
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copies saved configuration information to one slot.
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is called recursively for bridge devices.
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is for hot plug REPLACE!
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_configure_board(struct controller *ctrl, struct pci_func * func)
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
965427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Start at the top of config space so that the control
966427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * registers are programmed last
967427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
9684aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang		for (cloop = 0x3C; cloop > 0; cloop -= 4)
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
973427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If this is a bridge device, restore subordinate devices */
974427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sub_bus = (int) secondary_bus;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[sub_bus];
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_configure_board(ctrl, next);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
990427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Check all the base Address Registers to make sure
991427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * they are the same.  If not, the board is different.
992427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 16; cloop < 40; cloop += 4) {
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp);
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (temp != func->config_space[cloop >> 2]) {
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("Config space compare failure!!! offset = %x\n", cloop);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function);
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]);
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 1;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func->configured = 1;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_valid_replace
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function checks to see if a board is the same as the
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one it is replacing.  this check will detect if the device's
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vendor or device id's are the same
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if the board is the same nonzero otherwise
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func)
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register = 0;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!func->is_a_board)
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(ADD_NOT_SUPPORTED);
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register);
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1049427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* No adapter present */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register == 0xFFFFFFFF)
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(NO_ADAPTER_PRESENT);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register != func->config_space[0])
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(ADAPTER_NOT_SAME);
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1056427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check for same revision number and class code */
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1059427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Adapter not the same */
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register != func->config_space[0x08 >> 2])
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(ADAPTER_NOT_SAME);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1063427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check for Bridge */
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1066427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
1067427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* In order to continue checking, we must program the
1068427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * bus registers in the bridge to respond to accesses
1069427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * for its subordinate bus(es)
1070427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			temp_register = func->config_space[0x18 >> 2];
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register);
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			secondary_bus = (temp_register >> 8) & 0xFF;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[secondary_bus];
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_valid_replace(ctrl, next);
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1088427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check to see if it is a standard config header */
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
1090427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Check subsystem vendor and ID */
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (temp_register != func->config_space[0x2C >> 2]) {
1094427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If it's a SMART-2 and the register isn't
1095427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 * filled in, ignore the difference because
1096427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 * they just have an old rev of the firmware
1097427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 */
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!((func->config_space[0] == 0xAE100E11)
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      && (temp_register == 0x00L)))
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1102427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
1107427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang
1108427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
1109427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
1111427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
1112427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set base = amount of IO
1113427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * space requested
1114427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
1120427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* memory base */
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* Check information in slot structure */
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (func->base_length[(cloop - 0x10) >> 2] != base)
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (func->base_type[(cloop - 0x10) >> 2] != type)
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1138427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1140427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		}		/* End of (type 0 config space) else */
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
1142427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* this is not a type 0 or 1 config space header so
1143427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * we don't know how to do it
1144427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(DEVICE_TYPE_NOT_SUPPORTED);
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1148427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Get the next function */
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_find_available_resources
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finds available memory, IO, and IRQ resources for programming
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * devices which may be added to the system
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function is for hot plug ADD!
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
1165861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiang */
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start)
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 populated_slot;
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 bridged_slot;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *one_slot;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *rom_resource_table;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *func = NULL;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 10, index;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_dword, rc;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *mem_node;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *p_mem_node;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *io_node;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *bus_node;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff);
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("rom_resource_table = %p\n", rom_resource_table);
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11844aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	if (rom_resource_table == NULL)
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
11864aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang
1187427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* Sum all resources and setup resource maps */
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("unused_IRQ = %x\n", unused_IRQ);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = 0;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (unused_IRQ) {
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unused_IRQ & 1) {
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpqhp_disk_irq = temp;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unused_IRQ = unused_IRQ >> 1;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp++;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq);
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = unused_IRQ >> 1;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp++;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (unused_IRQ) {
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unused_IRQ & 1) {
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpqhp_nic_irq = temp;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unused_IRQ = unused_IRQ >> 1;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp++;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq);
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = readl(rom_resource_table + PCIIRQ);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = 0;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12194aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	if (!cpqhp_nic_irq)
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpqhp_nic_irq = ctrl->cfgspc_irq;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12224aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	if (!cpqhp_disk_irq)
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpqhp_disk_irq = ctrl->cfgspc_irq;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = compaq_nvram_load(rom_start, ctrl);
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	one_slot = rom_resource_table + sizeof (struct hrt);
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("number_of_entries = %d\n", i);
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!readb(one_slot + SECONDARY_BUS))
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n");
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i && readb(one_slot + SECONDARY_BUS)) {
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 dev_func = readb(one_slot + DEV_FUNC);
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 max_bus = readb(one_slot + MAX_BUS);
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 io_base = readw(one_slot + IO_BASE);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 io_length = readw(one_slot + IO_LENGTH);
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 mem_base = readw(one_slot + MEM_BASE);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 mem_length = readw(one_slot + MEM_LENGTH);
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%2.2x | %4.4x  | %4.4x | %4.4x   | %4.4x | %4.4x   | %4.4x |%2.2x %2.2x %2.2x\n",
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    primary_bus, secondary_bus, max_bus);
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1257427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If this entry isn't for our controller's bus, ignore it */
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (primary_bus != ctrl->bus) {
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i--;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			one_slot += sizeof (struct slot_rt);
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1263427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* find out if this entry is for an occupied slot */
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl->pci_bus->number = primary_bus;
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("temp_D_word = %x\n", temp_dword);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_dword != 0xFFFFFFFF) {
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			index = 0;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (func && (func->function != (dev_func & 0x07))) {
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1277427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* If we can't find a match, skip this table entry */
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!func) {
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				i--;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				one_slot += sizeof (struct slot_rt);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1283427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* this may not work and shouldn't be used */
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (secondary_bus != primary_bus)
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bridged_slot = 1;
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bridged_slot = 0;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			populated_slot = 1;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			populated_slot = 0;
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bridged_slot = 0;
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1296427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid IO base, use it */
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = io_base + io_length;
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((io_base) && (temp_dword < 0x10000)) {
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!io_node)
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node->base = io_base;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node->length = io_length;
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found io_node(base, length) = %x, %x\n",
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					io_node->base, io_node->length);
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = ctrl->io_head;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->io_head = io_node;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = func->io_head;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->io_head = io_node;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1320427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid memory base, use it */
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = mem_base + mem_length;
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((mem_base) && (temp_dword < 0x10000)) {
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!mem_node)
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node->base = mem_base << 16;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node->length = mem_length << 16;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found mem_node(base, length) = %x, %x\n",
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mem_node->base, mem_node->length);
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = ctrl->mem_head;
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->mem_head = mem_node;
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = func->mem_head;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->mem_head = mem_node;
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1343427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid prefetchable memory base, and
1344427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * the base + length isn't greater than 0xFFFF
1345427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = pre_mem_base + pre_mem_length;
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((pre_mem_base) && (temp_dword < 0x10000)) {
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!p_mem_node)
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node->base = pre_mem_base << 16;
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node->length = pre_mem_length << 16;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found p_mem_node(base, length) = %x, %x\n",
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					p_mem_node->base, p_mem_node->length);
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = ctrl->p_mem_head;
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->p_mem_head = p_mem_node;
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = func->p_mem_head;
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->p_mem_head = p_mem_node;
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1368427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid bus number, use it
1369427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * The second condition is to ignore bus numbers on
1370427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * populated slots that don't have PCI-PCI bridges
1371427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (secondary_bus && (secondary_bus != primary_bus)) {
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bus_node)
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->base = secondary_bus;
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->length = max_bus - secondary_bus + 1;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found bus_node(base, length) = %x, %x\n",
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bus_node->base, bus_node->length);
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bus_node->next = ctrl->bus_head;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->bus_head = bus_node;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bus_node->next = func->bus_head;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->bus_head = bus_node;
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i--;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		one_slot += sizeof (struct slot_rt);
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1395427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* If all of the following fail, we don't have any resources for
1396427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	 * hot plug add
1397427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	 */
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 1;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_return_board_resources
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine returns all resources allocated to a board to
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the available pool.
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *node;
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *t_node;
142166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison	dbg("%s\n", __func__);
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!func)
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->io_head;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->io_head = NULL;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->io_head), node);
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->mem_head;
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->mem_head = NULL;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->mem_head), node);
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->p_mem_head;
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->p_mem_head = NULL;
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->p_mem_head), node);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->bus_head;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->bus_head = NULL;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->bus_head), node);
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head));
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head));
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->io_head));
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head));
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_destroy_resource_list
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts node back in the resource list pointed to by head
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cpqhp_destroy_resource_list (struct resource_lists * resources)
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *res, *tres;
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->io_head;
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->io_head = NULL;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->mem_head;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->mem_head = NULL;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->p_mem_head;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->p_mem_head = NULL;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->bus_head;
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->bus_head = NULL;
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_destroy_board_resources
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts node back in the resource list pointed to by head
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cpqhp_destroy_board_resources (struct pci_func * func)
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *res, *tres;
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->io_head;
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->io_head = NULL;
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->mem_head;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->mem_head = NULL;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->p_mem_head;
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->p_mem_head = NULL;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->bus_head;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->bus_head = NULL;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1560