cpqphp_pci.c revision 7a54f25cef6c763f16c9fd49ae382de162147873
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#include "../../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependent we are... */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 cpqhp_nic_irq;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu8 cpqhp_disk_irq;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 unused_IRQ;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * detect_HRT_floating_pointer
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * find the Hot Plug Resource Table in the specified region of memory.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end)
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *fp;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *endp;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp1, temp2, temp3, temp4;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status = 0;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	endp = (end - sizeof(struct hrt) + 1);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (fp = begin; fp <= endp; fp += 16) {
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp1 = readb(fp + SIG0);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp2 = readb(fp + SIG1);
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp3 = readb(fp + SIG2);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp4 = readb(fp + SIG3);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp1 == '$' &&
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    temp2 == 'H' &&
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    temp3 == 'R' &&
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    temp4 == 'T') {
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			status = 1;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!status)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fp = NULL;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("Discovered Hotplug Resource Table at %p\n", fp);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fp;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char bus;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *child;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int num;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (func->pci_dev == NULL)
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* No pci device, we need to create it then */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (func->pci_dev == NULL) {
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("INFO: pci_dev still null\n");
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function));
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (num)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_add_devices(ctrl->pci_dev->bus);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (func->pci_dev == NULL) {
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("ERROR: pci_dev still null\n");
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_do_scan_bus(child);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_unconfigure_device(struct pci_func* func)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int j;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j=0; j<8 ; j++) {
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pci_dev* temp = pci_find_slot(func->bus, PCI_DEVFN(func->device, j));
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_remove_bus_device(temp);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 vendID = 0;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vendID == 0xffffffff)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pci_bus_read_config_dword (bus, devfn, offset, value);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_set_irq
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bus_num: bus number of PCI device
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev_num: device number of PCI device
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slot: pointer to u8 where slot number will be returned
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpqhp_legacy_mode) {
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pci_dev *fakedev;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pci_bus *fakebus;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 temp_word;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakedev = kmalloc(sizeof(*fakedev), GFP_KERNEL);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakebus = kmalloc(sizeof(*fakebus), GFP_KERNEL);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!fakedev || !fakebus) {
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(fakedev);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(fakebus);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakedev->devfn = dev_num << 3;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakedev->bus = fakebus;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fakebus->number = bus_num;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s: dev %d, bus %d, pin %d, num %d\n",
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = pcibios_set_irq_routing(fakedev, int_pin - 0x0a, irq_num);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(fakedev);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(fakebus);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%s: rc %d\n", __FUNCTION__, rc);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!rc)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return !rc;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// set the Edge Level Control Register (ELCR)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_word = inb(0x4d0);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_word |= inb(0x4d1) << 8;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_word |= 0x01 << irq_num;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// This should only be for x86 as it sets the Edge Level Control Register
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb((u8) (temp_word & 0xFF), 0x4d0);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = 0;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WTF??? This function isn't in the code, yet a function calls it, but the
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * compiler optimizes it away?  strange.  Here as a placeholder to keep the
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * compiler happy.
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int PCI_ScanBusNonBridge (u8 bus, u8 device)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 tdevice;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 work;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tbus;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = bus_num;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//Scan for access first
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//Yep we got one. Not a bridge ?
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*dev_num = tdevice;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found it !\n");
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//Scan for access first
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//Yep we got one. bridge ?
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (PCI_ScanBusNonBridge(tbus, tdevice) == 0)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irq_routing_table *PCIIRQRoutingInfoLength;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long len;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long loop;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 work;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tbus, tdevice, tslot;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table();
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!PCIIRQRoutingInfoLength)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (PCIIRQRoutingInfoLength->size -
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Make sure I got at least one entry
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len == 0) {
2626044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl		kfree(PCIIRQRoutingInfoLength );
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (loop = 0; loop < len; ++loop) {
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tbus = PCIIRQRoutingInfoLength->slots[loop].bus;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tslot = PCIIRQRoutingInfoLength->slots[loop].slot;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tslot == slot) {
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*bus_num = tbus;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*dev_num = tdevice;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ctrl->pci_bus->number = tbus;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!nobridge || (work == 0xffffffff)) {
2776044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl				kfree(PCIIRQRoutingInfoLength );
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("bus_num %d devfn %d\n", *bus_num, *dev_num);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dbg("Scan bus for Non Bridge: bus %d\n", tbus);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) {
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					*bus_num = tbus;
2906044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl					kfree(PCIIRQRoutingInfoLength );
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 0;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2946044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl				kfree(PCIIRQRoutingInfoLength );
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3006044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl	kfree(PCIIRQRoutingInfoLength );
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot)
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0);	//plain (bridges allowed)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* More PCI configuration routines; this time centered around hotplug controller */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_config
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reads configuration for all slots in a PCI bus and saves info.
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note:  For non-hot plug busses, the slot # saved is the device #
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long rc;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 class_code;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ID;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *new_slot;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int FirstSupported;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int LastSupported;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_functions;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int function;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 DevError;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int device = 0;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop = 0;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int stop_it;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	//              Decide which slots are supported
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (is_hot_plug) {
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//*********************************
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// is_hot_plug is the slot mask
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//*********************************
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FirstSupported = is_hot_plug >> 4;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FirstSupported = 0;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LastSupported = 0x1F;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	//     Save PCI configuration space for all devices in supported slots
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = busnumber;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (device = FirstSupported; device <= LastSupported; device++) {
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ID = 0xFFFFFFFF;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ID != 0xFFFFFFFF) {	  //  device in slot
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return rc;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc)
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return rc;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// If multi-function device, set max_functions to 8
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (header_type & 0x80)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				max_functions = 8;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				max_functions = 1;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			function = 0;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do {
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DevError = 0;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   // P-P Bridge
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					//  Recurse the subordinate bus
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					//  get the subordinate bus number
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (rc) {
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return rc;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						sub_bus = (int) secondary_bus;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// Save secondary bus cfg spc
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// with this recursive call.
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rc = cpqhp_save_config(ctrl, sub_bus, 0);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (rc)
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return rc;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ctrl->pci_bus->number = busnumber;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				index = 0;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot = cpqhp_slot_find(busnumber, device, index++);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				while (new_slot &&
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       (new_slot->function != (u8) function))
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					new_slot = cpqhp_slot_find(busnumber, device, index++);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!new_slot) {
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// Setup slot structure.
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					new_slot = cpqhp_slot_create(busnumber);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (new_slot == NULL)
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->bus = (u8) busnumber;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->device = (u8) device;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->function = (u8) function;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->is_a_board = 1;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->switch_save = 0x10;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// In case of unsupported board
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->status = DevError;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (cloop = 0; cloop < 0x20; cloop++) {
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (rc)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return rc;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				function++;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				stop_it = 0;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				//  this loop skips to the next present function
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				//  reading in Class Code and Header type.
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				while ((function < max_functions)&&(!stop_it)) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (ID == 0xFFFFFFFF) {	 // nothing there.
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						function++;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {  // Something there
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (rc)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return rc;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (rc)
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return rc;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						stop_it++;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} while (function < max_functions);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}		// End of IF (device in slot?)
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (is_hot_plug) {
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Setup slot structure with entry for empty slot
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot = cpqhp_slot_create(busnumber);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (new_slot == NULL) {
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return(1);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->bus = (u8) busnumber;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->device = (u8) device;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->function = 0;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->is_a_board = 0;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->presence_save = 0;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->switch_save = 0;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			// End of FOR loop
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_slot_config
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Saves configuration info for all PCI devices in a given slot
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including subordinate busses.
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long rc;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 class_code;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ID;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_functions;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int function;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop = 0;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int stop_it;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ID = 0xFFFFFFFF;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = new_slot->bus;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ID != 0xFFFFFFFF) {	  //  device in slot
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (header_type & 0x80)	// Multi-function device
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			max_functions = 8;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			max_functions = 1;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		function = 0;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				//  Recurse the subordinate bus
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sub_bus = (int) secondary_bus;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// Save the config headers for the secondary bus.
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_save_config(ctrl, sub_bus, 0);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(rc);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->pci_bus->number = new_slot->bus;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}	// End of IF
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->status = 0;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0; cloop < 0x20; cloop++) {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			function++;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			stop_it = 0;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			//  this loop skips to the next present function
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			//  reading in the Class Code and the Header type.
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while ((function < max_functions) && (!stop_it)) {
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ID == 0xFFFFFFFF) {	 // nothing there.
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					function++;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {  // Something there
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					stop_it++;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} while (function < max_functions);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			// End of IF (device in slot?)
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 2;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_base_addr_length
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Saves the length of all base address registers for the
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specified slot.  this is for hot plug REPLACE
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func)
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Check for Bridge
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// PCI-PCI Bridge
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sub_bus = (int) secondary_bus;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[sub_bus];
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_save_base_addr_length(ctrl, next);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus->number = func->bus;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			//FIXME: this loop is duplicated in the non-bridge case.  The two could be rolled together
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Figure out IO and memory base lengths
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (base) {  // If this register is implemented
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// IO base
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// set base = amount of IO space requested
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// memory base
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// Save information in slot structure
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_length[(cloop - 0x10) >> 2] =
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				base;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_type[(cloop - 0x10) >> 2] = type;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}	// End of base register loop
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if ((header_type & 0x7F) == 0x00) {	  // PCI-PCI Bridge
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Figure out IO and memory base lengths
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (base) {  // If this register is implemented
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// IO base
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// base = amount of IO space requested
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// memory base
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// base = amount of memory space requested
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// Save information in slot structure
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_length[(cloop - 0x10) >> 2] = base;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_type[(cloop - 0x10) >> 2] = type;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}	// End of base register loop
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {	  // Some other unknown header type
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// find the next device in this slot
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_used_resources
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stores used resource information for existing boards.  this is
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for boards that were in the system when this driver was loaded.
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function is for hot plug ADD
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func)
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_byte;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b_base;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b_length;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 command;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 save_command;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 w_base;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 w_length;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 save_base;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *mem_node;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *p_mem_node;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *io_node;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *bus_node;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((func != NULL) && func->is_a_board) {
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Save the command register
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// disable card
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		command = 0x00;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Check for Bridge
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Clear Bridge Control Register
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			command = 0x00;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bus_node)
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->base = secondary_bus;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->length = temp_byte - secondary_bus + 1;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->next = func->bus_head;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func->bus_head = bus_node;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Save IO base and Limit registers
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((b_base <= b_length) && (save_command & 0x01)) {
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!io_node)
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->base = (b_base & 0xF0) << 8;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->length = (b_length - b_base + 0x10) << 8;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = func->io_head;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->io_head = io_node;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Save memory base and Limit registers
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((w_base <= w_length) && (save_command & 0x02)) {
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!mem_node)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->base = w_base << 16;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->length = (w_length - w_base + 0x10) << 16;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = func->mem_head;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->mem_head = mem_node;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Save prefetchable memory base and Limit registers
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((w_base <= w_length) && (save_command & 0x02)) {
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!p_mem_node)
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->base = w_base << 16;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->length = (w_length - w_base + 0x10) << 16;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = func->p_mem_head;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->p_mem_head = p_mem_node;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Figure out IO and memory base lengths
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = base;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (base) {  // If this register is implemented
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (((base & 0x03L) == 0x01)
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    && (save_command & 0x01)) {
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// IO base
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// set temp_register = amount of IO space requested
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFFE;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node = kmalloc(sizeof(*io_node),
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!io_node)
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->base =
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						save_base & (~0x03L);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->length = temp_register;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->next = func->io_head;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->io_head = io_node;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x08)
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// prefetchable memory base
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node = kmalloc(sizeof(*p_mem_node),
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!p_mem_node)
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->base = save_base & (~0x0FL);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->length = temp_register;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->next = func->p_mem_head;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->p_mem_head = p_mem_node;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x00)
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// prefetchable memory base
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node = kmalloc(sizeof(*mem_node),
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!mem_node)
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->base = save_base & (~0x0FL);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->length = temp_register;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->next = func->mem_head;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->mem_head = mem_node;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}	// End of base register loop
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if ((header_type & 0x7F) == 0x00) {	  // Standard header
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Figure out IO and memory base lengths
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = base;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (base) {	  // If this register is implemented
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (((base & 0x03L) == 0x01)
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    && (save_command & 0x01)) {
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// IO base
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// set temp_register = amount of IO space requested
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFFE;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node = kmalloc(sizeof(*io_node),
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!io_node)
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->base = save_base & (~0x01L);
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->length = temp_register;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->next = func->io_head;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->io_head = io_node;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x08)
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// prefetchable memory base
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node = kmalloc(sizeof(*p_mem_node),
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!p_mem_node)
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->base = save_base & (~0x0FL);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->length = temp_register;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->next = func->p_mem_head;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->p_mem_head = p_mem_node;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x00)
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// prefetchable memory base
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node = kmalloc(sizeof(*mem_node),
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!mem_node)
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->base = save_base & (~0x0FL);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->length = temp_register;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->next = func->mem_head;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->mem_head = mem_node;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}	// End of base register loop
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {	  // Some other unknown header type
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// find the next device in this slot
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_configure_board
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copies saved configuration information to one slot.
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is called recursively for bridge devices.
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is for hot plug REPLACE!
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_configure_board(struct controller *ctrl, struct pci_func * func)
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Start at the top of config space so that the control
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// registers are programmed last
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (cloop = 0x3C; cloop > 0; cloop -= 4) {
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// If this is a bridge device, restore subordinate devices
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sub_bus = (int) secondary_bus;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[sub_bus];
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_configure_board(ctrl, next);
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Check all the base Address Registers to make sure
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// they are the same.  If not, the board is different.
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 16; cloop < 40; cloop += 4) {
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (temp != func->config_space[cloop >> 2]) {
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("Config space compare failure!!! offset = %x\n", cloop);
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 1;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func->configured = 1;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_valid_replace
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function checks to see if a board is the same as the
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one it is replacing.  this check will detect if the device's
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vendor or device id's are the same
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if the board is the same nonzero otherwise
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func)
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register = 0;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!func->is_a_board)
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(ADD_NOT_SUPPORTED);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register);
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// No adapter present
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register == 0xFFFFFFFF)
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(NO_ADAPTER_PRESENT);
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register != func->config_space[0])
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(ADAPTER_NOT_SAME);
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Check for same revision number and class code
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Adapter not the same
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register != func->config_space[0x08 >> 2])
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(ADAPTER_NOT_SAME);
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Check for Bridge
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// In order to continue checking, we must program the
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// bus registers in the bridge to respond to accesses
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// for it's subordinate bus(es)
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			temp_register = func->config_space[0x18 >> 2];
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register);
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			secondary_bus = (temp_register >> 8) & 0xFF;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[secondary_bus];
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_valid_replace(ctrl, next);
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Check to see if it is a standard config header
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Check subsystem vendor and ID
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (temp_register != func->config_space[0x2C >> 2]) {
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// If it's a SMART-2 and the register isn't filled
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// in, ignore the difference because
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// they just have an old rev of the firmware
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!((func->config_space[0] == 0xAE100E11)
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      && (temp_register == 0x00L)))
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// Figure out IO and memory base lengths
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (base) {	  // If this register is implemented
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// IO base
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// set base = amount of IO space requested
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						// memory base
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// Check information in slot structure
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (func->base_length[(cloop - 0x10) >> 2] != base)
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (func->base_type[(cloop - 0x10) >> 2] != type)
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}	// End of base register loop
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}		// End of (type 0 config space) else
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// this is not a type 0 or 1 config space header so
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// we don't know how to do it
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(DEVICE_TYPE_NOT_SUPPORTED);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Get the next function
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_find_available_resources
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finds available memory, IO, and IRQ resources for programming
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * devices which may be added to the system
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function is for hot plug ADD!
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start)
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 populated_slot;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 bridged_slot;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *one_slot;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *rom_resource_table;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *func = NULL;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 10, index;
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_dword, rc;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *mem_node;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *p_mem_node;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *io_node;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *bus_node;
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("rom_resource_table = %p\n", rom_resource_table);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rom_resource_table == NULL) {
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Sum all resources and setup resource maps
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("unused_IRQ = %x\n", unused_IRQ);
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = 0;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (unused_IRQ) {
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unused_IRQ & 1) {
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpqhp_disk_irq = temp;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unused_IRQ = unused_IRQ >> 1;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp++;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = unused_IRQ >> 1;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp++;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (unused_IRQ) {
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unused_IRQ & 1) {
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpqhp_nic_irq = temp;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unused_IRQ = unused_IRQ >> 1;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp++;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq);
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = readl(rom_resource_table + PCIIRQ);
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = 0;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cpqhp_nic_irq) {
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpqhp_nic_irq = ctrl->cfgspc_irq;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cpqhp_disk_irq) {
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpqhp_disk_irq = ctrl->cfgspc_irq;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = compaq_nvram_load(rom_start, ctrl);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	one_slot = rom_resource_table + sizeof (struct hrt);
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("number_of_entries = %d\n", i);
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!readb(one_slot + SECONDARY_BUS))
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n");
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i && readb(one_slot + SECONDARY_BUS)) {
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 dev_func = readb(one_slot + DEV_FUNC);
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 max_bus = readb(one_slot + MAX_BUS);
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 io_base = readw(one_slot + IO_BASE);
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 io_length = readw(one_slot + IO_LENGTH);
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 mem_base = readw(one_slot + MEM_BASE);
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 mem_length = readw(one_slot + MEM_LENGTH);
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%2.2x | %4.4x  | %4.4x | %4.4x   | %4.4x | %4.4x   | %4.4x |%2.2x %2.2x %2.2x\n",
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    primary_bus, secondary_bus, max_bus);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// If this entry isn't for our controller's bus, ignore it
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (primary_bus != ctrl->bus) {
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i--;
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			one_slot += sizeof (struct slot_rt);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// find out if this entry is for an occupied slot
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl->pci_bus->number = primary_bus;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("temp_D_word = %x\n", temp_dword);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_dword != 0xFFFFFFFF) {
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			index = 0;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (func && (func->function != (dev_func & 0x07))) {
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index);
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++);
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// If we can't find a match, skip this table entry
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!func) {
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				i--;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				one_slot += sizeof (struct slot_rt);
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			// this may not work and shouldn't be used
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (secondary_bus != primary_bus)
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bridged_slot = 1;
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bridged_slot = 0;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			populated_slot = 1;
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			populated_slot = 0;
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bridged_slot = 0;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// If we've got a valid IO base, use it
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = io_base + io_length;
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((io_base) && (temp_dword < 0x10000)) {
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!io_node)
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node->base = io_base;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node->length = io_length;
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found io_node(base, length) = %x, %x\n",
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					io_node->base, io_node->length);
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = ctrl->io_head;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->io_head = io_node;
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = func->io_head;
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->io_head = io_node;
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// If we've got a valid memory base, use it
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = mem_base + mem_length;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((mem_base) && (temp_dword < 0x10000)) {
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!mem_node)
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node->base = mem_base << 16;
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node->length = mem_length << 16;
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found mem_node(base, length) = %x, %x\n",
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mem_node->base, mem_node->length);
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = ctrl->mem_head;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->mem_head = mem_node;
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = func->mem_head;
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->mem_head = mem_node;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// If we've got a valid prefetchable memory base, and
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// the base + length isn't greater than 0xFFFF
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = pre_mem_base + pre_mem_length;
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((pre_mem_base) && (temp_dword < 0x10000)) {
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!p_mem_node)
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node->base = pre_mem_base << 16;
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node->length = pre_mem_length << 16;
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found p_mem_node(base, length) = %x, %x\n",
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					p_mem_node->base, p_mem_node->length);
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = ctrl->p_mem_head;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->p_mem_head = p_mem_node;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = func->p_mem_head;
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->p_mem_head = p_mem_node;
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// If we've got a valid bus number, use it
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// The second condition is to ignore bus numbers on
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// populated slots that don't have PCI-PCI bridges
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (secondary_bus && (secondary_bus != primary_bus)) {
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bus_node)
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->base = secondary_bus;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->length = max_bus - secondary_bus + 1;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found bus_node(base, length) = %x, %x\n",
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bus_node->base, bus_node->length);
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bus_node->next = ctrl->bus_head;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->bus_head = bus_node;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bus_node->next = func->bus_head;
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->bus_head = bus_node;
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i--;
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		one_slot += sizeof (struct slot_rt);
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// If all of the following fail, we don't have any resources for
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// hot plug add
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 1;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_return_board_resources
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine returns all resources allocated to a board to
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the available pool.
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *node;
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *t_node;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("%s\n", __FUNCTION__);
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!func)
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->io_head;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->io_head = NULL;
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->io_head), node);
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->mem_head;
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->mem_head = NULL;
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->mem_head), node);
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->p_mem_head;
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->p_mem_head = NULL;
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->p_mem_head), node);
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->bus_head;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->bus_head = NULL;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->bus_head), node);
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head));
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head));
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->io_head));
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head));
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_destroy_resource_list
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts node back in the resource list pointed to by head
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cpqhp_destroy_resource_list (struct resource_lists * resources)
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *res, *tres;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->io_head;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->io_head = NULL;
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->mem_head;
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->mem_head = NULL;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->p_mem_head;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->p_mem_head = NULL;
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->bus_head;
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->bus_head = NULL;
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_destroy_board_resources
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts node back in the resource list pointed to by head
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cpqhp_destroy_board_resources (struct pci_func * func)
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *res, *tres;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->io_head;
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->io_head = NULL;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->mem_head;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->mem_head = NULL;
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->p_mem_head;
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->p_mem_head = NULL;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->bus_head;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->bus_head = NULL;
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1565