cpqphp_pci.c revision 4aabb58e1f544e97dbb97d0ce29bdfc9108f2f2c
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"
40824877111cd7f2b4fd2fe6947c5c5cbbb3ac5bd8Jaswinder Singh Rajput#include <asm/pci_x86.h>
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
85861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiangint 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
119861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiangint cpqhp_unconfigure_device(struct pci_func* func)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int j;
122861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiang
12366bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison	dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, 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",
17366bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		    __func__, dev_num, bus_num, int_pin, irq_num);
17498d3333a13029ab07ca1d1bfb9bfa138ea76c3c0Bjorn Helgaas		rc = pcibios_set_irq_routing(fakedev, int_pin - 1, irq_num);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(fakedev);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(fakebus);
17766bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		dbg("%s: rc %d\n", __func__, rc);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!rc)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return !rc;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* 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
187427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* This should only be for x86 as it sets the Edge Level
188427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * Control Register
189427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
190427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word &
191427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		0xFF00) >> 8), 0x4d1); rc = 0; }
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
198861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiang * WTF??? This function isn't in the code, yet a function calls it, but the
199861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiang * 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++) {
216427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* 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);
220427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* 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++) {
228427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* 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);
232427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* 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);
260427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* 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{
307427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* plain (bridges allowed) */
308427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
312427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang/* More PCI configuration routines; this time centered around hotplug
313427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang * controller
314427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_config
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reads configuration for all slots in a PCI bus and saves info.
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note:  For non-hot plug busses, the slot # saved is the device #
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long rc;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 class_code;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ID;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *new_slot;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int FirstSupported;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int LastSupported;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_functions;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int function;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 DevError;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int device = 0;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop = 0;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int stop_it;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
345427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* Decide which slots are supported */
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (is_hot_plug) {
348427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/*
349427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * is_hot_plug is the slot mask
350427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FirstSupported = is_hot_plug >> 4;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		FirstSupported = 0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LastSupported = 0x1F;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
358427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* Save PCI configuration space for all devices in supported slots */
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = busnumber;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (device = FirstSupported; device <= LastSupported; device++) {
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ID = 0xFFFFFFFF;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
364427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		if (ID != 0xFFFFFFFF) {	  /* device in slot */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc)
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return rc;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return rc;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
373427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* If multi-function device, set max_functions to 8 */
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (header_type & 0x80)
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				max_functions = 8;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				max_functions = 1;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			function = 0;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DevError = 0;
383427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
384427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang					/* Recurse the subordinate bus
385427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang					 * get the subordinate bus number
386427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang					 */
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (rc) {
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return rc;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						sub_bus = (int) secondary_bus;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
393427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* Save secondary bus cfg spc
394427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * with this recursive call.
395427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rc = cpqhp_save_config(ctrl, sub_bus, 0);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (rc)
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return rc;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						ctrl->pci_bus->number = busnumber;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				index = 0;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot = cpqhp_slot_find(busnumber, device, index++);
405861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiang				while (new_slot &&
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       (new_slot->function != (u8) function))
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					new_slot = cpqhp_slot_find(busnumber, device, index++);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!new_slot) {
410427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang					/* Setup slot structure. */
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					new_slot = cpqhp_slot_create(busnumber);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (new_slot == NULL)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->bus = (u8) busnumber;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->device = (u8) device;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->function = (u8) function;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->is_a_board = 1;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->switch_save = 0x10;
422427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* In case of unsupported board */
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->status = DevError;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (cloop = 0; cloop < 0x20; cloop++) {
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (rc)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return rc;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				function++;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				stop_it = 0;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
436427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* this loop skips to the next present function
437427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 * reading in Class Code and Header type.
438427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 */
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				while ((function < max_functions)&&(!stop_it)) {
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
442427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang					if (ID == 0xFFFFFFFF) {	 /* nothing there. */
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						function++;
444427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang					} else {  /* Something there */
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (rc)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return rc;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (rc)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return rc;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						stop_it++;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} while (function < max_functions);
458427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		}		/* End of IF (device in slot?) */
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (is_hot_plug) {
460427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Setup slot structure with entry for empty slot */
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot = cpqhp_slot_create(busnumber);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (new_slot == NULL) {
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return(1);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->bus = (u8) busnumber;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->device = (u8) device;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->function = 0;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->is_a_board = 0;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->presence_save = 0;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_slot->switch_save = 0;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
474427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	}			/* End of FOR loop */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_slot_config
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Saves configuration info for all PCI devices in a given slot
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including subordinate busses.
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long rc;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 class_code;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 ID;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_functions;
497de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	int function = 0;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop = 0;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int stop_it;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ID = 0xFFFFFFFF;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ctrl->pci_bus->number = new_slot->bus;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
506de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	if (ID == 0xFFFFFFFF)
507de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		return 2;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
509de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
510de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
512de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	if (header_type & 0x80)	/* Multi-function device */
513de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		max_functions = 8;
514de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	else
515de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		max_functions = 1;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
517de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang	while (function < max_functions) {
518de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
519de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			/*  Recurse the subordinate bus */
520de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
522de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			sub_bus = (int) secondary_bus;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
524de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			/* Save the config headers for the secondary
525de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			 * bus.
526de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			 */
527de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			rc = cpqhp_save_config(ctrl, sub_bus, 0);
528de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			if (rc)
529de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				return(rc);
530de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			ctrl->pci_bus->number = new_slot->bus;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
532de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
534de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		new_slot->status = 0;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
536de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		for (cloop = 0; cloop < 0x20; cloop++)
537de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
539de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		function++;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		stop_it = 0;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
543de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		/* this loop skips to the next present function
544de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		 * reading in the Class Code and the Header type.
545de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		 */
546de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		while ((function < max_functions) && (!stop_it)) {
547de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
549de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			if (ID == 0xFFFFFFFF)
550de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				function++;
551de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang			else {
552de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
553de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
554de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang				stop_it++;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
556de86ae16d55a23315cdf1dae68df9de55312cf25Alex Chiang		}
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
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
593427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* 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_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sub_bus = (int) secondary_bus;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[sub_bus];
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_save_base_addr_length(ctrl, next);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus->number = func->bus;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
612427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* FIXME: this loop is duplicated in the non-bridge
613427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * case.  The two could be rolled together Figure out
614427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * IO and memory base lengths
615427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
620427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
621427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
623427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
624427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set base = amount of IO space
625427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * requested
626427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
632427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* memory base */
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
643427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* Save information in slot structure */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_length[(cloop - 0x10) >> 2] =
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				base;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_type[(cloop - 0x10) >> 2] = type;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
648427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
650427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		} else if ((header_type & 0x7F) == 0x00) {
651427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
657427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
658427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
660427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
661427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * base = amount of IO space
662427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * requested
663427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
669427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* memory base
670427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * base = amount of memory
671427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * space requested
672427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
683427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* Save information in slot structure */
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_length[(cloop - 0x10) >> 2] = base;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->base_type[(cloop - 0x10) >> 2] = type;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
687427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
689427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		} else {	  /* Some other unknown header type */
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
692427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* find the next device in this slot */
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_save_used_resources
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stores used resource information for existing boards.  this is
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for boards that were in the system when this driver was loaded.
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function is for hot plug ADD
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func)
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp_byte;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b_base;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 b_length;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 command;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 save_command;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 w_base;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 w_length;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 save_base;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *mem_node;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *p_mem_node;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *io_node;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *bus_node;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((func != NULL) && func->is_a_board) {
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
738427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Save the command register */
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* disable card */
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		command = 0x00;
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
745427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check for Bridge */
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
748427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
749427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Clear Bridge Control Register */
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			command = 0x00;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bus_node)
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->base = secondary_bus;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->length = temp_byte - secondary_bus + 1;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->next = func->bus_head;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func->bus_head = bus_node;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
765427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Save IO base and Limit registers */
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((b_base <= b_length) && (save_command & 0x01)) {
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!io_node)
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->base = (b_base & 0xF0) << 8;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->length = (b_length - b_base + 0x10) << 8;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = func->io_head;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->io_head = io_node;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Save memory base and Limit registers */
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((w_base <= w_length) && (save_command & 0x02)) {
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!mem_node)
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->base = w_base << 16;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->length = (w_length - w_base + 0x10) << 16;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = func->mem_head;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->mem_head = mem_node;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
797427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Save prefetchable memory base and Limit registers */
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((w_base <= w_length) && (save_command & 0x02)) {
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!p_mem_node)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return -ENOMEM;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->base = w_base << 16;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->length = (w_length - w_base + 0x10) << 16;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = func->p_mem_head;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->p_mem_head = p_mem_node;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
812427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = base;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
822427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
823427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (((base & 0x03L) == 0x01)
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    && (save_command & 0x01)) {
826427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
827427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set temp_register = amount
828427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * of IO space requested
829427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFFE;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node = kmalloc(sizeof(*io_node),
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!io_node)
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->base =
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						save_base & (~0x03L);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->length = temp_register;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->next = func->io_head;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->io_head = io_node;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x08)
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
847427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node = kmalloc(sizeof(*p_mem_node),
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!p_mem_node)
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->base = save_base & (~0x0FL);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->length = temp_register;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->next = func->p_mem_head;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->p_mem_head = p_mem_node;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x00)
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
864427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node = kmalloc(sizeof(*mem_node),
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!mem_node)
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->base = save_base & (~0x0FL);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->length = temp_register;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->next = func->mem_head;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->mem_head = mem_node;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
881427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
882427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Standard header */
883427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		} else if ((header_type & 0x7F) == 0x00) {
884427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = base;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
894427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
895427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (((base & 0x03L) == 0x01)
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    && (save_command & 0x01)) {
898427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
899427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set temp_register = amount
900427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * of IO space requested
901427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFFE;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node = kmalloc(sizeof(*io_node),
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!io_node)
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->base = save_base & (~0x01L);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->length = temp_register;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						io_node->next = func->io_head;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->io_head = io_node;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x08)
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
918427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node = kmalloc(sizeof(*p_mem_node),
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!p_mem_node)
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->base = save_base & (~0x0FL);
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->length = temp_register;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						p_mem_node->next = func->p_mem_head;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->p_mem_head = p_mem_node;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (((base & 0x0BL) == 0x00)
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    && (save_command & 0x02)) {
935427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* prefetchable memory base */
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = base & 0xFFFFFFF0;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						temp_register = (~temp_register) + 1;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node = kmalloc(sizeof(*mem_node),
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								GFP_KERNEL);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (!mem_node)
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							return -ENOMEM;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->base = save_base & (~0x0FL);
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->length = temp_register;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						mem_node->next = func->mem_head;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						func->mem_head = mem_node;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						return(1);
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
952427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
955427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* find the next device in this slot */
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9594aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	return 0;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_configure_board
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copies saved configuration information to one slot.
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is called recursively for bridge devices.
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is for hot plug REPLACE!
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_configure_board(struct controller *ctrl, struct pci_func * func)
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cloop;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sub_bus;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Start at the top of config space so that the control
992427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * registers are programmed last
993427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
9944aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang		for (cloop = 0x3C; cloop > 0; cloop -= 4)
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
999427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If this is a bridge device, restore subordinate devices */
1000427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sub_bus = (int) secondary_bus;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[sub_bus];
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_configure_board(ctrl, next);
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1016427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Check all the base Address Registers to make sure
1017427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * they are the same.  If not, the board is different.
1018427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 16; cloop < 40; cloop += 4) {
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (temp != func->config_space[cloop >> 2]) {
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("Config space compare failure!!! offset = %x\n", cloop);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function);
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]);
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 1;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func->configured = 1;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_valid_replace
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function checks to see if a board is the same as the
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one it is replacing.  this check will detect if the device's
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vendor or device id's are the same
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if the board is the same nonzero otherwise
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func)
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cloop;
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 header_type;
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 secondary_bus;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 type;
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_register = 0;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 base;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rc;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *next;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int index = 0;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_bus *pci_bus = ctrl->pci_bus;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int devfn;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!func->is_a_board)
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(ADD_NOT_SUPPORTED);
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func = cpqhp_slot_find(func->bus, func->device, index++);
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (func != NULL) {
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus->number = func->bus;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devfn = PCI_DEVFN(func->device, func->function);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register);
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1075427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* No adapter present */
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register == 0xFFFFFFFF)
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(NO_ADAPTER_PRESENT);
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register != func->config_space[0])
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(ADAPTER_NOT_SAME);
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1082427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check for same revision number and class code */
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1085427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Adapter not the same */
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_register != func->config_space[0x08 >> 2])
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(ADAPTER_NOT_SAME);
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1089427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check for Bridge */
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1092427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
1093427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* In order to continue checking, we must program the
1094427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * bus registers in the bridge to respond to accesses
1095427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * for its subordinate bus(es)
1096427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			temp_register = func->config_space[0x18 >> 2];
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register);
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			secondary_bus = (temp_register >> 8) & 0xFF;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			next = cpqhp_slot_list[secondary_bus];
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (next != NULL) {
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = cpqhp_valid_replace(ctrl, next);
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (rc)
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return rc;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next = next->next;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1114427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Check to see if it is a standard config header */
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
1116427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Check subsystem vendor and ID */
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (temp_register != func->config_space[0x2C >> 2]) {
1120427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If it's a SMART-2 and the register isn't
1121427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 * filled in, ignore the difference because
1122427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 * they just have an old rev of the firmware
1123427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				 */
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!((func->config_space[0] == 0xAE100E11)
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      && (temp_register == 0x00L)))
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1128427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* Figure out IO and memory base lengths */
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp_register = 0xFFFFFFFF;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
1133427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang
1134427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* If this register is implemented */
1135427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				if (base) {
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (base & 0x01L) {
1137427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* IO base
1138427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * set base = amount of IO
1139427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 * space requested
1140427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						 */
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFFE;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 1;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					} else {
1146427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang						/* memory base */
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = base & 0xFFFFFFF0;
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						base = (~base) + 1;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						type = 0;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base = 0x0L;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					type = 0;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1157427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang				/* Check information in slot structure */
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (func->base_length[(cloop - 0x10) >> 2] != base)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (func->base_type[(cloop - 0x10) >> 2] != type)
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return(ADAPTER_NOT_SAME);
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1164427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			}	/* End of base register loop */
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1166427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		}		/* End of (type 0 config space) else */
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
1168427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* this is not a type 0 or 1 config space header so
1169427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 * we don't know how to do it
1170427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			 */
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return(DEVICE_TYPE_NOT_SUPPORTED);
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1174427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* Get the next function */
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		func = cpqhp_slot_find(func->bus, func->device, index++);
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_find_available_resources
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finds available memory, IO, and IRQ resources for programming
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * devices which may be added to the system
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this function is for hot plug ADD!
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
1191861fefbf550d41e7a4f44584f3ec35977fa08bf1Alex Chiang */
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start)
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 temp;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 populated_slot;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 bridged_slot;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *one_slot;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *rom_resource_table;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_func *func = NULL;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 10, index;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 temp_dword, rc;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *mem_node;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *p_mem_node;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *io_node;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *bus_node;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("rom_resource_table = %p\n", rom_resource_table);
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12104aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	if (rom_resource_table == NULL)
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
12124aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang
1213427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* Sum all resources and setup resource maps */
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("unused_IRQ = %x\n", unused_IRQ);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = 0;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (unused_IRQ) {
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unused_IRQ & 1) {
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpqhp_disk_irq = temp;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unused_IRQ = unused_IRQ >> 1;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp++;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq);
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = unused_IRQ >> 1;
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp++;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (unused_IRQ) {
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unused_IRQ & 1) {
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cpqhp_nic_irq = temp;
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unused_IRQ = unused_IRQ >> 1;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp++;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unused_IRQ = readl(rom_resource_table + PCIIRQ);
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = 0;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12454aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	if (!cpqhp_nic_irq)
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpqhp_nic_irq = ctrl->cfgspc_irq;
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12484aabb58e1f544e97dbb97d0ce29bdfc9108f2f2cAlex Chiang	if (!cpqhp_disk_irq)
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpqhp_disk_irq = ctrl->cfgspc_irq;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = compaq_nvram_load(rom_start, ctrl);
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	one_slot = rom_resource_table + sizeof (struct hrt);
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("number_of_entries = %d\n", i);
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!readb(one_slot + SECONDARY_BUS))
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n");
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i && readb(one_slot + SECONDARY_BUS)) {
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 dev_func = readb(one_slot + DEV_FUNC);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8 max_bus = readb(one_slot + MAX_BUS);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 io_base = readw(one_slot + IO_BASE);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 io_length = readw(one_slot + IO_LENGTH);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 mem_base = readw(one_slot + MEM_BASE);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 mem_length = readw(one_slot + MEM_LENGTH);
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("%2.2x | %4.4x  | %4.4x | %4.4x   | %4.4x | %4.4x   | %4.4x |%2.2x %2.2x %2.2x\n",
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    primary_bus, secondary_bus, max_bus);
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1283427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If this entry isn't for our controller's bus, ignore it */
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (primary_bus != ctrl->bus) {
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i--;
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			one_slot += sizeof (struct slot_rt);
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1289427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* find out if this entry is for an occupied slot */
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ctrl->pci_bus->number = primary_bus;
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dbg("temp_D_word = %x\n", temp_dword);
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp_dword != 0xFFFFFFFF) {
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			index = 0;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (func && (func->function != (dev_func & 0x07))) {
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index);
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++);
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1303427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* If we can't find a match, skip this table entry */
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!func) {
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				i--;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				one_slot += sizeof (struct slot_rt);
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1309427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang			/* this may not work and shouldn't be used */
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (secondary_bus != primary_bus)
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bridged_slot = 1;
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bridged_slot = 0;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			populated_slot = 1;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			populated_slot = 0;
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bridged_slot = 0;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1322427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid IO base, use it */
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = io_base + io_length;
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((io_base) && (temp_dword < 0x10000)) {
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!io_node)
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node->base = io_base;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io_node->length = io_length;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found io_node(base, length) = %x, %x\n",
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					io_node->base, io_node->length);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = ctrl->io_head;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->io_head = io_node;
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				io_node->next = func->io_head;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->io_head = io_node;
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1346427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid memory base, use it */
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = mem_base + mem_length;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((mem_base) && (temp_dword < 0x10000)) {
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!mem_node)
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node->base = mem_base << 16;
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem_node->length = mem_length << 16;
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found mem_node(base, length) = %x, %x\n",
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mem_node->base, mem_node->length);
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = ctrl->mem_head;
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->mem_head = mem_node;
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mem_node->next = func->mem_head;
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->mem_head = mem_node;
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1369427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid prefetchable memory base, and
1370427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * the base + length isn't greater than 0xFFFF
1371427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp_dword = pre_mem_base + pre_mem_length;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((pre_mem_base) && (temp_dword < 0x10000)) {
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!p_mem_node)
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node->base = pre_mem_base << 16;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p_mem_node->length = pre_mem_length << 16;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found p_mem_node(base, length) = %x, %x\n",
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					p_mem_node->base, p_mem_node->length);
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = ctrl->p_mem_head;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->p_mem_head = p_mem_node;
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				p_mem_node->next = func->p_mem_head;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->p_mem_head = p_mem_node;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1394427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		/* If we've got a valid bus number, use it
1395427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * The second condition is to ignore bus numbers on
1396427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 * populated slots that don't have PCI-PCI bridges
1397427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang		 */
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (secondary_bus && (secondary_bus != primary_bus)) {
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!bus_node)
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->base = secondary_bus;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bus_node->length = max_bus - secondary_bus + 1;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("found bus_node(base, length) = %x, %x\n",
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bus_node->base, bus_node->length);
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dbg("populated slot =%d \n", populated_slot);
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!populated_slot) {
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bus_node->next = ctrl->bus_head;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ctrl->bus_head = bus_node;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bus_node->next = func->bus_head;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func->bus_head = bus_node;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i--;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		one_slot += sizeof (struct slot_rt);
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	/* If all of the following fail, we don't have any resources for
1422427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	 * hot plug add
1423427438c61b0083a60bb953cb36cfdc5841f0bb03Alex Chiang	 */
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 1;
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_return_board_resources
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this routine returns all resources allocated to a board to
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the available pool.
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 0 if success
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *node;
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *t_node;
144766bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison	dbg("%s\n", __func__);
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!func)
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->io_head;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->io_head = NULL;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->io_head), node);
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->mem_head;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->mem_head = NULL;
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->mem_head), node);
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->p_mem_head;
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->p_mem_head = NULL;
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->p_mem_head), node);
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = func->bus_head;
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->bus_head = NULL;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (node) {
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		t_node = node->next;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return_resource(&(resources->bus_head), node);
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		node = t_node;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head));
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head));
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->io_head));
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head));
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_destroy_resource_list
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts node back in the resource list pointed to by head
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cpqhp_destroy_resource_list (struct resource_lists * resources)
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *res, *tres;
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->io_head;
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->io_head = NULL;
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->mem_head;
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->mem_head = NULL;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->p_mem_head;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->p_mem_head = NULL;
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = resources->bus_head;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resources->bus_head = NULL;
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cpqhp_destroy_board_resources
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts node back in the resource list pointed to by head
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid cpqhp_destroy_board_resources (struct pci_func * func)
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_resource *res, *tres;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->io_head;
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->io_head = NULL;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->mem_head;
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->mem_head = NULL;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->p_mem_head;
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->p_mem_head = NULL;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = func->bus_head;
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	func->bus_head = NULL;
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (res) {
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tres = res;
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = res->next;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tres);
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1586