18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * IBM Hot Plug Controller Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Written By: Irene Zubarev, IBM Corporation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
88c2ecf20Sopenharmony_ci * Copyright (C) 2001,2002 IBM Corp.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * All rights reserved.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Send feedback to <gregkh@us.ibm.com>
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/pci.h>
198c2ecf20Sopenharmony_ci#include <linux/list.h>
208c2ecf20Sopenharmony_ci#include "ibmphp.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int configure_device(struct pci_func *);
248c2ecf20Sopenharmony_cistatic int configure_bridge(struct pci_func **, u8);
258c2ecf20Sopenharmony_cistatic struct res_needed *scan_behind_bridge(struct pci_func *, u8);
268c2ecf20Sopenharmony_cistatic int add_new_bus(struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8);
278c2ecf20Sopenharmony_cistatic u8 find_sec_number(u8 primary_busno, u8 slotno);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * NOTE..... If BIOS doesn't provide default routing, we assign:
318c2ecf20Sopenharmony_ci * 9 for SCSI, 10 for LAN adapters, and 11 for everything else.
328c2ecf20Sopenharmony_ci * If adapter is bridged, then we assign 11 to it and devices behind it.
338c2ecf20Sopenharmony_ci * We also assign the same irq numbers for multi function devices.
348c2ecf20Sopenharmony_ci * These are PIC mode, so shouldn't matter n.e.ways (hopefully)
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic void assign_alt_irq(struct pci_func *cur_func, u8 class_code)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	int j;
398c2ecf20Sopenharmony_ci	for (j = 0; j < 4; j++) {
408c2ecf20Sopenharmony_ci		if (cur_func->irq[j] == 0xff) {
418c2ecf20Sopenharmony_ci			switch (class_code) {
428c2ecf20Sopenharmony_ci				case PCI_BASE_CLASS_STORAGE:
438c2ecf20Sopenharmony_ci					cur_func->irq[j] = SCSI_IRQ;
448c2ecf20Sopenharmony_ci					break;
458c2ecf20Sopenharmony_ci				case PCI_BASE_CLASS_NETWORK:
468c2ecf20Sopenharmony_ci					cur_func->irq[j] = LAN_IRQ;
478c2ecf20Sopenharmony_ci					break;
488c2ecf20Sopenharmony_ci				default:
498c2ecf20Sopenharmony_ci					cur_func->irq[j] = OTHER_IRQ;
508c2ecf20Sopenharmony_ci					break;
518c2ecf20Sopenharmony_ci			}
528c2ecf20Sopenharmony_ci		}
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/*
578c2ecf20Sopenharmony_ci * Configures the device to be added (will allocate needed resources if it
588c2ecf20Sopenharmony_ci * can), the device can be a bridge or a regular pci device, can also be
598c2ecf20Sopenharmony_ci * multi-functional
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * Input: function to be added
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * TO DO:  The error case with Multifunction device or multi function bridge,
648c2ecf20Sopenharmony_ci * if there is an error, will need to go through all previous functions and
658c2ecf20Sopenharmony_ci * unconfigure....or can add some code into unconfigure_card....
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_ciint ibmphp_configure_card(struct pci_func *func, u8 slotno)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	u16 vendor_id;
708c2ecf20Sopenharmony_ci	u32 class;
718c2ecf20Sopenharmony_ci	u8 class_code;
728c2ecf20Sopenharmony_ci	u8 hdr_type, device, sec_number;
738c2ecf20Sopenharmony_ci	u8 function;
748c2ecf20Sopenharmony_ci	struct pci_func *newfunc;	/* for multi devices */
758c2ecf20Sopenharmony_ci	struct pci_func *cur_func, *prev_func;
768c2ecf20Sopenharmony_ci	int rc, i, j;
778c2ecf20Sopenharmony_ci	int cleanup_count;
788c2ecf20Sopenharmony_ci	u8 flag;
798c2ecf20Sopenharmony_ci	u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	debug("inside configure_card, func->busno = %x\n", func->busno);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	device = func->device;
848c2ecf20Sopenharmony_ci	cur_func = func;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* We only get bus and device from IRQ routing table.  So at this point,
878c2ecf20Sopenharmony_ci	 * func->busno is correct, and func->device contains only device (at the 5
888c2ecf20Sopenharmony_ci	 * highest bits)
898c2ecf20Sopenharmony_ci	 */
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* For every function on the card */
928c2ecf20Sopenharmony_ci	for (function = 0x00; function < 0x08; function++) {
938c2ecf20Sopenharmony_ci		unsigned int devfn = PCI_DEVFN(device, function);
948c2ecf20Sopenharmony_ci		ibmphp_pci_bus->number = cur_func->busno;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		cur_func->function = function;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		debug("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->function = %x\n",
998c2ecf20Sopenharmony_ci			cur_func->busno, cur_func->device, cur_func->function);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		debug("vendor_id is %x\n", vendor_id);
1048c2ecf20Sopenharmony_ci		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
1058c2ecf20Sopenharmony_ci			/* found correct device!!! */
1068c2ecf20Sopenharmony_ci			debug("found valid device, vendor_id = %x\n", vendor_id);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci			++valid_device;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci			/* header: x x x x x x x x
1118c2ecf20Sopenharmony_ci			 *         | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge
1128c2ecf20Sopenharmony_ci			 *         |_=> 0 = single function device, 1 = multi-function device
1138c2ecf20Sopenharmony_ci			 */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
1168c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci			class_code = class >> 24;
1198c2ecf20Sopenharmony_ci			debug("hrd_type = %x, class = %x, class_code %x\n", hdr_type, class, class_code);
1208c2ecf20Sopenharmony_ci			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
1218c2ecf20Sopenharmony_ci			if (class == PCI_CLASS_NOT_DEFINED_VGA) {
1228c2ecf20Sopenharmony_ci				err("The device %x is VGA compatible and as is not supported for hot plugging. "
1238c2ecf20Sopenharmony_ci				     "Please choose another device.\n", cur_func->device);
1248c2ecf20Sopenharmony_ci				return -ENODEV;
1258c2ecf20Sopenharmony_ci			} else if (class == PCI_CLASS_DISPLAY_VGA) {
1268c2ecf20Sopenharmony_ci				err("The device %x is not supported for hot plugging. Please choose another device.\n",
1278c2ecf20Sopenharmony_ci				     cur_func->device);
1288c2ecf20Sopenharmony_ci				return -ENODEV;
1298c2ecf20Sopenharmony_ci			}
1308c2ecf20Sopenharmony_ci			switch (hdr_type) {
1318c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_NORMAL:
1328c2ecf20Sopenharmony_ci					debug("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class);
1338c2ecf20Sopenharmony_ci					assign_alt_irq(cur_func, class_code);
1348c2ecf20Sopenharmony_ci					rc = configure_device(cur_func);
1358c2ecf20Sopenharmony_ci					if (rc < 0) {
1368c2ecf20Sopenharmony_ci						/* We need to do this in case some other BARs were properly inserted */
1378c2ecf20Sopenharmony_ci						err("was not able to configure devfunc %x on bus %x.\n",
1388c2ecf20Sopenharmony_ci						     cur_func->device, cur_func->busno);
1398c2ecf20Sopenharmony_ci						cleanup_count = 6;
1408c2ecf20Sopenharmony_ci						goto error;
1418c2ecf20Sopenharmony_ci					}
1428c2ecf20Sopenharmony_ci					cur_func->next = NULL;
1438c2ecf20Sopenharmony_ci					function = 0x8;
1448c2ecf20Sopenharmony_ci					break;
1458c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_MULTIDEVICE:
1468c2ecf20Sopenharmony_ci					assign_alt_irq(cur_func, class_code);
1478c2ecf20Sopenharmony_ci					rc = configure_device(cur_func);
1488c2ecf20Sopenharmony_ci					if (rc < 0) {
1498c2ecf20Sopenharmony_ci						/* We need to do this in case some other BARs were properly inserted */
1508c2ecf20Sopenharmony_ci						err("was not able to configure devfunc %x on bus %x...bailing out\n",
1518c2ecf20Sopenharmony_ci						     cur_func->device, cur_func->busno);
1528c2ecf20Sopenharmony_ci						cleanup_count = 6;
1538c2ecf20Sopenharmony_ci						goto error;
1548c2ecf20Sopenharmony_ci					}
1558c2ecf20Sopenharmony_ci					newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
1568c2ecf20Sopenharmony_ci					if (!newfunc)
1578c2ecf20Sopenharmony_ci						return -ENOMEM;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci					newfunc->busno = cur_func->busno;
1608c2ecf20Sopenharmony_ci					newfunc->device = device;
1618c2ecf20Sopenharmony_ci					cur_func->next = newfunc;
1628c2ecf20Sopenharmony_ci					cur_func = newfunc;
1638c2ecf20Sopenharmony_ci					for (j = 0; j < 4; j++)
1648c2ecf20Sopenharmony_ci						newfunc->irq[j] = cur_func->irq[j];
1658c2ecf20Sopenharmony_ci					break;
1668c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_MULTIBRIDGE:
1678c2ecf20Sopenharmony_ci					class >>= 8;
1688c2ecf20Sopenharmony_ci					if (class != PCI_CLASS_BRIDGE_PCI) {
1698c2ecf20Sopenharmony_ci						err("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging.  Please insert another card.\n",
1708c2ecf20Sopenharmony_ci						     cur_func->device);
1718c2ecf20Sopenharmony_ci						return -ENODEV;
1728c2ecf20Sopenharmony_ci					}
1738c2ecf20Sopenharmony_ci					assign_alt_irq(cur_func, class_code);
1748c2ecf20Sopenharmony_ci					rc = configure_bridge(&cur_func, slotno);
1758c2ecf20Sopenharmony_ci					if (rc == -ENODEV) {
1768c2ecf20Sopenharmony_ci						err("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");
1778c2ecf20Sopenharmony_ci						err("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device);
1788c2ecf20Sopenharmony_ci						return rc;
1798c2ecf20Sopenharmony_ci					}
1808c2ecf20Sopenharmony_ci					if (rc) {
1818c2ecf20Sopenharmony_ci						/* We need to do this in case some other BARs were properly inserted */
1828c2ecf20Sopenharmony_ci						err("was not able to hot-add PPB properly.\n");
1838c2ecf20Sopenharmony_ci						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
1848c2ecf20Sopenharmony_ci						cleanup_count = 2;
1858c2ecf20Sopenharmony_ci						goto error;
1868c2ecf20Sopenharmony_ci					}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci					pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
1898c2ecf20Sopenharmony_ci					flag = 0;
1908c2ecf20Sopenharmony_ci					for (i = 0; i < 32; i++) {
1918c2ecf20Sopenharmony_ci						if (func->devices[i]) {
1928c2ecf20Sopenharmony_ci							newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
1938c2ecf20Sopenharmony_ci							if (!newfunc)
1948c2ecf20Sopenharmony_ci								return -ENOMEM;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci							newfunc->busno = sec_number;
1978c2ecf20Sopenharmony_ci							newfunc->device = (u8) i;
1988c2ecf20Sopenharmony_ci							for (j = 0; j < 4; j++)
1998c2ecf20Sopenharmony_ci								newfunc->irq[j] = cur_func->irq[j];
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci							if (flag) {
2028c2ecf20Sopenharmony_ci								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;
2038c2ecf20Sopenharmony_ci								prev_func->next = newfunc;
2048c2ecf20Sopenharmony_ci							} else
2058c2ecf20Sopenharmony_ci								cur_func->next = newfunc;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci							rc = ibmphp_configure_card(newfunc, slotno);
2088c2ecf20Sopenharmony_ci							/* This could only happen if kmalloc failed */
2098c2ecf20Sopenharmony_ci							if (rc) {
2108c2ecf20Sopenharmony_ci								/* We need to do this in case bridge itself got configured properly, but devices behind it failed */
2118c2ecf20Sopenharmony_ci								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
2128c2ecf20Sopenharmony_ci								cleanup_count = 2;
2138c2ecf20Sopenharmony_ci								goto error;
2148c2ecf20Sopenharmony_ci							}
2158c2ecf20Sopenharmony_ci							flag = 1;
2168c2ecf20Sopenharmony_ci						}
2178c2ecf20Sopenharmony_ci					}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci					newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
2208c2ecf20Sopenharmony_ci					if (!newfunc)
2218c2ecf20Sopenharmony_ci						return -ENOMEM;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci					newfunc->busno = cur_func->busno;
2248c2ecf20Sopenharmony_ci					newfunc->device = device;
2258c2ecf20Sopenharmony_ci					for (j = 0; j < 4; j++)
2268c2ecf20Sopenharmony_ci						newfunc->irq[j] = cur_func->irq[j];
2278c2ecf20Sopenharmony_ci					for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next);
2288c2ecf20Sopenharmony_ci					prev_func->next = newfunc;
2298c2ecf20Sopenharmony_ci					cur_func = newfunc;
2308c2ecf20Sopenharmony_ci					break;
2318c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_BRIDGE:
2328c2ecf20Sopenharmony_ci					class >>= 8;
2338c2ecf20Sopenharmony_ci					debug("class now is %x\n", class);
2348c2ecf20Sopenharmony_ci					if (class != PCI_CLASS_BRIDGE_PCI) {
2358c2ecf20Sopenharmony_ci						err("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging.  Please insert another card.\n",
2368c2ecf20Sopenharmony_ci						     cur_func->device);
2378c2ecf20Sopenharmony_ci						return -ENODEV;
2388c2ecf20Sopenharmony_ci					}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci					assign_alt_irq(cur_func, class_code);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci					debug("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno);
2438c2ecf20Sopenharmony_ci					rc = configure_bridge(&cur_func, slotno);
2448c2ecf20Sopenharmony_ci					if (rc == -ENODEV) {
2458c2ecf20Sopenharmony_ci						err("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");
2468c2ecf20Sopenharmony_ci						err("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device);
2478c2ecf20Sopenharmony_ci						return rc;
2488c2ecf20Sopenharmony_ci					}
2498c2ecf20Sopenharmony_ci					if (rc) {
2508c2ecf20Sopenharmony_ci						/* We need to do this in case some other BARs were properly inserted */
2518c2ecf20Sopenharmony_ci						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
2528c2ecf20Sopenharmony_ci						err("was not able to hot-add PPB properly.\n");
2538c2ecf20Sopenharmony_ci						cleanup_count = 2;
2548c2ecf20Sopenharmony_ci						goto error;
2558c2ecf20Sopenharmony_ci					}
2568c2ecf20Sopenharmony_ci					debug("cur_func->busno = %x, device = %x, function = %x\n",
2578c2ecf20Sopenharmony_ci						cur_func->busno, device, function);
2588c2ecf20Sopenharmony_ci					pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
2598c2ecf20Sopenharmony_ci					debug("after configuring bridge..., sec_number = %x\n", sec_number);
2608c2ecf20Sopenharmony_ci					flag = 0;
2618c2ecf20Sopenharmony_ci					for (i = 0; i < 32; i++) {
2628c2ecf20Sopenharmony_ci						if (func->devices[i]) {
2638c2ecf20Sopenharmony_ci							debug("inside for loop, device is %x\n", i);
2648c2ecf20Sopenharmony_ci							newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
2658c2ecf20Sopenharmony_ci							if (!newfunc)
2668c2ecf20Sopenharmony_ci								return -ENOMEM;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci							newfunc->busno = sec_number;
2698c2ecf20Sopenharmony_ci							newfunc->device = (u8) i;
2708c2ecf20Sopenharmony_ci							for (j = 0; j < 4; j++)
2718c2ecf20Sopenharmony_ci								newfunc->irq[j] = cur_func->irq[j];
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci							if (flag) {
2748c2ecf20Sopenharmony_ci								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next);
2758c2ecf20Sopenharmony_ci								prev_func->next = newfunc;
2768c2ecf20Sopenharmony_ci							} else
2778c2ecf20Sopenharmony_ci								cur_func->next = newfunc;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci							rc = ibmphp_configure_card(newfunc, slotno);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci							/* Again, this case should not happen... For complete paranoia, will need to call remove_bus */
2828c2ecf20Sopenharmony_ci							if (rc) {
2838c2ecf20Sopenharmony_ci								/* We need to do this in case some other BARs were properly inserted */
2848c2ecf20Sopenharmony_ci								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
2858c2ecf20Sopenharmony_ci								cleanup_count = 2;
2868c2ecf20Sopenharmony_ci								goto error;
2878c2ecf20Sopenharmony_ci							}
2888c2ecf20Sopenharmony_ci							flag = 1;
2898c2ecf20Sopenharmony_ci						}
2908c2ecf20Sopenharmony_ci					}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci					function = 0x8;
2938c2ecf20Sopenharmony_ci					break;
2948c2ecf20Sopenharmony_ci				default:
2958c2ecf20Sopenharmony_ci					err("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type);
2968c2ecf20Sopenharmony_ci					return -ENXIO;
2978c2ecf20Sopenharmony_ci					break;
2988c2ecf20Sopenharmony_ci			}	/* end of switch */
2998c2ecf20Sopenharmony_ci		}	/* end of valid device */
3008c2ecf20Sopenharmony_ci	}	/* end of for */
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (!valid_device) {
3038c2ecf20Sopenharmony_ci		err("Cannot find any valid devices on the card.  Or unable to read from card.\n");
3048c2ecf20Sopenharmony_ci		return -ENODEV;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return 0;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cierror:
3108c2ecf20Sopenharmony_ci	for (i = 0; i < cleanup_count; i++) {
3118c2ecf20Sopenharmony_ci		if (cur_func->io[i]) {
3128c2ecf20Sopenharmony_ci			ibmphp_remove_resource(cur_func->io[i]);
3138c2ecf20Sopenharmony_ci			cur_func->io[i] = NULL;
3148c2ecf20Sopenharmony_ci		} else if (cur_func->pfmem[i]) {
3158c2ecf20Sopenharmony_ci			ibmphp_remove_resource(cur_func->pfmem[i]);
3168c2ecf20Sopenharmony_ci			cur_func->pfmem[i] = NULL;
3178c2ecf20Sopenharmony_ci		} else if (cur_func->mem[i]) {
3188c2ecf20Sopenharmony_ci			ibmphp_remove_resource(cur_func->mem[i]);
3198c2ecf20Sopenharmony_ci			cur_func->mem[i] = NULL;
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	return rc;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci/*
3268c2ecf20Sopenharmony_ci * This function configures the pci BARs of a single device.
3278c2ecf20Sopenharmony_ci * Input: pointer to the pci_func
3288c2ecf20Sopenharmony_ci * Output: configured PCI, 0, or error
3298c2ecf20Sopenharmony_ci */
3308c2ecf20Sopenharmony_cistatic int configure_device(struct pci_func *func)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	u32 bar[6];
3338c2ecf20Sopenharmony_ci	u32 address[] = {
3348c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_0,
3358c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_1,
3368c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_2,
3378c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_3,
3388c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_4,
3398c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_5,
3408c2ecf20Sopenharmony_ci		0
3418c2ecf20Sopenharmony_ci	};
3428c2ecf20Sopenharmony_ci	u8 irq;
3438c2ecf20Sopenharmony_ci	int count;
3448c2ecf20Sopenharmony_ci	int len[6];
3458c2ecf20Sopenharmony_ci	struct resource_node *io[6];
3468c2ecf20Sopenharmony_ci	struct resource_node *mem[6];
3478c2ecf20Sopenharmony_ci	struct resource_node *mem_tmp;
3488c2ecf20Sopenharmony_ci	struct resource_node *pfmem[6];
3498c2ecf20Sopenharmony_ci	unsigned int devfn;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	debug("%s - inside\n", __func__);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	devfn = PCI_DEVFN(func->device, func->function);
3548c2ecf20Sopenharmony_ci	ibmphp_pci_bus->number = func->busno;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	for (count = 0; address[count]; count++) {	/* for 6 BARs */
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		/* not sure if i need this.  per scott, said maybe need * something like this
3598c2ecf20Sopenharmony_ci		   if devices don't adhere 100% to the spec, so don't want to write
3608c2ecf20Sopenharmony_ci		   to the reserved bits
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		pcibios_read_config_byte(cur_func->busno, cur_func->device,
3638c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_0 + 4 * count, &tmp);
3648c2ecf20Sopenharmony_ci		if (tmp & 0x01) // IO
3658c2ecf20Sopenharmony_ci			pcibios_write_config_dword(cur_func->busno, cur_func->device,
3668c2ecf20Sopenharmony_ci			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD);
3678c2ecf20Sopenharmony_ci		else  // Memory
3688c2ecf20Sopenharmony_ci			pcibios_write_config_dword(cur_func->busno, cur_func->device,
3698c2ecf20Sopenharmony_ci			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF);
3708c2ecf20Sopenharmony_ci		 */
3718c2ecf20Sopenharmony_ci		pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
3728c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		if (!bar[count])	/* This BAR is not implemented */
3758c2ecf20Sopenharmony_ci			continue;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		debug("Device %x BAR %d wants %x\n", func->device, count, bar[count]);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
3808c2ecf20Sopenharmony_ci			/* This is IO */
3818c2ecf20Sopenharmony_ci			debug("inside IO SPACE\n");
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci			len[count] = bar[count] & 0xFFFFFFFC;
3848c2ecf20Sopenharmony_ci			len[count] = ~len[count] + 1;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci			debug("len[count] in IO %x, count %d\n", len[count], count);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci			io[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci			if (!io[count])
3918c2ecf20Sopenharmony_ci				return -ENOMEM;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci			io[count]->type = IO;
3948c2ecf20Sopenharmony_ci			io[count]->busno = func->busno;
3958c2ecf20Sopenharmony_ci			io[count]->devfunc = PCI_DEVFN(func->device, func->function);
3968c2ecf20Sopenharmony_ci			io[count]->len = len[count];
3978c2ecf20Sopenharmony_ci			if (ibmphp_check_resource(io[count], 0) == 0) {
3988c2ecf20Sopenharmony_ci				ibmphp_add_resource(io[count]);
3998c2ecf20Sopenharmony_ci				func->io[count] = io[count];
4008c2ecf20Sopenharmony_ci			} else {
4018c2ecf20Sopenharmony_ci				err("cannot allocate requested io for bus %x device %x function %x len %x\n",
4028c2ecf20Sopenharmony_ci				     func->busno, func->device, func->function, len[count]);
4038c2ecf20Sopenharmony_ci				kfree(io[count]);
4048c2ecf20Sopenharmony_ci				return -EIO;
4058c2ecf20Sopenharmony_ci			}
4068c2ecf20Sopenharmony_ci			pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->io[count]->start);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci			/* _______________This is for debugging purposes only_____________________ */
4098c2ecf20Sopenharmony_ci			debug("b4 writing, the IO address is %x\n", func->io[count]->start);
4108c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]);
4118c2ecf20Sopenharmony_ci			debug("after writing.... the start address is %x\n", bar[count]);
4128c2ecf20Sopenharmony_ci			/* _________________________________________________________________________*/
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		} else {
4158c2ecf20Sopenharmony_ci			/* This is Memory */
4168c2ecf20Sopenharmony_ci			if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
4178c2ecf20Sopenharmony_ci				/* pfmem */
4188c2ecf20Sopenharmony_ci				debug("PFMEM SPACE\n");
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci				len[count] = bar[count] & 0xFFFFFFF0;
4218c2ecf20Sopenharmony_ci				len[count] = ~len[count] + 1;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci				debug("len[count] in PFMEM %x, count %d\n", len[count], count);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci				pfmem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
4268c2ecf20Sopenharmony_ci				if (!pfmem[count])
4278c2ecf20Sopenharmony_ci					return -ENOMEM;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci				pfmem[count]->type = PFMEM;
4308c2ecf20Sopenharmony_ci				pfmem[count]->busno = func->busno;
4318c2ecf20Sopenharmony_ci				pfmem[count]->devfunc = PCI_DEVFN(func->device,
4328c2ecf20Sopenharmony_ci							func->function);
4338c2ecf20Sopenharmony_ci				pfmem[count]->len = len[count];
4348c2ecf20Sopenharmony_ci				pfmem[count]->fromMem = 0;
4358c2ecf20Sopenharmony_ci				if (ibmphp_check_resource(pfmem[count], 0) == 0) {
4368c2ecf20Sopenharmony_ci					ibmphp_add_resource(pfmem[count]);
4378c2ecf20Sopenharmony_ci					func->pfmem[count] = pfmem[count];
4388c2ecf20Sopenharmony_ci				} else {
4398c2ecf20Sopenharmony_ci					mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL);
4408c2ecf20Sopenharmony_ci					if (!mem_tmp) {
4418c2ecf20Sopenharmony_ci						kfree(pfmem[count]);
4428c2ecf20Sopenharmony_ci						return -ENOMEM;
4438c2ecf20Sopenharmony_ci					}
4448c2ecf20Sopenharmony_ci					mem_tmp->type = MEM;
4458c2ecf20Sopenharmony_ci					mem_tmp->busno = pfmem[count]->busno;
4468c2ecf20Sopenharmony_ci					mem_tmp->devfunc = pfmem[count]->devfunc;
4478c2ecf20Sopenharmony_ci					mem_tmp->len = pfmem[count]->len;
4488c2ecf20Sopenharmony_ci					debug("there's no pfmem... going into mem.\n");
4498c2ecf20Sopenharmony_ci					if (ibmphp_check_resource(mem_tmp, 0) == 0) {
4508c2ecf20Sopenharmony_ci						ibmphp_add_resource(mem_tmp);
4518c2ecf20Sopenharmony_ci						pfmem[count]->fromMem = 1;
4528c2ecf20Sopenharmony_ci						pfmem[count]->rangeno = mem_tmp->rangeno;
4538c2ecf20Sopenharmony_ci						pfmem[count]->start = mem_tmp->start;
4548c2ecf20Sopenharmony_ci						pfmem[count]->end = mem_tmp->end;
4558c2ecf20Sopenharmony_ci						ibmphp_add_pfmem_from_mem(pfmem[count]);
4568c2ecf20Sopenharmony_ci						func->pfmem[count] = pfmem[count];
4578c2ecf20Sopenharmony_ci					} else {
4588c2ecf20Sopenharmony_ci						err("cannot allocate requested pfmem for bus %x, device %x, len %x\n",
4598c2ecf20Sopenharmony_ci						     func->busno, func->device, len[count]);
4608c2ecf20Sopenharmony_ci						kfree(mem_tmp);
4618c2ecf20Sopenharmony_ci						kfree(pfmem[count]);
4628c2ecf20Sopenharmony_ci						return -EIO;
4638c2ecf20Sopenharmony_ci					}
4648c2ecf20Sopenharmony_ci				}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci				/*_______________This is for debugging purposes only______________________________*/
4698c2ecf20Sopenharmony_ci				debug("b4 writing, start address is %x\n", func->pfmem[count]->start);
4708c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]);
4718c2ecf20Sopenharmony_ci				debug("after writing, start address is %x\n", bar[count]);
4728c2ecf20Sopenharmony_ci				/*_________________________________________________________________________________*/
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
4758c2ecf20Sopenharmony_ci					debug("inside the mem 64 case, count %d\n", count);
4768c2ecf20Sopenharmony_ci					count += 1;
4778c2ecf20Sopenharmony_ci					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
4788c2ecf20Sopenharmony_ci					pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0x00000000);
4798c2ecf20Sopenharmony_ci				}
4808c2ecf20Sopenharmony_ci			} else {
4818c2ecf20Sopenharmony_ci				/* regular memory */
4828c2ecf20Sopenharmony_ci				debug("REGULAR MEM SPACE\n");
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci				len[count] = bar[count] & 0xFFFFFFF0;
4858c2ecf20Sopenharmony_ci				len[count] = ~len[count] + 1;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci				debug("len[count] in Mem %x, count %d\n", len[count], count);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci				mem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
4908c2ecf20Sopenharmony_ci				if (!mem[count])
4918c2ecf20Sopenharmony_ci					return -ENOMEM;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci				mem[count]->type = MEM;
4948c2ecf20Sopenharmony_ci				mem[count]->busno = func->busno;
4958c2ecf20Sopenharmony_ci				mem[count]->devfunc = PCI_DEVFN(func->device,
4968c2ecf20Sopenharmony_ci							func->function);
4978c2ecf20Sopenharmony_ci				mem[count]->len = len[count];
4988c2ecf20Sopenharmony_ci				if (ibmphp_check_resource(mem[count], 0) == 0) {
4998c2ecf20Sopenharmony_ci					ibmphp_add_resource(mem[count]);
5008c2ecf20Sopenharmony_ci					func->mem[count] = mem[count];
5018c2ecf20Sopenharmony_ci				} else {
5028c2ecf20Sopenharmony_ci					err("cannot allocate requested mem for bus %x, device %x, len %x\n",
5038c2ecf20Sopenharmony_ci					     func->busno, func->device, len[count]);
5048c2ecf20Sopenharmony_ci					kfree(mem[count]);
5058c2ecf20Sopenharmony_ci					return -EIO;
5068c2ecf20Sopenharmony_ci				}
5078c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->mem[count]->start);
5088c2ecf20Sopenharmony_ci				/* _______________________This is for debugging purposes only _______________________*/
5098c2ecf20Sopenharmony_ci				debug("b4 writing, start address is %x\n", func->mem[count]->start);
5108c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]);
5118c2ecf20Sopenharmony_ci				debug("after writing, the address is %x\n", bar[count]);
5128c2ecf20Sopenharmony_ci				/* __________________________________________________________________________________*/
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
5158c2ecf20Sopenharmony_ci					/* takes up another dword */
5168c2ecf20Sopenharmony_ci					debug("inside mem 64 case, reg. mem, count %d\n", count);
5178c2ecf20Sopenharmony_ci					count += 1;
5188c2ecf20Sopenharmony_ci					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
5198c2ecf20Sopenharmony_ci					pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0x00000000);
5208c2ecf20Sopenharmony_ci				}
5218c2ecf20Sopenharmony_ci			}
5228c2ecf20Sopenharmony_ci		}		/* end of mem */
5238c2ecf20Sopenharmony_ci	}			/* end of for */
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	func->bus = 0;		/* To indicate that this is not a PPB */
5268c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq);
5278c2ecf20Sopenharmony_ci	if ((irq > 0x00) && (irq < 0x05))
5288c2ecf20Sopenharmony_ci		pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE);
5318c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	pci_bus_write_config_dword(ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L);
5348c2ecf20Sopenharmony_ci	pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	return 0;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci/******************************************************************************
5408c2ecf20Sopenharmony_ci * This routine configures a PCI-2-PCI bridge and the functions behind it
5418c2ecf20Sopenharmony_ci * Parameters: pci_func
5428c2ecf20Sopenharmony_ci * Returns:
5438c2ecf20Sopenharmony_ci ******************************************************************************/
5448c2ecf20Sopenharmony_cistatic int configure_bridge(struct pci_func **func_passed, u8 slotno)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	int count;
5478c2ecf20Sopenharmony_ci	int i;
5488c2ecf20Sopenharmony_ci	int rc;
5498c2ecf20Sopenharmony_ci	u8 sec_number;
5508c2ecf20Sopenharmony_ci	u8 io_base;
5518c2ecf20Sopenharmony_ci	u16 pfmem_base;
5528c2ecf20Sopenharmony_ci	u32 bar[2];
5538c2ecf20Sopenharmony_ci	u32 len[2];
5548c2ecf20Sopenharmony_ci	u8 flag_io = 0;
5558c2ecf20Sopenharmony_ci	u8 flag_mem = 0;
5568c2ecf20Sopenharmony_ci	u8 flag_pfmem = 0;
5578c2ecf20Sopenharmony_ci	u8 need_io_upper = 0;
5588c2ecf20Sopenharmony_ci	u8 need_pfmem_upper = 0;
5598c2ecf20Sopenharmony_ci	struct res_needed *amount_needed = NULL;
5608c2ecf20Sopenharmony_ci	struct resource_node *io = NULL;
5618c2ecf20Sopenharmony_ci	struct resource_node *bus_io[2] = {NULL, NULL};
5628c2ecf20Sopenharmony_ci	struct resource_node *mem = NULL;
5638c2ecf20Sopenharmony_ci	struct resource_node *bus_mem[2] = {NULL, NULL};
5648c2ecf20Sopenharmony_ci	struct resource_node *mem_tmp = NULL;
5658c2ecf20Sopenharmony_ci	struct resource_node *pfmem = NULL;
5668c2ecf20Sopenharmony_ci	struct resource_node *bus_pfmem[2] = {NULL, NULL};
5678c2ecf20Sopenharmony_ci	struct bus_node *bus;
5688c2ecf20Sopenharmony_ci	u32 address[] = {
5698c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_0,
5708c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_1,
5718c2ecf20Sopenharmony_ci		0
5728c2ecf20Sopenharmony_ci	};
5738c2ecf20Sopenharmony_ci	struct pci_func *func = *func_passed;
5748c2ecf20Sopenharmony_ci	unsigned int devfn;
5758c2ecf20Sopenharmony_ci	u8 irq;
5768c2ecf20Sopenharmony_ci	int retval;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	debug("%s - enter\n", __func__);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	devfn = PCI_DEVFN(func->function, func->device);
5818c2ecf20Sopenharmony_ci	ibmphp_pci_bus->number = func->busno;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	/* Configuring necessary info for the bridge so that we could see the devices
5848c2ecf20Sopenharmony_ci	 * behind it
5858c2ecf20Sopenharmony_ci	 */
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, func->busno);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	/* _____________________For debugging purposes only __________________________
5908c2ecf20Sopenharmony_ci	pci_bus_config_byte(ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number);
5918c2ecf20Sopenharmony_ci	debug("primary # written into the bridge is %x\n", pri_number);
5928c2ecf20Sopenharmony_ci	 ___________________________________________________________________________*/
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/* in EBDA, only get allocated 1 additional bus # per slot */
5958c2ecf20Sopenharmony_ci	sec_number = find_sec_number(func->busno, slotno);
5968c2ecf20Sopenharmony_ci	if (sec_number == 0xff) {
5978c2ecf20Sopenharmony_ci		err("cannot allocate secondary bus number for the bridged device\n");
5988c2ecf20Sopenharmony_ci		return -EINVAL;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	debug("after find_sec_number, the number we got is %x\n", sec_number);
6028c2ecf20Sopenharmony_ci	debug("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* __________________For debugging purposes only __________________________________
6078c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
6088c2ecf20Sopenharmony_ci	debug("sec_number after write/read is %x\n", sec_number);
6098c2ecf20Sopenharmony_ci	 ________________________________________________________________________________*/
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, sec_number);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	/* __________________For debugging purposes only ____________________________________
6148c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sec_number);
6158c2ecf20Sopenharmony_ci	debug("subordinate number after write/read is %x\n", sec_number);
6168c2ecf20Sopenharmony_ci	 __________________________________________________________________________________*/
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE);
6198c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY);
6208c2ecf20Sopenharmony_ci	pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_SEC_LATENCY_TIMER, LATENCY);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	debug("func->busno is %x\n", func->busno);
6238c2ecf20Sopenharmony_ci	debug("sec_number after writing is %x\n", sec_number);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6278c2ecf20Sopenharmony_ci	   !!!!!!!!!!!!!!!NEED TO ADD!!!  FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!!
6288c2ecf20Sopenharmony_ci	   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	/* First we need to allocate mem/io for the bridge itself in case it needs it */
6328c2ecf20Sopenharmony_ci	for (count = 0; address[count]; count++) {	/* for 2 BARs */
6338c2ecf20Sopenharmony_ci		pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
6348c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci		if (!bar[count]) {
6378c2ecf20Sopenharmony_ci			/* This BAR is not implemented */
6388c2ecf20Sopenharmony_ci			debug("so we come here then, eh?, count = %d\n", count);
6398c2ecf20Sopenharmony_ci			continue;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci		//  tmp_bar = bar[count];
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		debug("Bar %d wants %x\n", count, bar[count]);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
6468c2ecf20Sopenharmony_ci			/* This is IO */
6478c2ecf20Sopenharmony_ci			len[count] = bar[count] & 0xFFFFFFFC;
6488c2ecf20Sopenharmony_ci			len[count] = ~len[count] + 1;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci			debug("len[count] in IO = %x\n", len[count]);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci			bus_io[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci			if (!bus_io[count]) {
6558c2ecf20Sopenharmony_ci				retval = -ENOMEM;
6568c2ecf20Sopenharmony_ci				goto error;
6578c2ecf20Sopenharmony_ci			}
6588c2ecf20Sopenharmony_ci			bus_io[count]->type = IO;
6598c2ecf20Sopenharmony_ci			bus_io[count]->busno = func->busno;
6608c2ecf20Sopenharmony_ci			bus_io[count]->devfunc = PCI_DEVFN(func->device,
6618c2ecf20Sopenharmony_ci							func->function);
6628c2ecf20Sopenharmony_ci			bus_io[count]->len = len[count];
6638c2ecf20Sopenharmony_ci			if (ibmphp_check_resource(bus_io[count], 0) == 0) {
6648c2ecf20Sopenharmony_ci				ibmphp_add_resource(bus_io[count]);
6658c2ecf20Sopenharmony_ci				func->io[count] = bus_io[count];
6668c2ecf20Sopenharmony_ci			} else {
6678c2ecf20Sopenharmony_ci				err("cannot allocate requested io for bus %x, device %x, len %x\n",
6688c2ecf20Sopenharmony_ci				     func->busno, func->device, len[count]);
6698c2ecf20Sopenharmony_ci				kfree(bus_io[count]);
6708c2ecf20Sopenharmony_ci				return -EIO;
6718c2ecf20Sopenharmony_ci			}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci			pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->io[count]->start);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		} else {
6768c2ecf20Sopenharmony_ci			/* This is Memory */
6778c2ecf20Sopenharmony_ci			if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
6788c2ecf20Sopenharmony_ci				/* pfmem */
6798c2ecf20Sopenharmony_ci				len[count] = bar[count] & 0xFFFFFFF0;
6808c2ecf20Sopenharmony_ci				len[count] = ~len[count] + 1;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci				debug("len[count] in PFMEM = %x\n", len[count]);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci				bus_pfmem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
6858c2ecf20Sopenharmony_ci				if (!bus_pfmem[count]) {
6868c2ecf20Sopenharmony_ci					retval = -ENOMEM;
6878c2ecf20Sopenharmony_ci					goto error;
6888c2ecf20Sopenharmony_ci				}
6898c2ecf20Sopenharmony_ci				bus_pfmem[count]->type = PFMEM;
6908c2ecf20Sopenharmony_ci				bus_pfmem[count]->busno = func->busno;
6918c2ecf20Sopenharmony_ci				bus_pfmem[count]->devfunc = PCI_DEVFN(func->device,
6928c2ecf20Sopenharmony_ci							func->function);
6938c2ecf20Sopenharmony_ci				bus_pfmem[count]->len = len[count];
6948c2ecf20Sopenharmony_ci				bus_pfmem[count]->fromMem = 0;
6958c2ecf20Sopenharmony_ci				if (ibmphp_check_resource(bus_pfmem[count], 0) == 0) {
6968c2ecf20Sopenharmony_ci					ibmphp_add_resource(bus_pfmem[count]);
6978c2ecf20Sopenharmony_ci					func->pfmem[count] = bus_pfmem[count];
6988c2ecf20Sopenharmony_ci				} else {
6998c2ecf20Sopenharmony_ci					mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL);
7008c2ecf20Sopenharmony_ci					if (!mem_tmp) {
7018c2ecf20Sopenharmony_ci						retval = -ENOMEM;
7028c2ecf20Sopenharmony_ci						goto error;
7038c2ecf20Sopenharmony_ci					}
7048c2ecf20Sopenharmony_ci					mem_tmp->type = MEM;
7058c2ecf20Sopenharmony_ci					mem_tmp->busno = bus_pfmem[count]->busno;
7068c2ecf20Sopenharmony_ci					mem_tmp->devfunc = bus_pfmem[count]->devfunc;
7078c2ecf20Sopenharmony_ci					mem_tmp->len = bus_pfmem[count]->len;
7088c2ecf20Sopenharmony_ci					if (ibmphp_check_resource(mem_tmp, 0) == 0) {
7098c2ecf20Sopenharmony_ci						ibmphp_add_resource(mem_tmp);
7108c2ecf20Sopenharmony_ci						bus_pfmem[count]->fromMem = 1;
7118c2ecf20Sopenharmony_ci						bus_pfmem[count]->rangeno = mem_tmp->rangeno;
7128c2ecf20Sopenharmony_ci						ibmphp_add_pfmem_from_mem(bus_pfmem[count]);
7138c2ecf20Sopenharmony_ci						func->pfmem[count] = bus_pfmem[count];
7148c2ecf20Sopenharmony_ci					} else {
7158c2ecf20Sopenharmony_ci						err("cannot allocate requested pfmem for bus %x, device %x, len %x\n",
7168c2ecf20Sopenharmony_ci						     func->busno, func->device, len[count]);
7178c2ecf20Sopenharmony_ci						kfree(mem_tmp);
7188c2ecf20Sopenharmony_ci						kfree(bus_pfmem[count]);
7198c2ecf20Sopenharmony_ci						return -EIO;
7208c2ecf20Sopenharmony_ci					}
7218c2ecf20Sopenharmony_ci				}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
7268c2ecf20Sopenharmony_ci					/* takes up another dword */
7278c2ecf20Sopenharmony_ci					count += 1;
7288c2ecf20Sopenharmony_ci					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
7298c2ecf20Sopenharmony_ci					pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0x00000000);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci				}
7328c2ecf20Sopenharmony_ci			} else {
7338c2ecf20Sopenharmony_ci				/* regular memory */
7348c2ecf20Sopenharmony_ci				len[count] = bar[count] & 0xFFFFFFF0;
7358c2ecf20Sopenharmony_ci				len[count] = ~len[count] + 1;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci				debug("len[count] in Memory is %x\n", len[count]);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci				bus_mem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
7408c2ecf20Sopenharmony_ci				if (!bus_mem[count]) {
7418c2ecf20Sopenharmony_ci					retval = -ENOMEM;
7428c2ecf20Sopenharmony_ci					goto error;
7438c2ecf20Sopenharmony_ci				}
7448c2ecf20Sopenharmony_ci				bus_mem[count]->type = MEM;
7458c2ecf20Sopenharmony_ci				bus_mem[count]->busno = func->busno;
7468c2ecf20Sopenharmony_ci				bus_mem[count]->devfunc = PCI_DEVFN(func->device,
7478c2ecf20Sopenharmony_ci							func->function);
7488c2ecf20Sopenharmony_ci				bus_mem[count]->len = len[count];
7498c2ecf20Sopenharmony_ci				if (ibmphp_check_resource(bus_mem[count], 0) == 0) {
7508c2ecf20Sopenharmony_ci					ibmphp_add_resource(bus_mem[count]);
7518c2ecf20Sopenharmony_ci					func->mem[count] = bus_mem[count];
7528c2ecf20Sopenharmony_ci				} else {
7538c2ecf20Sopenharmony_ci					err("cannot allocate requested mem for bus %x, device %x, len %x\n",
7548c2ecf20Sopenharmony_ci					     func->busno, func->device, len[count]);
7558c2ecf20Sopenharmony_ci					kfree(bus_mem[count]);
7568c2ecf20Sopenharmony_ci					return -EIO;
7578c2ecf20Sopenharmony_ci				}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->mem[count]->start);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
7628c2ecf20Sopenharmony_ci					/* takes up another dword */
7638c2ecf20Sopenharmony_ci					count += 1;
7648c2ecf20Sopenharmony_ci					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
7658c2ecf20Sopenharmony_ci					pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0x00000000);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci				}
7688c2ecf20Sopenharmony_ci			}
7698c2ecf20Sopenharmony_ci		}		/* end of mem */
7708c2ecf20Sopenharmony_ci	}			/* end of for  */
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	/* Now need to see how much space the devices behind the bridge needed */
7738c2ecf20Sopenharmony_ci	amount_needed = scan_behind_bridge(func, sec_number);
7748c2ecf20Sopenharmony_ci	if (amount_needed == NULL)
7758c2ecf20Sopenharmony_ci		return -ENOMEM;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	ibmphp_pci_bus->number = func->busno;
7788c2ecf20Sopenharmony_ci	debug("after coming back from scan_behind_bridge\n");
7798c2ecf20Sopenharmony_ci	debug("amount_needed->not_correct = %x\n", amount_needed->not_correct);
7808c2ecf20Sopenharmony_ci	debug("amount_needed->io = %x\n", amount_needed->io);
7818c2ecf20Sopenharmony_ci	debug("amount_needed->mem = %x\n", amount_needed->mem);
7828c2ecf20Sopenharmony_ci	debug("amount_needed->pfmem =  %x\n", amount_needed->pfmem);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (amount_needed->not_correct) {
7858c2ecf20Sopenharmony_ci		debug("amount_needed is not correct\n");
7868c2ecf20Sopenharmony_ci		for (count = 0; address[count]; count++) {
7878c2ecf20Sopenharmony_ci			/* for 2 BARs */
7888c2ecf20Sopenharmony_ci			if (bus_io[count]) {
7898c2ecf20Sopenharmony_ci				ibmphp_remove_resource(bus_io[count]);
7908c2ecf20Sopenharmony_ci				func->io[count] = NULL;
7918c2ecf20Sopenharmony_ci			} else if (bus_pfmem[count]) {
7928c2ecf20Sopenharmony_ci				ibmphp_remove_resource(bus_pfmem[count]);
7938c2ecf20Sopenharmony_ci				func->pfmem[count] = NULL;
7948c2ecf20Sopenharmony_ci			} else if (bus_mem[count]) {
7958c2ecf20Sopenharmony_ci				ibmphp_remove_resource(bus_mem[count]);
7968c2ecf20Sopenharmony_ci				func->mem[count] = NULL;
7978c2ecf20Sopenharmony_ci			}
7988c2ecf20Sopenharmony_ci		}
7998c2ecf20Sopenharmony_ci		kfree(amount_needed);
8008c2ecf20Sopenharmony_ci		return -ENODEV;
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (!amount_needed->io) {
8048c2ecf20Sopenharmony_ci		debug("it doesn't want IO?\n");
8058c2ecf20Sopenharmony_ci		flag_io = 1;
8068c2ecf20Sopenharmony_ci	} else {
8078c2ecf20Sopenharmony_ci		debug("it wants %x IO behind the bridge\n", amount_needed->io);
8088c2ecf20Sopenharmony_ci		io = kzalloc(sizeof(*io), GFP_KERNEL);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci		if (!io) {
8118c2ecf20Sopenharmony_ci			retval = -ENOMEM;
8128c2ecf20Sopenharmony_ci			goto error;
8138c2ecf20Sopenharmony_ci		}
8148c2ecf20Sopenharmony_ci		io->type = IO;
8158c2ecf20Sopenharmony_ci		io->busno = func->busno;
8168c2ecf20Sopenharmony_ci		io->devfunc = PCI_DEVFN(func->device, func->function);
8178c2ecf20Sopenharmony_ci		io->len = amount_needed->io;
8188c2ecf20Sopenharmony_ci		if (ibmphp_check_resource(io, 1) == 0) {
8198c2ecf20Sopenharmony_ci			debug("were we able to add io\n");
8208c2ecf20Sopenharmony_ci			ibmphp_add_resource(io);
8218c2ecf20Sopenharmony_ci			flag_io = 1;
8228c2ecf20Sopenharmony_ci		}
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (!amount_needed->mem) {
8268c2ecf20Sopenharmony_ci		debug("it doesn't want n.e.memory?\n");
8278c2ecf20Sopenharmony_ci		flag_mem = 1;
8288c2ecf20Sopenharmony_ci	} else {
8298c2ecf20Sopenharmony_ci		debug("it wants %x memory behind the bridge\n", amount_needed->mem);
8308c2ecf20Sopenharmony_ci		mem = kzalloc(sizeof(*mem), GFP_KERNEL);
8318c2ecf20Sopenharmony_ci		if (!mem) {
8328c2ecf20Sopenharmony_ci			retval = -ENOMEM;
8338c2ecf20Sopenharmony_ci			goto error;
8348c2ecf20Sopenharmony_ci		}
8358c2ecf20Sopenharmony_ci		mem->type = MEM;
8368c2ecf20Sopenharmony_ci		mem->busno = func->busno;
8378c2ecf20Sopenharmony_ci		mem->devfunc = PCI_DEVFN(func->device, func->function);
8388c2ecf20Sopenharmony_ci		mem->len = amount_needed->mem;
8398c2ecf20Sopenharmony_ci		if (ibmphp_check_resource(mem, 1) == 0) {
8408c2ecf20Sopenharmony_ci			ibmphp_add_resource(mem);
8418c2ecf20Sopenharmony_ci			flag_mem = 1;
8428c2ecf20Sopenharmony_ci			debug("were we able to add mem\n");
8438c2ecf20Sopenharmony_ci		}
8448c2ecf20Sopenharmony_ci	}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	if (!amount_needed->pfmem) {
8478c2ecf20Sopenharmony_ci		debug("it doesn't want n.e.pfmem mem?\n");
8488c2ecf20Sopenharmony_ci		flag_pfmem = 1;
8498c2ecf20Sopenharmony_ci	} else {
8508c2ecf20Sopenharmony_ci		debug("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem);
8518c2ecf20Sopenharmony_ci		pfmem = kzalloc(sizeof(*pfmem), GFP_KERNEL);
8528c2ecf20Sopenharmony_ci		if (!pfmem) {
8538c2ecf20Sopenharmony_ci			retval = -ENOMEM;
8548c2ecf20Sopenharmony_ci			goto error;
8558c2ecf20Sopenharmony_ci		}
8568c2ecf20Sopenharmony_ci		pfmem->type = PFMEM;
8578c2ecf20Sopenharmony_ci		pfmem->busno = func->busno;
8588c2ecf20Sopenharmony_ci		pfmem->devfunc = PCI_DEVFN(func->device, func->function);
8598c2ecf20Sopenharmony_ci		pfmem->len = amount_needed->pfmem;
8608c2ecf20Sopenharmony_ci		pfmem->fromMem = 0;
8618c2ecf20Sopenharmony_ci		if (ibmphp_check_resource(pfmem, 1) == 0) {
8628c2ecf20Sopenharmony_ci			ibmphp_add_resource(pfmem);
8638c2ecf20Sopenharmony_ci			flag_pfmem = 1;
8648c2ecf20Sopenharmony_ci		} else {
8658c2ecf20Sopenharmony_ci			mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL);
8668c2ecf20Sopenharmony_ci			if (!mem_tmp) {
8678c2ecf20Sopenharmony_ci				retval = -ENOMEM;
8688c2ecf20Sopenharmony_ci				goto error;
8698c2ecf20Sopenharmony_ci			}
8708c2ecf20Sopenharmony_ci			mem_tmp->type = MEM;
8718c2ecf20Sopenharmony_ci			mem_tmp->busno = pfmem->busno;
8728c2ecf20Sopenharmony_ci			mem_tmp->devfunc = pfmem->devfunc;
8738c2ecf20Sopenharmony_ci			mem_tmp->len = pfmem->len;
8748c2ecf20Sopenharmony_ci			if (ibmphp_check_resource(mem_tmp, 1) == 0) {
8758c2ecf20Sopenharmony_ci				ibmphp_add_resource(mem_tmp);
8768c2ecf20Sopenharmony_ci				pfmem->fromMem = 1;
8778c2ecf20Sopenharmony_ci				pfmem->rangeno = mem_tmp->rangeno;
8788c2ecf20Sopenharmony_ci				ibmphp_add_pfmem_from_mem(pfmem);
8798c2ecf20Sopenharmony_ci				flag_pfmem = 1;
8808c2ecf20Sopenharmony_ci			}
8818c2ecf20Sopenharmony_ci		}
8828c2ecf20Sopenharmony_ci	}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	debug("b4 if (flag_io && flag_mem && flag_pfmem)\n");
8858c2ecf20Sopenharmony_ci	debug("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem);
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (flag_io && flag_mem && flag_pfmem) {
8888c2ecf20Sopenharmony_ci		/* If on bootup, there was a bridged card in this slot,
8898c2ecf20Sopenharmony_ci		 * then card was removed and ibmphp got unloaded and loaded
8908c2ecf20Sopenharmony_ci		 * back again, there's no way for us to remove the bus
8918c2ecf20Sopenharmony_ci		 * struct, so no need to kmalloc, can use existing node
8928c2ecf20Sopenharmony_ci		 */
8938c2ecf20Sopenharmony_ci		bus = ibmphp_find_res_bus(sec_number);
8948c2ecf20Sopenharmony_ci		if (!bus) {
8958c2ecf20Sopenharmony_ci			bus = kzalloc(sizeof(*bus), GFP_KERNEL);
8968c2ecf20Sopenharmony_ci			if (!bus) {
8978c2ecf20Sopenharmony_ci				retval = -ENOMEM;
8988c2ecf20Sopenharmony_ci				goto error;
8998c2ecf20Sopenharmony_ci			}
9008c2ecf20Sopenharmony_ci			bus->busno = sec_number;
9018c2ecf20Sopenharmony_ci			debug("b4 adding new bus\n");
9028c2ecf20Sopenharmony_ci			rc = add_new_bus(bus, io, mem, pfmem, func->busno);
9038c2ecf20Sopenharmony_ci		} else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem))
9048c2ecf20Sopenharmony_ci			rc = add_new_bus(bus, io, mem, pfmem, 0xFF);
9058c2ecf20Sopenharmony_ci		else {
9068c2ecf20Sopenharmony_ci			err("expected bus structure not empty?\n");
9078c2ecf20Sopenharmony_ci			retval = -EIO;
9088c2ecf20Sopenharmony_ci			goto error;
9098c2ecf20Sopenharmony_ci		}
9108c2ecf20Sopenharmony_ci		if (rc) {
9118c2ecf20Sopenharmony_ci			if (rc == -ENOMEM) {
9128c2ecf20Sopenharmony_ci				ibmphp_remove_bus(bus, func->busno);
9138c2ecf20Sopenharmony_ci				kfree(amount_needed);
9148c2ecf20Sopenharmony_ci				return rc;
9158c2ecf20Sopenharmony_ci			}
9168c2ecf20Sopenharmony_ci			retval = rc;
9178c2ecf20Sopenharmony_ci			goto error;
9188c2ecf20Sopenharmony_ci		}
9198c2ecf20Sopenharmony_ci		pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_IO_BASE, &io_base);
9208c2ecf20Sopenharmony_ci		pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &pfmem_base);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci		if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
9238c2ecf20Sopenharmony_ci			debug("io 32\n");
9248c2ecf20Sopenharmony_ci			need_io_upper = 1;
9258c2ecf20Sopenharmony_ci		}
9268c2ecf20Sopenharmony_ci		if ((pfmem_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
9278c2ecf20Sopenharmony_ci			debug("pfmem 64\n");
9288c2ecf20Sopenharmony_ci			need_pfmem_upper = 1;
9298c2ecf20Sopenharmony_ci		}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		if (bus->noIORanges) {
9328c2ecf20Sopenharmony_ci			pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8);
9338c2ecf20Sopenharmony_ci			pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci			/* _______________This is for debugging purposes only ____________________
9368c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp);
9378c2ecf20Sopenharmony_ci			debug("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
9388c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &temp);
9398c2ecf20Sopenharmony_ci			debug("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
9408c2ecf20Sopenharmony_ci			 ________________________________________________________________________*/
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci			if (need_io_upper) {	/* since can't support n.e.ways */
9438c2ecf20Sopenharmony_ci				pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, 0x0000);
9448c2ecf20Sopenharmony_ci				pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, 0x0000);
9458c2ecf20Sopenharmony_ci			}
9468c2ecf20Sopenharmony_ci		} else {
9478c2ecf20Sopenharmony_ci			pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00);
9488c2ecf20Sopenharmony_ci			pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00);
9498c2ecf20Sopenharmony_ci		}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci		if (bus->noMemRanges) {
9528c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16);
9538c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci			/* ____________________This is for debugging purposes only ________________________
9568c2ecf20Sopenharmony_ci			pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp);
9578c2ecf20Sopenharmony_ci			debug("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
9588c2ecf20Sopenharmony_ci			pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &temp);
9598c2ecf20Sopenharmony_ci			debug("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
9608c2ecf20Sopenharmony_ci			 __________________________________________________________________________________*/
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		} else {
9638c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0xffff);
9648c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000);
9658c2ecf20Sopenharmony_ci		}
9668c2ecf20Sopenharmony_ci		if (bus->noPFMemRanges) {
9678c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16);
9688c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci			/* __________________________This is for debugging purposes only _______________________
9718c2ecf20Sopenharmony_ci			pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &temp);
9728c2ecf20Sopenharmony_ci			debug("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
9738c2ecf20Sopenharmony_ci			pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &temp);
9748c2ecf20Sopenharmony_ci			debug("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
9758c2ecf20Sopenharmony_ci			 ______________________________________________________________________________________*/
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci			if (need_pfmem_upper) {	/* since can't support n.e.ways */
9788c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, 0x00000000);
9798c2ecf20Sopenharmony_ci				pci_bus_write_config_dword(ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, 0x00000000);
9808c2ecf20Sopenharmony_ci			}
9818c2ecf20Sopenharmony_ci		} else {
9828c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0xffff);
9838c2ecf20Sopenharmony_ci			pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000);
9848c2ecf20Sopenharmony_ci		}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci		debug("b4 writing control information\n");
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq);
9898c2ecf20Sopenharmony_ci		if ((irq > 0x00) && (irq < 0x05))
9908c2ecf20Sopenharmony_ci			pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
9918c2ecf20Sopenharmony_ci		/*
9928c2ecf20Sopenharmony_ci		pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl);
9938c2ecf20Sopenharmony_ci		pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY);
9948c2ecf20Sopenharmony_ci		pci_bus_write_config_byte(ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
9958c2ecf20Sopenharmony_ci		 */
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci		pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE);
9988c2ecf20Sopenharmony_ci		pci_bus_write_config_word(ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, 0x07);
9998c2ecf20Sopenharmony_ci		for (i = 0; i < 32; i++) {
10008c2ecf20Sopenharmony_ci			if (amount_needed->devices[i]) {
10018c2ecf20Sopenharmony_ci				debug("device where devices[i] is 1 = %x\n", i);
10028c2ecf20Sopenharmony_ci				func->devices[i] = 1;
10038c2ecf20Sopenharmony_ci			}
10048c2ecf20Sopenharmony_ci		}
10058c2ecf20Sopenharmony_ci		func->bus = 1;	/* For unconfiguring, to indicate it's PPB */
10068c2ecf20Sopenharmony_ci		func_passed = &func;
10078c2ecf20Sopenharmony_ci		debug("func->busno b4 returning is %x\n", func->busno);
10088c2ecf20Sopenharmony_ci		debug("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno);
10098c2ecf20Sopenharmony_ci		kfree(amount_needed);
10108c2ecf20Sopenharmony_ci		return 0;
10118c2ecf20Sopenharmony_ci	} else {
10128c2ecf20Sopenharmony_ci		err("Configuring bridge was unsuccessful...\n");
10138c2ecf20Sopenharmony_ci		mem_tmp = NULL;
10148c2ecf20Sopenharmony_ci		retval = -EIO;
10158c2ecf20Sopenharmony_ci		goto error;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cierror:
10198c2ecf20Sopenharmony_ci	kfree(amount_needed);
10208c2ecf20Sopenharmony_ci	if (pfmem)
10218c2ecf20Sopenharmony_ci		ibmphp_remove_resource(pfmem);
10228c2ecf20Sopenharmony_ci	if (io)
10238c2ecf20Sopenharmony_ci		ibmphp_remove_resource(io);
10248c2ecf20Sopenharmony_ci	if (mem)
10258c2ecf20Sopenharmony_ci		ibmphp_remove_resource(mem);
10268c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {	/* for 2 BARs */
10278c2ecf20Sopenharmony_ci		if (bus_io[i]) {
10288c2ecf20Sopenharmony_ci			ibmphp_remove_resource(bus_io[i]);
10298c2ecf20Sopenharmony_ci			func->io[i] = NULL;
10308c2ecf20Sopenharmony_ci		} else if (bus_pfmem[i]) {
10318c2ecf20Sopenharmony_ci			ibmphp_remove_resource(bus_pfmem[i]);
10328c2ecf20Sopenharmony_ci			func->pfmem[i] = NULL;
10338c2ecf20Sopenharmony_ci		} else if (bus_mem[i]) {
10348c2ecf20Sopenharmony_ci			ibmphp_remove_resource(bus_mem[i]);
10358c2ecf20Sopenharmony_ci			func->mem[i] = NULL;
10368c2ecf20Sopenharmony_ci		}
10378c2ecf20Sopenharmony_ci	}
10388c2ecf20Sopenharmony_ci	return retval;
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci/*****************************************************************************
10428c2ecf20Sopenharmony_ci * This function adds up the amount of resources needed behind the PPB bridge
10438c2ecf20Sopenharmony_ci * and passes it to the configure_bridge function
10448c2ecf20Sopenharmony_ci * Input: bridge function
10458c2ecf20Sopenharmony_ci * Output: amount of resources needed
10468c2ecf20Sopenharmony_ci *****************************************************************************/
10478c2ecf20Sopenharmony_cistatic struct res_needed *scan_behind_bridge(struct pci_func *func, u8 busno)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	int count, len[6];
10508c2ecf20Sopenharmony_ci	u16 vendor_id;
10518c2ecf20Sopenharmony_ci	u8 hdr_type;
10528c2ecf20Sopenharmony_ci	u8 device, function;
10538c2ecf20Sopenharmony_ci	unsigned int devfn;
10548c2ecf20Sopenharmony_ci	int howmany = 0;	/*this is to see if there are any devices behind the bridge */
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	u32 bar[6], class;
10578c2ecf20Sopenharmony_ci	u32 address[] = {
10588c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_0,
10598c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_1,
10608c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_2,
10618c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_3,
10628c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_4,
10638c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_5,
10648c2ecf20Sopenharmony_ci		0
10658c2ecf20Sopenharmony_ci	};
10668c2ecf20Sopenharmony_ci	struct res_needed *amount;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	amount = kzalloc(sizeof(*amount), GFP_KERNEL);
10698c2ecf20Sopenharmony_ci	if (amount == NULL)
10708c2ecf20Sopenharmony_ci		return NULL;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	ibmphp_pci_bus->number = busno;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	debug("the bus_no behind the bridge is %x\n", busno);
10758c2ecf20Sopenharmony_ci	debug("scanning devices behind the bridge...\n");
10768c2ecf20Sopenharmony_ci	for (device = 0; device < 32; device++) {
10778c2ecf20Sopenharmony_ci		amount->devices[device] = 0;
10788c2ecf20Sopenharmony_ci		for (function = 0; function < 8; function++) {
10798c2ecf20Sopenharmony_ci			devfn = PCI_DEVFN(device, function);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci			pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
10848c2ecf20Sopenharmony_ci				/* found correct device!!! */
10858c2ecf20Sopenharmony_ci				howmany++;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci				pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
10888c2ecf20Sopenharmony_ci				pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci				debug("hdr_type behind the bridge is %x\n", hdr_type);
10918c2ecf20Sopenharmony_ci				if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
10928c2ecf20Sopenharmony_ci					err("embedded bridges not supported for hot-plugging.\n");
10938c2ecf20Sopenharmony_ci					amount->not_correct = 1;
10948c2ecf20Sopenharmony_ci					return amount;
10958c2ecf20Sopenharmony_ci				}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci				class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
10988c2ecf20Sopenharmony_ci				if (class == PCI_CLASS_NOT_DEFINED_VGA) {
10998c2ecf20Sopenharmony_ci					err("The device %x is VGA compatible and as is not supported for hot plugging.  Please choose another device.\n", device);
11008c2ecf20Sopenharmony_ci					amount->not_correct = 1;
11018c2ecf20Sopenharmony_ci					return amount;
11028c2ecf20Sopenharmony_ci				} else if (class == PCI_CLASS_DISPLAY_VGA) {
11038c2ecf20Sopenharmony_ci					err("The device %x is not supported for hot plugging.  Please choose another device.\n", device);
11048c2ecf20Sopenharmony_ci					amount->not_correct = 1;
11058c2ecf20Sopenharmony_ci					return amount;
11068c2ecf20Sopenharmony_ci				}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci				amount->devices[device] = 1;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci				for (count = 0; address[count]; count++) {
11118c2ecf20Sopenharmony_ci					/* for 6 BARs */
11128c2ecf20Sopenharmony_ci					/*
11138c2ecf20Sopenharmony_ci					pci_bus_read_config_byte(ibmphp_pci_bus, devfn, address[count], &tmp);
11148c2ecf20Sopenharmony_ci					if (tmp & 0x01) // IO
11158c2ecf20Sopenharmony_ci						pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFD);
11168c2ecf20Sopenharmony_ci					else // MEMORY
11178c2ecf20Sopenharmony_ci						pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
11188c2ecf20Sopenharmony_ci					*/
11198c2ecf20Sopenharmony_ci					pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
11208c2ecf20Sopenharmony_ci					pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci					debug("what is bar[count]? %x, count = %d\n", bar[count], count);
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci					if (!bar[count])	/* This BAR is not implemented */
11258c2ecf20Sopenharmony_ci						continue;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci					//tmp_bar = bar[count];
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci					debug("count %d device %x function %x wants %x resources\n", count, device, function, bar[count]);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci					if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
11328c2ecf20Sopenharmony_ci						/* This is IO */
11338c2ecf20Sopenharmony_ci						len[count] = bar[count] & 0xFFFFFFFC;
11348c2ecf20Sopenharmony_ci						len[count] = ~len[count] + 1;
11358c2ecf20Sopenharmony_ci						amount->io += len[count];
11368c2ecf20Sopenharmony_ci					} else {
11378c2ecf20Sopenharmony_ci						/* This is Memory */
11388c2ecf20Sopenharmony_ci						if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
11398c2ecf20Sopenharmony_ci							/* pfmem */
11408c2ecf20Sopenharmony_ci							len[count] = bar[count] & 0xFFFFFFF0;
11418c2ecf20Sopenharmony_ci							len[count] = ~len[count] + 1;
11428c2ecf20Sopenharmony_ci							amount->pfmem += len[count];
11438c2ecf20Sopenharmony_ci							if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64)
11448c2ecf20Sopenharmony_ci								/* takes up another dword */
11458c2ecf20Sopenharmony_ci								count += 1;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci						} else {
11488c2ecf20Sopenharmony_ci							/* regular memory */
11498c2ecf20Sopenharmony_ci							len[count] = bar[count] & 0xFFFFFFF0;
11508c2ecf20Sopenharmony_ci							len[count] = ~len[count] + 1;
11518c2ecf20Sopenharmony_ci							amount->mem += len[count];
11528c2ecf20Sopenharmony_ci							if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
11538c2ecf20Sopenharmony_ci								/* takes up another dword */
11548c2ecf20Sopenharmony_ci								count += 1;
11558c2ecf20Sopenharmony_ci							}
11568c2ecf20Sopenharmony_ci						}
11578c2ecf20Sopenharmony_ci					}
11588c2ecf20Sopenharmony_ci				}	/* end for */
11598c2ecf20Sopenharmony_ci			}	/* end if (valid) */
11608c2ecf20Sopenharmony_ci		}	/* end for */
11618c2ecf20Sopenharmony_ci	}	/* end for */
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	if (!howmany)
11648c2ecf20Sopenharmony_ci		amount->not_correct = 1;
11658c2ecf20Sopenharmony_ci	else
11668c2ecf20Sopenharmony_ci		amount->not_correct = 0;
11678c2ecf20Sopenharmony_ci	if ((amount->io) && (amount->io < IOBRIDGE))
11688c2ecf20Sopenharmony_ci		amount->io = IOBRIDGE;
11698c2ecf20Sopenharmony_ci	if ((amount->mem) && (amount->mem < MEMBRIDGE))
11708c2ecf20Sopenharmony_ci		amount->mem = MEMBRIDGE;
11718c2ecf20Sopenharmony_ci	if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE))
11728c2ecf20Sopenharmony_ci		amount->pfmem = MEMBRIDGE;
11738c2ecf20Sopenharmony_ci	return amount;
11748c2ecf20Sopenharmony_ci}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci/* The following 3 unconfigure_boot_ routines deal with the case when we had the card
11778c2ecf20Sopenharmony_ci * upon bootup in the system, since we don't allocate func to such case, we need to read
11788c2ecf20Sopenharmony_ci * the start addresses from pci config space and then find the corresponding entries in
11798c2ecf20Sopenharmony_ci * our resource lists.  The functions return either 0, -ENODEV, or -1 (general failure)
11808c2ecf20Sopenharmony_ci * Change: we also call these functions even if we configured the card ourselves (i.e., not
11818c2ecf20Sopenharmony_ci * the bootup case), since it should work same way
11828c2ecf20Sopenharmony_ci */
11838c2ecf20Sopenharmony_cistatic int unconfigure_boot_device(u8 busno, u8 device, u8 function)
11848c2ecf20Sopenharmony_ci{
11858c2ecf20Sopenharmony_ci	u32 start_address;
11868c2ecf20Sopenharmony_ci	u32 address[] = {
11878c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_0,
11888c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_1,
11898c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_2,
11908c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_3,
11918c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_4,
11928c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_5,
11938c2ecf20Sopenharmony_ci		0
11948c2ecf20Sopenharmony_ci	};
11958c2ecf20Sopenharmony_ci	int count;
11968c2ecf20Sopenharmony_ci	struct resource_node *io;
11978c2ecf20Sopenharmony_ci	struct resource_node *mem;
11988c2ecf20Sopenharmony_ci	struct resource_node *pfmem;
11998c2ecf20Sopenharmony_ci	struct bus_node *bus;
12008c2ecf20Sopenharmony_ci	u32 end_address;
12018c2ecf20Sopenharmony_ci	u32 temp_end;
12028c2ecf20Sopenharmony_ci	u32 size;
12038c2ecf20Sopenharmony_ci	u32 tmp_address;
12048c2ecf20Sopenharmony_ci	unsigned int devfn;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	debug("%s - enter\n", __func__);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	bus = ibmphp_find_res_bus(busno);
12098c2ecf20Sopenharmony_ci	if (!bus) {
12108c2ecf20Sopenharmony_ci		debug("cannot find corresponding bus.\n");
12118c2ecf20Sopenharmony_ci		return -EINVAL;
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	devfn = PCI_DEVFN(device, function);
12158c2ecf20Sopenharmony_ci	ibmphp_pci_bus->number = busno;
12168c2ecf20Sopenharmony_ci	for (count = 0; address[count]; count++) {	/* for 6 BARs */
12178c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &start_address);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci		/* We can do this here, b/c by that time the device driver of the card has been stopped */
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci		pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
12228c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &size);
12238c2ecf20Sopenharmony_ci		pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], start_address);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		debug("start_address is %x\n", start_address);
12268c2ecf20Sopenharmony_ci		debug("busno, device, function %x %x %x\n", busno, device, function);
12278c2ecf20Sopenharmony_ci		if (!size) {
12288c2ecf20Sopenharmony_ci			/* This BAR is not implemented */
12298c2ecf20Sopenharmony_ci			debug("is this bar no implemented?, count = %d\n", count);
12308c2ecf20Sopenharmony_ci			continue;
12318c2ecf20Sopenharmony_ci		}
12328c2ecf20Sopenharmony_ci		tmp_address = start_address;
12338c2ecf20Sopenharmony_ci		if (start_address & PCI_BASE_ADDRESS_SPACE_IO) {
12348c2ecf20Sopenharmony_ci			/* This is IO */
12358c2ecf20Sopenharmony_ci			start_address &= PCI_BASE_ADDRESS_IO_MASK;
12368c2ecf20Sopenharmony_ci			size = size & 0xFFFFFFFC;
12378c2ecf20Sopenharmony_ci			size = ~size + 1;
12388c2ecf20Sopenharmony_ci			end_address = start_address + size - 1;
12398c2ecf20Sopenharmony_ci			if (ibmphp_find_resource(bus, start_address, &io, IO))
12408c2ecf20Sopenharmony_ci				goto report_search_failure;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci			debug("io->start = %x\n", io->start);
12438c2ecf20Sopenharmony_ci			temp_end = io->end;
12448c2ecf20Sopenharmony_ci			start_address = io->end + 1;
12458c2ecf20Sopenharmony_ci			ibmphp_remove_resource(io);
12468c2ecf20Sopenharmony_ci			/* This is needed b/c of the old I/O restrictions in the BIOS */
12478c2ecf20Sopenharmony_ci			while (temp_end < end_address) {
12488c2ecf20Sopenharmony_ci				if (ibmphp_find_resource(bus, start_address,
12498c2ecf20Sopenharmony_ci							 &io, IO))
12508c2ecf20Sopenharmony_ci					goto report_search_failure;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci				debug("io->start = %x\n", io->start);
12538c2ecf20Sopenharmony_ci				temp_end = io->end;
12548c2ecf20Sopenharmony_ci				start_address = io->end + 1;
12558c2ecf20Sopenharmony_ci				ibmphp_remove_resource(io);
12568c2ecf20Sopenharmony_ci			}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci			/* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */
12598c2ecf20Sopenharmony_ci		} else {
12608c2ecf20Sopenharmony_ci			/* This is Memory */
12618c2ecf20Sopenharmony_ci			if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) {
12628c2ecf20Sopenharmony_ci				/* pfmem */
12638c2ecf20Sopenharmony_ci				debug("start address of pfmem is %x\n", start_address);
12648c2ecf20Sopenharmony_ci				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci				if (ibmphp_find_resource(bus, start_address, &pfmem, PFMEM) < 0) {
12678c2ecf20Sopenharmony_ci					err("cannot find corresponding PFMEM resource to remove\n");
12688c2ecf20Sopenharmony_ci					return -EIO;
12698c2ecf20Sopenharmony_ci				}
12708c2ecf20Sopenharmony_ci				if (pfmem) {
12718c2ecf20Sopenharmony_ci					debug("pfmem->start = %x\n", pfmem->start);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci					ibmphp_remove_resource(pfmem);
12748c2ecf20Sopenharmony_ci				}
12758c2ecf20Sopenharmony_ci			} else {
12768c2ecf20Sopenharmony_ci				/* regular memory */
12778c2ecf20Sopenharmony_ci				debug("start address of mem is %x\n", start_address);
12788c2ecf20Sopenharmony_ci				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci				if (ibmphp_find_resource(bus, start_address, &mem, MEM) < 0) {
12818c2ecf20Sopenharmony_ci					err("cannot find corresponding MEM resource to remove\n");
12828c2ecf20Sopenharmony_ci					return -EIO;
12838c2ecf20Sopenharmony_ci				}
12848c2ecf20Sopenharmony_ci				if (mem) {
12858c2ecf20Sopenharmony_ci					debug("mem->start = %x\n", mem->start);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci					ibmphp_remove_resource(mem);
12888c2ecf20Sopenharmony_ci				}
12898c2ecf20Sopenharmony_ci			}
12908c2ecf20Sopenharmony_ci			if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
12918c2ecf20Sopenharmony_ci				/* takes up another dword */
12928c2ecf20Sopenharmony_ci				count += 1;
12938c2ecf20Sopenharmony_ci			}
12948c2ecf20Sopenharmony_ci		}	/* end of mem */
12958c2ecf20Sopenharmony_ci	}	/* end of for */
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	return 0;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_cireport_search_failure:
13008c2ecf20Sopenharmony_ci	err("cannot find corresponding IO resource to remove\n");
13018c2ecf20Sopenharmony_ci	return -EIO;
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cistatic int unconfigure_boot_bridge(u8 busno, u8 device, u8 function)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	int count;
13078c2ecf20Sopenharmony_ci	int bus_no, pri_no, sub_no, sec_no = 0;
13088c2ecf20Sopenharmony_ci	u32 start_address, tmp_address;
13098c2ecf20Sopenharmony_ci	u8 sec_number, sub_number, pri_number;
13108c2ecf20Sopenharmony_ci	struct resource_node *io = NULL;
13118c2ecf20Sopenharmony_ci	struct resource_node *mem = NULL;
13128c2ecf20Sopenharmony_ci	struct resource_node *pfmem = NULL;
13138c2ecf20Sopenharmony_ci	struct bus_node *bus;
13148c2ecf20Sopenharmony_ci	u32 address[] = {
13158c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_0,
13168c2ecf20Sopenharmony_ci		PCI_BASE_ADDRESS_1,
13178c2ecf20Sopenharmony_ci		0
13188c2ecf20Sopenharmony_ci	};
13198c2ecf20Sopenharmony_ci	unsigned int devfn;
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	devfn = PCI_DEVFN(device, function);
13228c2ecf20Sopenharmony_ci	ibmphp_pci_bus->number = busno;
13238c2ecf20Sopenharmony_ci	bus_no = (int) busno;
13248c2ecf20Sopenharmony_ci	debug("busno is %x\n", busno);
13258c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number);
13268c2ecf20Sopenharmony_ci	debug("%s - busno = %x, primary_number = %x\n", __func__, busno, pri_number);
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
13298c2ecf20Sopenharmony_ci	debug("sec_number is %x\n", sec_number);
13308c2ecf20Sopenharmony_ci	sec_no = (int) sec_number;
13318c2ecf20Sopenharmony_ci	pri_no = (int) pri_number;
13328c2ecf20Sopenharmony_ci	if (pri_no != bus_no) {
13338c2ecf20Sopenharmony_ci		err("primary numbers in our structures and pci config space don't match.\n");
13348c2ecf20Sopenharmony_ci		return -EINVAL;
13358c2ecf20Sopenharmony_ci	}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number);
13388c2ecf20Sopenharmony_ci	sub_no = (int) sub_number;
13398c2ecf20Sopenharmony_ci	debug("sub_no is %d, sec_no is %d\n", sub_no, sec_no);
13408c2ecf20Sopenharmony_ci	if (sec_no != sub_number) {
13418c2ecf20Sopenharmony_ci		err("there're more buses behind this bridge.  Hot removal is not supported.  Please choose another card\n");
13428c2ecf20Sopenharmony_ci		return -ENODEV;
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	bus = ibmphp_find_res_bus(sec_number);
13468c2ecf20Sopenharmony_ci	if (!bus) {
13478c2ecf20Sopenharmony_ci		err("cannot find Bus structure for the bridged device\n");
13488c2ecf20Sopenharmony_ci		return -EINVAL;
13498c2ecf20Sopenharmony_ci	}
13508c2ecf20Sopenharmony_ci	debug("bus->busno is %x\n", bus->busno);
13518c2ecf20Sopenharmony_ci	debug("sec_number is %x\n", sec_number);
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	ibmphp_remove_bus(bus, busno);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	for (count = 0; address[count]; count++) {
13568c2ecf20Sopenharmony_ci		/* for 2 BARs */
13578c2ecf20Sopenharmony_ci		pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &start_address);
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci		if (!start_address) {
13608c2ecf20Sopenharmony_ci			/* This BAR is not implemented */
13618c2ecf20Sopenharmony_ci			continue;
13628c2ecf20Sopenharmony_ci		}
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci		tmp_address = start_address;
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci		if (start_address & PCI_BASE_ADDRESS_SPACE_IO) {
13678c2ecf20Sopenharmony_ci			/* This is IO */
13688c2ecf20Sopenharmony_ci			start_address &= PCI_BASE_ADDRESS_IO_MASK;
13698c2ecf20Sopenharmony_ci			if (ibmphp_find_resource(bus, start_address, &io, IO) < 0) {
13708c2ecf20Sopenharmony_ci				err("cannot find corresponding IO resource to remove\n");
13718c2ecf20Sopenharmony_ci				return -EIO;
13728c2ecf20Sopenharmony_ci			}
13738c2ecf20Sopenharmony_ci			if (io)
13748c2ecf20Sopenharmony_ci				debug("io->start = %x\n", io->start);
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci			ibmphp_remove_resource(io);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci			/* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */
13798c2ecf20Sopenharmony_ci		} else {
13808c2ecf20Sopenharmony_ci			/* This is Memory */
13818c2ecf20Sopenharmony_ci			if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) {
13828c2ecf20Sopenharmony_ci				/* pfmem */
13838c2ecf20Sopenharmony_ci				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
13848c2ecf20Sopenharmony_ci				if (ibmphp_find_resource(bus, start_address, &pfmem, PFMEM) < 0) {
13858c2ecf20Sopenharmony_ci					err("cannot find corresponding PFMEM resource to remove\n");
13868c2ecf20Sopenharmony_ci					return -EINVAL;
13878c2ecf20Sopenharmony_ci				}
13888c2ecf20Sopenharmony_ci				if (pfmem) {
13898c2ecf20Sopenharmony_ci					debug("pfmem->start = %x\n", pfmem->start);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci					ibmphp_remove_resource(pfmem);
13928c2ecf20Sopenharmony_ci				}
13938c2ecf20Sopenharmony_ci			} else {
13948c2ecf20Sopenharmony_ci				/* regular memory */
13958c2ecf20Sopenharmony_ci				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
13968c2ecf20Sopenharmony_ci				if (ibmphp_find_resource(bus, start_address, &mem, MEM) < 0) {
13978c2ecf20Sopenharmony_ci					err("cannot find corresponding MEM resource to remove\n");
13988c2ecf20Sopenharmony_ci					return -EINVAL;
13998c2ecf20Sopenharmony_ci				}
14008c2ecf20Sopenharmony_ci				if (mem) {
14018c2ecf20Sopenharmony_ci					debug("mem->start = %x\n", mem->start);
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci					ibmphp_remove_resource(mem);
14048c2ecf20Sopenharmony_ci				}
14058c2ecf20Sopenharmony_ci			}
14068c2ecf20Sopenharmony_ci			if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
14078c2ecf20Sopenharmony_ci				/* takes up another dword */
14088c2ecf20Sopenharmony_ci				count += 1;
14098c2ecf20Sopenharmony_ci			}
14108c2ecf20Sopenharmony_ci		}	/* end of mem */
14118c2ecf20Sopenharmony_ci	}	/* end of for */
14128c2ecf20Sopenharmony_ci	debug("%s - exiting, returning success\n", __func__);
14138c2ecf20Sopenharmony_ci	return 0;
14148c2ecf20Sopenharmony_ci}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_cistatic int unconfigure_boot_card(struct slot *slot_cur)
14178c2ecf20Sopenharmony_ci{
14188c2ecf20Sopenharmony_ci	u16 vendor_id;
14198c2ecf20Sopenharmony_ci	u32 class;
14208c2ecf20Sopenharmony_ci	u8 hdr_type;
14218c2ecf20Sopenharmony_ci	u8 device;
14228c2ecf20Sopenharmony_ci	u8 busno;
14238c2ecf20Sopenharmony_ci	u8 function;
14248c2ecf20Sopenharmony_ci	int rc;
14258c2ecf20Sopenharmony_ci	unsigned int devfn;
14268c2ecf20Sopenharmony_ci	u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	debug("%s - enter\n", __func__);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	device = slot_cur->device;
14318c2ecf20Sopenharmony_ci	busno = slot_cur->bus;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	debug("b4 for loop, device is %x\n", device);
14348c2ecf20Sopenharmony_ci	/* For every function on the card */
14358c2ecf20Sopenharmony_ci	for (function = 0x0; function < 0x08; function++) {
14368c2ecf20Sopenharmony_ci		devfn = PCI_DEVFN(device, function);
14378c2ecf20Sopenharmony_ci		ibmphp_pci_bus->number = busno;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci		pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
14428c2ecf20Sopenharmony_ci			/* found correct device!!! */
14438c2ecf20Sopenharmony_ci			++valid_device;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci			debug("%s - found correct device\n", __func__);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci			/* header: x x x x x x x x
14488c2ecf20Sopenharmony_ci			 *         | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge
14498c2ecf20Sopenharmony_ci			 *         |_=> 0 = single function device, 1 = multi-function device
14508c2ecf20Sopenharmony_ci			 */
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci			pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
14538c2ecf20Sopenharmony_ci			pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci			debug("hdr_type %x, class %x\n", hdr_type, class);
14568c2ecf20Sopenharmony_ci			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
14578c2ecf20Sopenharmony_ci			if (class == PCI_CLASS_NOT_DEFINED_VGA) {
14588c2ecf20Sopenharmony_ci				err("The device %x function %x is VGA compatible and is not supported for hot removing.  Please choose another device.\n", device, function);
14598c2ecf20Sopenharmony_ci				return -ENODEV;
14608c2ecf20Sopenharmony_ci			} else if (class == PCI_CLASS_DISPLAY_VGA) {
14618c2ecf20Sopenharmony_ci				err("The device %x function %x is not supported for hot removing.  Please choose another device.\n", device, function);
14628c2ecf20Sopenharmony_ci				return -ENODEV;
14638c2ecf20Sopenharmony_ci			}
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci			switch (hdr_type) {
14668c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_NORMAL:
14678c2ecf20Sopenharmony_ci					rc = unconfigure_boot_device(busno, device, function);
14688c2ecf20Sopenharmony_ci					if (rc) {
14698c2ecf20Sopenharmony_ci						err("was not able to unconfigure device %x func %x on bus %x. bailing out...\n",
14708c2ecf20Sopenharmony_ci						     device, function, busno);
14718c2ecf20Sopenharmony_ci						return rc;
14728c2ecf20Sopenharmony_ci					}
14738c2ecf20Sopenharmony_ci					function = 0x8;
14748c2ecf20Sopenharmony_ci					break;
14758c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_MULTIDEVICE:
14768c2ecf20Sopenharmony_ci					rc = unconfigure_boot_device(busno, device, function);
14778c2ecf20Sopenharmony_ci					if (rc) {
14788c2ecf20Sopenharmony_ci						err("was not able to unconfigure device %x func %x on bus %x. bailing out...\n",
14798c2ecf20Sopenharmony_ci						     device, function, busno);
14808c2ecf20Sopenharmony_ci						return rc;
14818c2ecf20Sopenharmony_ci					}
14828c2ecf20Sopenharmony_ci					break;
14838c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_BRIDGE:
14848c2ecf20Sopenharmony_ci					class >>= 8;
14858c2ecf20Sopenharmony_ci					if (class != PCI_CLASS_BRIDGE_PCI) {
14868c2ecf20Sopenharmony_ci						err("This device %x function %x is not PCI-to-PCI bridge, and is not supported for hot-removing.  Please try another card.\n", device, function);
14878c2ecf20Sopenharmony_ci						return -ENODEV;
14888c2ecf20Sopenharmony_ci					}
14898c2ecf20Sopenharmony_ci					rc = unconfigure_boot_bridge(busno, device, function);
14908c2ecf20Sopenharmony_ci					if (rc != 0) {
14918c2ecf20Sopenharmony_ci						err("was not able to hot-remove PPB properly.\n");
14928c2ecf20Sopenharmony_ci						return rc;
14938c2ecf20Sopenharmony_ci					}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci					function = 0x8;
14968c2ecf20Sopenharmony_ci					break;
14978c2ecf20Sopenharmony_ci				case PCI_HEADER_TYPE_MULTIBRIDGE:
14988c2ecf20Sopenharmony_ci					class >>= 8;
14998c2ecf20Sopenharmony_ci					if (class != PCI_CLASS_BRIDGE_PCI) {
15008c2ecf20Sopenharmony_ci						err("This device %x function %x is not PCI-to-PCI bridge,  and is not supported for hot-removing.  Please try another card.\n", device, function);
15018c2ecf20Sopenharmony_ci						return -ENODEV;
15028c2ecf20Sopenharmony_ci					}
15038c2ecf20Sopenharmony_ci					rc = unconfigure_boot_bridge(busno, device, function);
15048c2ecf20Sopenharmony_ci					if (rc != 0) {
15058c2ecf20Sopenharmony_ci						err("was not able to hot-remove PPB properly.\n");
15068c2ecf20Sopenharmony_ci						return rc;
15078c2ecf20Sopenharmony_ci					}
15088c2ecf20Sopenharmony_ci					break;
15098c2ecf20Sopenharmony_ci				default:
15108c2ecf20Sopenharmony_ci					err("MAJOR PROBLEM!!!! Cannot read device's header\n");
15118c2ecf20Sopenharmony_ci					return -1;
15128c2ecf20Sopenharmony_ci					break;
15138c2ecf20Sopenharmony_ci			}	/* end of switch */
15148c2ecf20Sopenharmony_ci		}	/* end of valid device */
15158c2ecf20Sopenharmony_ci	}	/* end of for */
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	if (!valid_device) {
15188c2ecf20Sopenharmony_ci		err("Could not find device to unconfigure.  Or could not read the card.\n");
15198c2ecf20Sopenharmony_ci		return -1;
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci	return 0;
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci/*
15258c2ecf20Sopenharmony_ci * free the resources of the card (multi, single, or bridged)
15268c2ecf20Sopenharmony_ci * Parameters: slot, flag to say if this is for removing entire module or just
15278c2ecf20Sopenharmony_ci * unconfiguring the device
15288c2ecf20Sopenharmony_ci * TO DO:  will probably need to add some code in case there was some resource,
15298c2ecf20Sopenharmony_ci * to remove it... this is from when we have errors in the configure_card...
15308c2ecf20Sopenharmony_ci *			!!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!!
15318c2ecf20Sopenharmony_ci * Returns: 0, -1, -ENODEV
15328c2ecf20Sopenharmony_ci */
15338c2ecf20Sopenharmony_ciint ibmphp_unconfigure_card(struct slot **slot_cur, int the_end)
15348c2ecf20Sopenharmony_ci{
15358c2ecf20Sopenharmony_ci	int i;
15368c2ecf20Sopenharmony_ci	int count;
15378c2ecf20Sopenharmony_ci	int rc;
15388c2ecf20Sopenharmony_ci	struct slot *sl = *slot_cur;
15398c2ecf20Sopenharmony_ci	struct pci_func *cur_func = NULL;
15408c2ecf20Sopenharmony_ci	struct pci_func *temp_func;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	debug("%s - enter\n", __func__);
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	if (!the_end) {
15458c2ecf20Sopenharmony_ci		/* Need to unconfigure the card */
15468c2ecf20Sopenharmony_ci		rc = unconfigure_boot_card(sl);
15478c2ecf20Sopenharmony_ci		if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) {
15488c2ecf20Sopenharmony_ci			/* In all other cases, will still need to get rid of func structure if it exists */
15498c2ecf20Sopenharmony_ci			return rc;
15508c2ecf20Sopenharmony_ci		}
15518c2ecf20Sopenharmony_ci	}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	if (sl->func) {
15548c2ecf20Sopenharmony_ci		cur_func = sl->func;
15558c2ecf20Sopenharmony_ci		while (cur_func) {
15568c2ecf20Sopenharmony_ci			/* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */
15578c2ecf20Sopenharmony_ci			if (cur_func->bus) {
15588c2ecf20Sopenharmony_ci				/* in other words, it's a PPB */
15598c2ecf20Sopenharmony_ci				count = 2;
15608c2ecf20Sopenharmony_ci			} else {
15618c2ecf20Sopenharmony_ci				count = 6;
15628c2ecf20Sopenharmony_ci			}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci			for (i = 0; i < count; i++) {
15658c2ecf20Sopenharmony_ci				if (cur_func->io[i]) {
15668c2ecf20Sopenharmony_ci					debug("io[%d] exists\n", i);
15678c2ecf20Sopenharmony_ci					if (the_end > 0)
15688c2ecf20Sopenharmony_ci						ibmphp_remove_resource(cur_func->io[i]);
15698c2ecf20Sopenharmony_ci					cur_func->io[i] = NULL;
15708c2ecf20Sopenharmony_ci				}
15718c2ecf20Sopenharmony_ci				if (cur_func->mem[i]) {
15728c2ecf20Sopenharmony_ci					debug("mem[%d] exists\n", i);
15738c2ecf20Sopenharmony_ci					if (the_end > 0)
15748c2ecf20Sopenharmony_ci						ibmphp_remove_resource(cur_func->mem[i]);
15758c2ecf20Sopenharmony_ci					cur_func->mem[i] = NULL;
15768c2ecf20Sopenharmony_ci				}
15778c2ecf20Sopenharmony_ci				if (cur_func->pfmem[i]) {
15788c2ecf20Sopenharmony_ci					debug("pfmem[%d] exists\n", i);
15798c2ecf20Sopenharmony_ci					if (the_end > 0)
15808c2ecf20Sopenharmony_ci						ibmphp_remove_resource(cur_func->pfmem[i]);
15818c2ecf20Sopenharmony_ci					cur_func->pfmem[i] = NULL;
15828c2ecf20Sopenharmony_ci				}
15838c2ecf20Sopenharmony_ci			}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci			temp_func = cur_func->next;
15868c2ecf20Sopenharmony_ci			kfree(cur_func);
15878c2ecf20Sopenharmony_ci			cur_func = temp_func;
15888c2ecf20Sopenharmony_ci		}
15898c2ecf20Sopenharmony_ci	}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	sl->func = NULL;
15928c2ecf20Sopenharmony_ci	*slot_cur = sl;
15938c2ecf20Sopenharmony_ci	debug("%s - exit\n", __func__);
15948c2ecf20Sopenharmony_ci	return 0;
15958c2ecf20Sopenharmony_ci}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci/*
15988c2ecf20Sopenharmony_ci * add a new bus resulting from hot-plugging a PPB bridge with devices
15998c2ecf20Sopenharmony_ci *
16008c2ecf20Sopenharmony_ci * Input: bus and the amount of resources needed (we know we can assign those,
16018c2ecf20Sopenharmony_ci *        since they've been checked already
16028c2ecf20Sopenharmony_ci * Output: bus added to the correct spot
16038c2ecf20Sopenharmony_ci *         0, -1, error
16048c2ecf20Sopenharmony_ci */
16058c2ecf20Sopenharmony_cistatic int add_new_bus(struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno)
16068c2ecf20Sopenharmony_ci{
16078c2ecf20Sopenharmony_ci	struct range_node *io_range = NULL;
16088c2ecf20Sopenharmony_ci	struct range_node *mem_range = NULL;
16098c2ecf20Sopenharmony_ci	struct range_node *pfmem_range = NULL;
16108c2ecf20Sopenharmony_ci	struct bus_node *cur_bus = NULL;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	/* Trying to find the parent bus number */
16138c2ecf20Sopenharmony_ci	if (parent_busno != 0xFF) {
16148c2ecf20Sopenharmony_ci		cur_bus	= ibmphp_find_res_bus(parent_busno);
16158c2ecf20Sopenharmony_ci		if (!cur_bus) {
16168c2ecf20Sopenharmony_ci			err("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n");
16178c2ecf20Sopenharmony_ci			return -ENODEV;
16188c2ecf20Sopenharmony_ci		}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci		list_add(&bus->bus_list, &cur_bus->bus_list);
16218c2ecf20Sopenharmony_ci	}
16228c2ecf20Sopenharmony_ci	if (io) {
16238c2ecf20Sopenharmony_ci		io_range = kzalloc(sizeof(*io_range), GFP_KERNEL);
16248c2ecf20Sopenharmony_ci		if (!io_range)
16258c2ecf20Sopenharmony_ci			return -ENOMEM;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci		io_range->start = io->start;
16288c2ecf20Sopenharmony_ci		io_range->end = io->end;
16298c2ecf20Sopenharmony_ci		io_range->rangeno = 1;
16308c2ecf20Sopenharmony_ci		bus->noIORanges = 1;
16318c2ecf20Sopenharmony_ci		bus->rangeIO = io_range;
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci	if (mem) {
16348c2ecf20Sopenharmony_ci		mem_range = kzalloc(sizeof(*mem_range), GFP_KERNEL);
16358c2ecf20Sopenharmony_ci		if (!mem_range)
16368c2ecf20Sopenharmony_ci			return -ENOMEM;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci		mem_range->start = mem->start;
16398c2ecf20Sopenharmony_ci		mem_range->end = mem->end;
16408c2ecf20Sopenharmony_ci		mem_range->rangeno = 1;
16418c2ecf20Sopenharmony_ci		bus->noMemRanges = 1;
16428c2ecf20Sopenharmony_ci		bus->rangeMem = mem_range;
16438c2ecf20Sopenharmony_ci	}
16448c2ecf20Sopenharmony_ci	if (pfmem) {
16458c2ecf20Sopenharmony_ci		pfmem_range = kzalloc(sizeof(*pfmem_range), GFP_KERNEL);
16468c2ecf20Sopenharmony_ci		if (!pfmem_range)
16478c2ecf20Sopenharmony_ci			return -ENOMEM;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		pfmem_range->start = pfmem->start;
16508c2ecf20Sopenharmony_ci		pfmem_range->end = pfmem->end;
16518c2ecf20Sopenharmony_ci		pfmem_range->rangeno = 1;
16528c2ecf20Sopenharmony_ci		bus->noPFMemRanges = 1;
16538c2ecf20Sopenharmony_ci		bus->rangePFMem = pfmem_range;
16548c2ecf20Sopenharmony_ci	}
16558c2ecf20Sopenharmony_ci	return 0;
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci/*
16598c2ecf20Sopenharmony_ci * find the 1st available bus number for PPB to set as its secondary bus
16608c2ecf20Sopenharmony_ci * Parameters: bus_number of the primary bus
16618c2ecf20Sopenharmony_ci * Returns: bus_number of the secondary bus or 0xff in case of failure
16628c2ecf20Sopenharmony_ci */
16638c2ecf20Sopenharmony_cistatic u8 find_sec_number(u8 primary_busno, u8 slotno)
16648c2ecf20Sopenharmony_ci{
16658c2ecf20Sopenharmony_ci	int min, max;
16668c2ecf20Sopenharmony_ci	u8 busno;
16678c2ecf20Sopenharmony_ci	struct bus_info *bus;
16688c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	bus = ibmphp_find_same_bus_num(primary_busno);
16718c2ecf20Sopenharmony_ci	if (!bus) {
16728c2ecf20Sopenharmony_ci		err("cannot get slot range of the bus from the BIOS\n");
16738c2ecf20Sopenharmony_ci		return 0xff;
16748c2ecf20Sopenharmony_ci	}
16758c2ecf20Sopenharmony_ci	max = bus->slot_max;
16768c2ecf20Sopenharmony_ci	min = bus->slot_min;
16778c2ecf20Sopenharmony_ci	if ((slotno > max) || (slotno < min)) {
16788c2ecf20Sopenharmony_ci		err("got the wrong range\n");
16798c2ecf20Sopenharmony_ci		return 0xff;
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci	busno = (u8) (slotno - (u8) min);
16828c2ecf20Sopenharmony_ci	busno += primary_busno + 0x01;
16838c2ecf20Sopenharmony_ci	bus_cur = ibmphp_find_res_bus(busno);
16848c2ecf20Sopenharmony_ci	/* either there is no such bus number, or there are no ranges, which
16858c2ecf20Sopenharmony_ci	 * can only happen if we removed the bridged device in previous load
16868c2ecf20Sopenharmony_ci	 * of the driver, and now only have the skeleton bus struct
16878c2ecf20Sopenharmony_ci	 */
16888c2ecf20Sopenharmony_ci	if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem)))
16898c2ecf20Sopenharmony_ci		return busno;
16908c2ecf20Sopenharmony_ci	return 0xff;
16918c2ecf20Sopenharmony_ci}
1692