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 <linux/init.h>
218c2ecf20Sopenharmony_ci#include "ibmphp.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int flags = 0;		/* for testing */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic void update_resources(struct bus_node *bus_cur, int type, int rangeno);
268c2ecf20Sopenharmony_cistatic int once_over(void);
278c2ecf20Sopenharmony_cistatic int remove_ranges(struct bus_node *, struct bus_node *);
288c2ecf20Sopenharmony_cistatic int update_bridge_ranges(struct bus_node **);
298c2ecf20Sopenharmony_cistatic int add_bus_range(int type, struct range_node *, struct bus_node *);
308c2ecf20Sopenharmony_cistatic void fix_resources(struct bus_node *);
318c2ecf20Sopenharmony_cistatic struct bus_node *find_bus_wprev(u8, struct bus_node **, u8);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic LIST_HEAD(gbuses);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic struct bus_node * __init alloc_error_bus(struct ebda_pci_rsrc *curr, u8 busno, int flag)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct bus_node *newbus;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!(curr) && !(flag)) {
408c2ecf20Sopenharmony_ci		err("NULL pointer passed\n");
418c2ecf20Sopenharmony_ci		return NULL;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	newbus = kzalloc(sizeof(struct bus_node), GFP_KERNEL);
458c2ecf20Sopenharmony_ci	if (!newbus)
468c2ecf20Sopenharmony_ci		return NULL;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (flag)
498c2ecf20Sopenharmony_ci		newbus->busno = busno;
508c2ecf20Sopenharmony_ci	else
518c2ecf20Sopenharmony_ci		newbus->busno = curr->bus_num;
528c2ecf20Sopenharmony_ci	list_add_tail(&newbus->bus_list, &gbuses);
538c2ecf20Sopenharmony_ci	return newbus;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic struct resource_node * __init alloc_resources(struct ebda_pci_rsrc *curr)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct resource_node *rs;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (!curr) {
618c2ecf20Sopenharmony_ci		err("NULL passed to allocate\n");
628c2ecf20Sopenharmony_ci		return NULL;
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	rs = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
668c2ecf20Sopenharmony_ci	if (!rs)
678c2ecf20Sopenharmony_ci		return NULL;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	rs->busno = curr->bus_num;
708c2ecf20Sopenharmony_ci	rs->devfunc = curr->dev_fun;
718c2ecf20Sopenharmony_ci	rs->start = curr->start_addr;
728c2ecf20Sopenharmony_ci	rs->end = curr->end_addr;
738c2ecf20Sopenharmony_ci	rs->len = curr->end_addr - curr->start_addr + 1;
748c2ecf20Sopenharmony_ci	return rs;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic int __init alloc_bus_range(struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct bus_node *newbus;
808c2ecf20Sopenharmony_ci	struct range_node *newrange;
818c2ecf20Sopenharmony_ci	u8 num_ranges = 0;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (first_bus) {
848c2ecf20Sopenharmony_ci		newbus = kzalloc(sizeof(struct bus_node), GFP_KERNEL);
858c2ecf20Sopenharmony_ci		if (!newbus)
868c2ecf20Sopenharmony_ci			return -ENOMEM;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		newbus->busno = curr->bus_num;
898c2ecf20Sopenharmony_ci	} else {
908c2ecf20Sopenharmony_ci		newbus = *new_bus;
918c2ecf20Sopenharmony_ci		switch (flag) {
928c2ecf20Sopenharmony_ci			case MEM:
938c2ecf20Sopenharmony_ci				num_ranges = newbus->noMemRanges;
948c2ecf20Sopenharmony_ci				break;
958c2ecf20Sopenharmony_ci			case PFMEM:
968c2ecf20Sopenharmony_ci				num_ranges = newbus->noPFMemRanges;
978c2ecf20Sopenharmony_ci				break;
988c2ecf20Sopenharmony_ci			case IO:
998c2ecf20Sopenharmony_ci				num_ranges = newbus->noIORanges;
1008c2ecf20Sopenharmony_ci				break;
1018c2ecf20Sopenharmony_ci		}
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	newrange = kzalloc(sizeof(struct range_node), GFP_KERNEL);
1058c2ecf20Sopenharmony_ci	if (!newrange) {
1068c2ecf20Sopenharmony_ci		if (first_bus)
1078c2ecf20Sopenharmony_ci			kfree(newbus);
1088c2ecf20Sopenharmony_ci		return -ENOMEM;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	newrange->start = curr->start_addr;
1118c2ecf20Sopenharmony_ci	newrange->end = curr->end_addr;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (first_bus || (!num_ranges))
1148c2ecf20Sopenharmony_ci		newrange->rangeno = 1;
1158c2ecf20Sopenharmony_ci	else {
1168c2ecf20Sopenharmony_ci		/* need to insert our range */
1178c2ecf20Sopenharmony_ci		add_bus_range(flag, newrange, newbus);
1188c2ecf20Sopenharmony_ci		debug("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end);
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	switch (flag) {
1228c2ecf20Sopenharmony_ci		case MEM:
1238c2ecf20Sopenharmony_ci			newbus->rangeMem = newrange;
1248c2ecf20Sopenharmony_ci			if (first_bus)
1258c2ecf20Sopenharmony_ci				newbus->noMemRanges = 1;
1268c2ecf20Sopenharmony_ci			else {
1278c2ecf20Sopenharmony_ci				debug("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
1288c2ecf20Sopenharmony_ci				++newbus->noMemRanges;
1298c2ecf20Sopenharmony_ci				fix_resources(newbus);
1308c2ecf20Sopenharmony_ci			}
1318c2ecf20Sopenharmony_ci			break;
1328c2ecf20Sopenharmony_ci		case IO:
1338c2ecf20Sopenharmony_ci			newbus->rangeIO = newrange;
1348c2ecf20Sopenharmony_ci			if (first_bus)
1358c2ecf20Sopenharmony_ci				newbus->noIORanges = 1;
1368c2ecf20Sopenharmony_ci			else {
1378c2ecf20Sopenharmony_ci				debug("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
1388c2ecf20Sopenharmony_ci				++newbus->noIORanges;
1398c2ecf20Sopenharmony_ci				fix_resources(newbus);
1408c2ecf20Sopenharmony_ci			}
1418c2ecf20Sopenharmony_ci			break;
1428c2ecf20Sopenharmony_ci		case PFMEM:
1438c2ecf20Sopenharmony_ci			newbus->rangePFMem = newrange;
1448c2ecf20Sopenharmony_ci			if (first_bus)
1458c2ecf20Sopenharmony_ci				newbus->noPFMemRanges = 1;
1468c2ecf20Sopenharmony_ci			else {
1478c2ecf20Sopenharmony_ci				debug("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
1488c2ecf20Sopenharmony_ci				++newbus->noPFMemRanges;
1498c2ecf20Sopenharmony_ci				fix_resources(newbus);
1508c2ecf20Sopenharmony_ci			}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci			break;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	*new_bus = newbus;
1568c2ecf20Sopenharmony_ci	*new_range = newrange;
1578c2ecf20Sopenharmony_ci	return 0;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/* Notes:
1628c2ecf20Sopenharmony_ci * 1. The ranges are ordered.  The buses are not ordered.  (First come)
1638c2ecf20Sopenharmony_ci *
1648c2ecf20Sopenharmony_ci * 2. If cannot allocate out of PFMem range, allocate from Mem ranges.  PFmemFromMem
1658c2ecf20Sopenharmony_ci * are not sorted. (no need since use mem node). To not change the entire code, we
1668c2ecf20Sopenharmony_ci * also add mem node whenever this case happens so as not to change
1678c2ecf20Sopenharmony_ci * ibmphp_check_mem_resource etc(and since it really is taking Mem resource)
1688c2ecf20Sopenharmony_ci */
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/*****************************************************************************
1718c2ecf20Sopenharmony_ci * This is the Resource Management initialization function.  It will go through
1728c2ecf20Sopenharmony_ci * the Resource list taken from EBDA and fill in this module's data structures
1738c2ecf20Sopenharmony_ci *
1748c2ecf20Sopenharmony_ci * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES,
1758c2ecf20Sopenharmony_ci * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW
1768c2ecf20Sopenharmony_ci *
1778c2ecf20Sopenharmony_ci * Input: ptr to the head of the resource list from EBDA
1788c2ecf20Sopenharmony_ci * Output: 0, -1 or error codes
1798c2ecf20Sopenharmony_ci ***************************************************************************/
1808c2ecf20Sopenharmony_ciint __init ibmphp_rsrc_init(void)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct ebda_pci_rsrc *curr;
1838c2ecf20Sopenharmony_ci	struct range_node *newrange = NULL;
1848c2ecf20Sopenharmony_ci	struct bus_node *newbus = NULL;
1858c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
1868c2ecf20Sopenharmony_ci	struct bus_node *bus_prev;
1878c2ecf20Sopenharmony_ci	struct resource_node *new_io = NULL;
1888c2ecf20Sopenharmony_ci	struct resource_node *new_mem = NULL;
1898c2ecf20Sopenharmony_ci	struct resource_node *new_pfmem = NULL;
1908c2ecf20Sopenharmony_ci	int rc;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	list_for_each_entry(curr, &ibmphp_ebda_pci_rsrc_head,
1938c2ecf20Sopenharmony_ci			    ebda_pci_rsrc_list) {
1948c2ecf20Sopenharmony_ci		if (!(curr->rsrc_type & PCIDEVMASK)) {
1958c2ecf20Sopenharmony_ci			/* EBDA still lists non PCI devices, so ignore... */
1968c2ecf20Sopenharmony_ci			debug("this is not a PCI DEVICE in rsrc_init, please take care\n");
1978c2ecf20Sopenharmony_ci			// continue;
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		/* this is a primary bus resource */
2018c2ecf20Sopenharmony_ci		if (curr->rsrc_type & PRIMARYBUSMASK) {
2028c2ecf20Sopenharmony_ci			/* memory */
2038c2ecf20Sopenharmony_ci			if ((curr->rsrc_type & RESTYPE) == MMASK) {
2048c2ecf20Sopenharmony_ci				/* no bus structure exists in place yet */
2058c2ecf20Sopenharmony_ci				if (list_empty(&gbuses)) {
2068c2ecf20Sopenharmony_ci					rc = alloc_bus_range(&newbus, &newrange, curr, MEM, 1);
2078c2ecf20Sopenharmony_ci					if (rc)
2088c2ecf20Sopenharmony_ci						return rc;
2098c2ecf20Sopenharmony_ci					list_add_tail(&newbus->bus_list, &gbuses);
2108c2ecf20Sopenharmony_ci					debug("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
2118c2ecf20Sopenharmony_ci				} else {
2128c2ecf20Sopenharmony_ci					bus_cur = find_bus_wprev(curr->bus_num, &bus_prev, 1);
2138c2ecf20Sopenharmony_ci					/* found our bus */
2148c2ecf20Sopenharmony_ci					if (bus_cur) {
2158c2ecf20Sopenharmony_ci						rc = alloc_bus_range(&bus_cur, &newrange, curr, MEM, 0);
2168c2ecf20Sopenharmony_ci						if (rc)
2178c2ecf20Sopenharmony_ci							return rc;
2188c2ecf20Sopenharmony_ci					} else {
2198c2ecf20Sopenharmony_ci						/* went through all the buses and didn't find ours, need to create a new bus node */
2208c2ecf20Sopenharmony_ci						rc = alloc_bus_range(&newbus, &newrange, curr, MEM, 1);
2218c2ecf20Sopenharmony_ci						if (rc)
2228c2ecf20Sopenharmony_ci							return rc;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci						list_add_tail(&newbus->bus_list, &gbuses);
2258c2ecf20Sopenharmony_ci						debug("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
2268c2ecf20Sopenharmony_ci					}
2278c2ecf20Sopenharmony_ci				}
2288c2ecf20Sopenharmony_ci			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
2298c2ecf20Sopenharmony_ci				/* prefetchable memory */
2308c2ecf20Sopenharmony_ci				if (list_empty(&gbuses)) {
2318c2ecf20Sopenharmony_ci					/* no bus structure exists in place yet */
2328c2ecf20Sopenharmony_ci					rc = alloc_bus_range(&newbus, &newrange, curr, PFMEM, 1);
2338c2ecf20Sopenharmony_ci					if (rc)
2348c2ecf20Sopenharmony_ci						return rc;
2358c2ecf20Sopenharmony_ci					list_add_tail(&newbus->bus_list, &gbuses);
2368c2ecf20Sopenharmony_ci					debug("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
2378c2ecf20Sopenharmony_ci				} else {
2388c2ecf20Sopenharmony_ci					bus_cur = find_bus_wprev(curr->bus_num, &bus_prev, 1);
2398c2ecf20Sopenharmony_ci					if (bus_cur) {
2408c2ecf20Sopenharmony_ci						/* found our bus */
2418c2ecf20Sopenharmony_ci						rc = alloc_bus_range(&bus_cur, &newrange, curr, PFMEM, 0);
2428c2ecf20Sopenharmony_ci						if (rc)
2438c2ecf20Sopenharmony_ci							return rc;
2448c2ecf20Sopenharmony_ci					} else {
2458c2ecf20Sopenharmony_ci						/* went through all the buses and didn't find ours, need to create a new bus node */
2468c2ecf20Sopenharmony_ci						rc = alloc_bus_range(&newbus, &newrange, curr, PFMEM, 1);
2478c2ecf20Sopenharmony_ci						if (rc)
2488c2ecf20Sopenharmony_ci							return rc;
2498c2ecf20Sopenharmony_ci						list_add_tail(&newbus->bus_list, &gbuses);
2508c2ecf20Sopenharmony_ci						debug("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
2518c2ecf20Sopenharmony_ci					}
2528c2ecf20Sopenharmony_ci				}
2538c2ecf20Sopenharmony_ci			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
2548c2ecf20Sopenharmony_ci				/* IO */
2558c2ecf20Sopenharmony_ci				if (list_empty(&gbuses)) {
2568c2ecf20Sopenharmony_ci					/* no bus structure exists in place yet */
2578c2ecf20Sopenharmony_ci					rc = alloc_bus_range(&newbus, &newrange, curr, IO, 1);
2588c2ecf20Sopenharmony_ci					if (rc)
2598c2ecf20Sopenharmony_ci						return rc;
2608c2ecf20Sopenharmony_ci					list_add_tail(&newbus->bus_list, &gbuses);
2618c2ecf20Sopenharmony_ci					debug("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
2628c2ecf20Sopenharmony_ci				} else {
2638c2ecf20Sopenharmony_ci					bus_cur = find_bus_wprev(curr->bus_num, &bus_prev, 1);
2648c2ecf20Sopenharmony_ci					if (bus_cur) {
2658c2ecf20Sopenharmony_ci						rc = alloc_bus_range(&bus_cur, &newrange, curr, IO, 0);
2668c2ecf20Sopenharmony_ci						if (rc)
2678c2ecf20Sopenharmony_ci							return rc;
2688c2ecf20Sopenharmony_ci					} else {
2698c2ecf20Sopenharmony_ci						/* went through all the buses and didn't find ours, need to create a new bus node */
2708c2ecf20Sopenharmony_ci						rc = alloc_bus_range(&newbus, &newrange, curr, IO, 1);
2718c2ecf20Sopenharmony_ci						if (rc)
2728c2ecf20Sopenharmony_ci							return rc;
2738c2ecf20Sopenharmony_ci						list_add_tail(&newbus->bus_list, &gbuses);
2748c2ecf20Sopenharmony_ci						debug("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
2758c2ecf20Sopenharmony_ci					}
2768c2ecf20Sopenharmony_ci				}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci			} else {
2798c2ecf20Sopenharmony_ci				;	/* type is reserved  WHAT TO DO IN THIS CASE???
2808c2ecf20Sopenharmony_ci					   NOTHING TO DO??? */
2818c2ecf20Sopenharmony_ci			}
2828c2ecf20Sopenharmony_ci		} else {
2838c2ecf20Sopenharmony_ci			/* regular pci device resource */
2848c2ecf20Sopenharmony_ci			if ((curr->rsrc_type & RESTYPE) == MMASK) {
2858c2ecf20Sopenharmony_ci				/* Memory resource */
2868c2ecf20Sopenharmony_ci				new_mem = alloc_resources(curr);
2878c2ecf20Sopenharmony_ci				if (!new_mem)
2888c2ecf20Sopenharmony_ci					return -ENOMEM;
2898c2ecf20Sopenharmony_ci				new_mem->type = MEM;
2908c2ecf20Sopenharmony_ci				/*
2918c2ecf20Sopenharmony_ci				 * if it didn't find the bus, means PCI dev
2928c2ecf20Sopenharmony_ci				 * came b4 the Primary Bus info, so need to
2938c2ecf20Sopenharmony_ci				 * create a bus rangeno becomes a problem...
2948c2ecf20Sopenharmony_ci				 * assign a -1 and then update once the range
2958c2ecf20Sopenharmony_ci				 * actually appears...
2968c2ecf20Sopenharmony_ci				 */
2978c2ecf20Sopenharmony_ci				if (ibmphp_add_resource(new_mem) < 0) {
2988c2ecf20Sopenharmony_ci					newbus = alloc_error_bus(curr, 0, 0);
2998c2ecf20Sopenharmony_ci					if (!newbus)
3008c2ecf20Sopenharmony_ci						return -ENOMEM;
3018c2ecf20Sopenharmony_ci					newbus->firstMem = new_mem;
3028c2ecf20Sopenharmony_ci					++newbus->needMemUpdate;
3038c2ecf20Sopenharmony_ci					new_mem->rangeno = -1;
3048c2ecf20Sopenharmony_ci				}
3058c2ecf20Sopenharmony_ci				debug("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
3088c2ecf20Sopenharmony_ci				/* PFMemory resource */
3098c2ecf20Sopenharmony_ci				new_pfmem = alloc_resources(curr);
3108c2ecf20Sopenharmony_ci				if (!new_pfmem)
3118c2ecf20Sopenharmony_ci					return -ENOMEM;
3128c2ecf20Sopenharmony_ci				new_pfmem->type = PFMEM;
3138c2ecf20Sopenharmony_ci				new_pfmem->fromMem = 0;
3148c2ecf20Sopenharmony_ci				if (ibmphp_add_resource(new_pfmem) < 0) {
3158c2ecf20Sopenharmony_ci					newbus = alloc_error_bus(curr, 0, 0);
3168c2ecf20Sopenharmony_ci					if (!newbus)
3178c2ecf20Sopenharmony_ci						return -ENOMEM;
3188c2ecf20Sopenharmony_ci					newbus->firstPFMem = new_pfmem;
3198c2ecf20Sopenharmony_ci					++newbus->needPFMemUpdate;
3208c2ecf20Sopenharmony_ci					new_pfmem->rangeno = -1;
3218c2ecf20Sopenharmony_ci				}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci				debug("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end);
3248c2ecf20Sopenharmony_ci			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
3258c2ecf20Sopenharmony_ci				/* IO resource */
3268c2ecf20Sopenharmony_ci				new_io = alloc_resources(curr);
3278c2ecf20Sopenharmony_ci				if (!new_io)
3288c2ecf20Sopenharmony_ci					return -ENOMEM;
3298c2ecf20Sopenharmony_ci				new_io->type = IO;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci				/*
3328c2ecf20Sopenharmony_ci				 * if it didn't find the bus, means PCI dev
3338c2ecf20Sopenharmony_ci				 * came b4 the Primary Bus info, so need to
3348c2ecf20Sopenharmony_ci				 * create a bus rangeno becomes a problem...
3358c2ecf20Sopenharmony_ci				 * Can assign a -1 and then update once the
3368c2ecf20Sopenharmony_ci				 * range actually appears...
3378c2ecf20Sopenharmony_ci				 */
3388c2ecf20Sopenharmony_ci				if (ibmphp_add_resource(new_io) < 0) {
3398c2ecf20Sopenharmony_ci					newbus = alloc_error_bus(curr, 0, 0);
3408c2ecf20Sopenharmony_ci					if (!newbus)
3418c2ecf20Sopenharmony_ci						return -ENOMEM;
3428c2ecf20Sopenharmony_ci					newbus->firstIO = new_io;
3438c2ecf20Sopenharmony_ci					++newbus->needIOUpdate;
3448c2ecf20Sopenharmony_ci					new_io->rangeno = -1;
3458c2ecf20Sopenharmony_ci				}
3468c2ecf20Sopenharmony_ci				debug("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end);
3478c2ecf20Sopenharmony_ci			}
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	list_for_each_entry(bus_cur, &gbuses, bus_list) {
3528c2ecf20Sopenharmony_ci		/* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */
3538c2ecf20Sopenharmony_ci		rc = update_bridge_ranges(&bus_cur);
3548c2ecf20Sopenharmony_ci		if (rc)
3558c2ecf20Sopenharmony_ci			return rc;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	return once_over();	/* This is to align ranges (so no -1) */
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/********************************************************************************
3618c2ecf20Sopenharmony_ci * This function adds a range into a sorted list of ranges per bus for a particular
3628c2ecf20Sopenharmony_ci * range type, it then calls another routine to update the range numbers on the
3638c2ecf20Sopenharmony_ci * pci devices' resources for the appropriate resource
3648c2ecf20Sopenharmony_ci *
3658c2ecf20Sopenharmony_ci * Input: type of the resource, range to add, current bus
3668c2ecf20Sopenharmony_ci * Output: 0 or -1, bus and range ptrs
3678c2ecf20Sopenharmony_ci ********************************************************************************/
3688c2ecf20Sopenharmony_cistatic int add_bus_range(int type, struct range_node *range, struct bus_node *bus_cur)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct range_node *range_cur = NULL;
3718c2ecf20Sopenharmony_ci	struct range_node *range_prev;
3728c2ecf20Sopenharmony_ci	int count = 0, i_init;
3738c2ecf20Sopenharmony_ci	int noRanges = 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	switch (type) {
3768c2ecf20Sopenharmony_ci		case MEM:
3778c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeMem;
3788c2ecf20Sopenharmony_ci			noRanges = bus_cur->noMemRanges;
3798c2ecf20Sopenharmony_ci			break;
3808c2ecf20Sopenharmony_ci		case PFMEM:
3818c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangePFMem;
3828c2ecf20Sopenharmony_ci			noRanges = bus_cur->noPFMemRanges;
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		case IO:
3858c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeIO;
3868c2ecf20Sopenharmony_ci			noRanges = bus_cur->noIORanges;
3878c2ecf20Sopenharmony_ci			break;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	range_prev = NULL;
3918c2ecf20Sopenharmony_ci	while (range_cur) {
3928c2ecf20Sopenharmony_ci		if (range->start < range_cur->start)
3938c2ecf20Sopenharmony_ci			break;
3948c2ecf20Sopenharmony_ci		range_prev = range_cur;
3958c2ecf20Sopenharmony_ci		range_cur = range_cur->next;
3968c2ecf20Sopenharmony_ci		count = count + 1;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci	if (!count) {
3998c2ecf20Sopenharmony_ci		/* our range will go at the beginning of the list */
4008c2ecf20Sopenharmony_ci		switch (type) {
4018c2ecf20Sopenharmony_ci			case MEM:
4028c2ecf20Sopenharmony_ci				bus_cur->rangeMem = range;
4038c2ecf20Sopenharmony_ci				break;
4048c2ecf20Sopenharmony_ci			case PFMEM:
4058c2ecf20Sopenharmony_ci				bus_cur->rangePFMem = range;
4068c2ecf20Sopenharmony_ci				break;
4078c2ecf20Sopenharmony_ci			case IO:
4088c2ecf20Sopenharmony_ci				bus_cur->rangeIO = range;
4098c2ecf20Sopenharmony_ci				break;
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci		range->next = range_cur;
4128c2ecf20Sopenharmony_ci		range->rangeno = 1;
4138c2ecf20Sopenharmony_ci		i_init = 0;
4148c2ecf20Sopenharmony_ci	} else if (!range_cur) {
4158c2ecf20Sopenharmony_ci		/* our range will go at the end of the list */
4168c2ecf20Sopenharmony_ci		range->next = NULL;
4178c2ecf20Sopenharmony_ci		range_prev->next = range;
4188c2ecf20Sopenharmony_ci		range->rangeno = range_prev->rangeno + 1;
4198c2ecf20Sopenharmony_ci		return 0;
4208c2ecf20Sopenharmony_ci	} else {
4218c2ecf20Sopenharmony_ci		/* the range is in the middle */
4228c2ecf20Sopenharmony_ci		range_prev->next = range;
4238c2ecf20Sopenharmony_ci		range->next = range_cur;
4248c2ecf20Sopenharmony_ci		range->rangeno = range_cur->rangeno;
4258c2ecf20Sopenharmony_ci		i_init = range_prev->rangeno;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	for (count = i_init; count < noRanges; ++count) {
4298c2ecf20Sopenharmony_ci		++range_cur->rangeno;
4308c2ecf20Sopenharmony_ci		range_cur = range_cur->next;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	update_resources(bus_cur, type, i_init + 1);
4348c2ecf20Sopenharmony_ci	return 0;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/*******************************************************************************
4388c2ecf20Sopenharmony_ci * This routine goes through the list of resources of type 'type' and updates
4398c2ecf20Sopenharmony_ci * the range numbers that they correspond to.  It was called from add_bus_range fnc
4408c2ecf20Sopenharmony_ci *
4418c2ecf20Sopenharmony_ci * Input: bus, type of the resource, the rangeno starting from which to update
4428c2ecf20Sopenharmony_ci ******************************************************************************/
4438c2ecf20Sopenharmony_cistatic void update_resources(struct bus_node *bus_cur, int type, int rangeno)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	struct resource_node *res = NULL;
4468c2ecf20Sopenharmony_ci	u8 eol = 0;	/* end of list indicator */
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	switch (type) {
4498c2ecf20Sopenharmony_ci		case MEM:
4508c2ecf20Sopenharmony_ci			if (bus_cur->firstMem)
4518c2ecf20Sopenharmony_ci				res = bus_cur->firstMem;
4528c2ecf20Sopenharmony_ci			break;
4538c2ecf20Sopenharmony_ci		case PFMEM:
4548c2ecf20Sopenharmony_ci			if (bus_cur->firstPFMem)
4558c2ecf20Sopenharmony_ci				res = bus_cur->firstPFMem;
4568c2ecf20Sopenharmony_ci			break;
4578c2ecf20Sopenharmony_ci		case IO:
4588c2ecf20Sopenharmony_ci			if (bus_cur->firstIO)
4598c2ecf20Sopenharmony_ci				res = bus_cur->firstIO;
4608c2ecf20Sopenharmony_ci			break;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (res) {
4648c2ecf20Sopenharmony_ci		while (res) {
4658c2ecf20Sopenharmony_ci			if (res->rangeno == rangeno)
4668c2ecf20Sopenharmony_ci				break;
4678c2ecf20Sopenharmony_ci			if (res->next)
4688c2ecf20Sopenharmony_ci				res = res->next;
4698c2ecf20Sopenharmony_ci			else if (res->nextRange)
4708c2ecf20Sopenharmony_ci				res = res->nextRange;
4718c2ecf20Sopenharmony_ci			else {
4728c2ecf20Sopenharmony_ci				eol = 1;
4738c2ecf20Sopenharmony_ci				break;
4748c2ecf20Sopenharmony_ci			}
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		if (!eol) {
4788c2ecf20Sopenharmony_ci			/* found the range */
4798c2ecf20Sopenharmony_ci			while (res) {
4808c2ecf20Sopenharmony_ci				++res->rangeno;
4818c2ecf20Sopenharmony_ci				res = res->next;
4828c2ecf20Sopenharmony_ci			}
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic void fix_me(struct resource_node *res, struct bus_node *bus_cur, struct range_node *range)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	char *str = "";
4908c2ecf20Sopenharmony_ci	switch (res->type) {
4918c2ecf20Sopenharmony_ci		case IO:
4928c2ecf20Sopenharmony_ci			str = "io";
4938c2ecf20Sopenharmony_ci			break;
4948c2ecf20Sopenharmony_ci		case MEM:
4958c2ecf20Sopenharmony_ci			str = "mem";
4968c2ecf20Sopenharmony_ci			break;
4978c2ecf20Sopenharmony_ci		case PFMEM:
4988c2ecf20Sopenharmony_ci			str = "pfmem";
4998c2ecf20Sopenharmony_ci			break;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	while (res) {
5038c2ecf20Sopenharmony_ci		if (res->rangeno == -1) {
5048c2ecf20Sopenharmony_ci			while (range) {
5058c2ecf20Sopenharmony_ci				if ((res->start >= range->start) && (res->end <= range->end)) {
5068c2ecf20Sopenharmony_ci					res->rangeno = range->rangeno;
5078c2ecf20Sopenharmony_ci					debug("%s->rangeno in fix_resources is %d\n", str, res->rangeno);
5088c2ecf20Sopenharmony_ci					switch (res->type) {
5098c2ecf20Sopenharmony_ci						case IO:
5108c2ecf20Sopenharmony_ci							--bus_cur->needIOUpdate;
5118c2ecf20Sopenharmony_ci							break;
5128c2ecf20Sopenharmony_ci						case MEM:
5138c2ecf20Sopenharmony_ci							--bus_cur->needMemUpdate;
5148c2ecf20Sopenharmony_ci							break;
5158c2ecf20Sopenharmony_ci						case PFMEM:
5168c2ecf20Sopenharmony_ci							--bus_cur->needPFMemUpdate;
5178c2ecf20Sopenharmony_ci							break;
5188c2ecf20Sopenharmony_ci					}
5198c2ecf20Sopenharmony_ci					break;
5208c2ecf20Sopenharmony_ci				}
5218c2ecf20Sopenharmony_ci				range = range->next;
5228c2ecf20Sopenharmony_ci			}
5238c2ecf20Sopenharmony_ci		}
5248c2ecf20Sopenharmony_ci		if (res->next)
5258c2ecf20Sopenharmony_ci			res = res->next;
5268c2ecf20Sopenharmony_ci		else
5278c2ecf20Sopenharmony_ci			res = res->nextRange;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci/*****************************************************************************
5338c2ecf20Sopenharmony_ci * This routine reassigns the range numbers to the resources that had a -1
5348c2ecf20Sopenharmony_ci * This case can happen only if upon initialization, resources taken by pci dev
5358c2ecf20Sopenharmony_ci * appear in EBDA before the resources allocated for that bus, since we don't
5368c2ecf20Sopenharmony_ci * know the range, we assign -1, and this routine is called after a new range
5378c2ecf20Sopenharmony_ci * is assigned to see the resources with unknown range belong to the added range
5388c2ecf20Sopenharmony_ci *
5398c2ecf20Sopenharmony_ci * Input: current bus
5408c2ecf20Sopenharmony_ci * Output: none, list of resources for that bus are fixed if can be
5418c2ecf20Sopenharmony_ci *******************************************************************************/
5428c2ecf20Sopenharmony_cistatic void fix_resources(struct bus_node *bus_cur)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	struct range_node *range;
5458c2ecf20Sopenharmony_ci	struct resource_node *res;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	debug("%s - bus_cur->busno = %d\n", __func__, bus_cur->busno);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (bus_cur->needIOUpdate) {
5508c2ecf20Sopenharmony_ci		res = bus_cur->firstIO;
5518c2ecf20Sopenharmony_ci		range = bus_cur->rangeIO;
5528c2ecf20Sopenharmony_ci		fix_me(res, bus_cur, range);
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	if (bus_cur->needMemUpdate) {
5558c2ecf20Sopenharmony_ci		res = bus_cur->firstMem;
5568c2ecf20Sopenharmony_ci		range = bus_cur->rangeMem;
5578c2ecf20Sopenharmony_ci		fix_me(res, bus_cur, range);
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci	if (bus_cur->needPFMemUpdate) {
5608c2ecf20Sopenharmony_ci		res = bus_cur->firstPFMem;
5618c2ecf20Sopenharmony_ci		range = bus_cur->rangePFMem;
5628c2ecf20Sopenharmony_ci		fix_me(res, bus_cur, range);
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci/*******************************************************************************
5678c2ecf20Sopenharmony_ci * This routine adds a resource to the list of resources to the appropriate bus
5688c2ecf20Sopenharmony_ci * based on their resource type and sorted by their starting addresses.  It assigns
5698c2ecf20Sopenharmony_ci * the ptrs to next and nextRange if needed.
5708c2ecf20Sopenharmony_ci *
5718c2ecf20Sopenharmony_ci * Input: resource ptr
5728c2ecf20Sopenharmony_ci * Output: ptrs assigned (to the node)
5738c2ecf20Sopenharmony_ci * 0 or -1
5748c2ecf20Sopenharmony_ci *******************************************************************************/
5758c2ecf20Sopenharmony_ciint ibmphp_add_resource(struct resource_node *res)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	struct resource_node *res_cur;
5788c2ecf20Sopenharmony_ci	struct resource_node *res_prev;
5798c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
5808c2ecf20Sopenharmony_ci	struct range_node *range_cur = NULL;
5818c2ecf20Sopenharmony_ci	struct resource_node *res_start = NULL;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	debug("%s - enter\n", __func__);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (!res) {
5868c2ecf20Sopenharmony_ci		err("NULL passed to add\n");
5878c2ecf20Sopenharmony_ci		return -ENODEV;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	bus_cur = find_bus_wprev(res->busno, NULL, 0);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (!bus_cur) {
5938c2ecf20Sopenharmony_ci		/* didn't find a bus, something's wrong!!! */
5948c2ecf20Sopenharmony_ci		debug("no bus in the system, either pci_dev's wrong or allocation failed\n");
5958c2ecf20Sopenharmony_ci		return -ENODEV;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* Normal case */
5998c2ecf20Sopenharmony_ci	switch (res->type) {
6008c2ecf20Sopenharmony_ci		case IO:
6018c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeIO;
6028c2ecf20Sopenharmony_ci			res_start = bus_cur->firstIO;
6038c2ecf20Sopenharmony_ci			break;
6048c2ecf20Sopenharmony_ci		case MEM:
6058c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeMem;
6068c2ecf20Sopenharmony_ci			res_start = bus_cur->firstMem;
6078c2ecf20Sopenharmony_ci			break;
6088c2ecf20Sopenharmony_ci		case PFMEM:
6098c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangePFMem;
6108c2ecf20Sopenharmony_ci			res_start = bus_cur->firstPFMem;
6118c2ecf20Sopenharmony_ci			break;
6128c2ecf20Sopenharmony_ci		default:
6138c2ecf20Sopenharmony_ci			err("cannot read the type of the resource to add... problem\n");
6148c2ecf20Sopenharmony_ci			return -EINVAL;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci	while (range_cur) {
6178c2ecf20Sopenharmony_ci		if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) {
6188c2ecf20Sopenharmony_ci			res->rangeno = range_cur->rangeno;
6198c2ecf20Sopenharmony_ci			break;
6208c2ecf20Sopenharmony_ci		}
6218c2ecf20Sopenharmony_ci		range_cur = range_cur->next;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6258c2ecf20Sopenharmony_ci	 * this is again the case of rangeno = -1
6268c2ecf20Sopenharmony_ci	 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6278c2ecf20Sopenharmony_ci	 */
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (!range_cur) {
6308c2ecf20Sopenharmony_ci		switch (res->type) {
6318c2ecf20Sopenharmony_ci			case IO:
6328c2ecf20Sopenharmony_ci				++bus_cur->needIOUpdate;
6338c2ecf20Sopenharmony_ci				break;
6348c2ecf20Sopenharmony_ci			case MEM:
6358c2ecf20Sopenharmony_ci				++bus_cur->needMemUpdate;
6368c2ecf20Sopenharmony_ci				break;
6378c2ecf20Sopenharmony_ci			case PFMEM:
6388c2ecf20Sopenharmony_ci				++bus_cur->needPFMemUpdate;
6398c2ecf20Sopenharmony_ci				break;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci		res->rangeno = -1;
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	debug("The range is %d\n", res->rangeno);
6458c2ecf20Sopenharmony_ci	if (!res_start) {
6468c2ecf20Sopenharmony_ci		/* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */
6478c2ecf20Sopenharmony_ci		switch (res->type) {
6488c2ecf20Sopenharmony_ci			case IO:
6498c2ecf20Sopenharmony_ci				bus_cur->firstIO = res;
6508c2ecf20Sopenharmony_ci				break;
6518c2ecf20Sopenharmony_ci			case MEM:
6528c2ecf20Sopenharmony_ci				bus_cur->firstMem = res;
6538c2ecf20Sopenharmony_ci				break;
6548c2ecf20Sopenharmony_ci			case PFMEM:
6558c2ecf20Sopenharmony_ci				bus_cur->firstPFMem = res;
6568c2ecf20Sopenharmony_ci				break;
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci		res->next = NULL;
6598c2ecf20Sopenharmony_ci		res->nextRange = NULL;
6608c2ecf20Sopenharmony_ci	} else {
6618c2ecf20Sopenharmony_ci		res_cur = res_start;
6628c2ecf20Sopenharmony_ci		res_prev = NULL;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci		debug("res_cur->rangeno is %d\n", res_cur->rangeno);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		while (res_cur) {
6678c2ecf20Sopenharmony_ci			if (res_cur->rangeno >= res->rangeno)
6688c2ecf20Sopenharmony_ci				break;
6698c2ecf20Sopenharmony_ci			res_prev = res_cur;
6708c2ecf20Sopenharmony_ci			if (res_cur->next)
6718c2ecf20Sopenharmony_ci				res_cur = res_cur->next;
6728c2ecf20Sopenharmony_ci			else
6738c2ecf20Sopenharmony_ci				res_cur = res_cur->nextRange;
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci		if (!res_cur) {
6778c2ecf20Sopenharmony_ci			/* at the end of the resource list */
6788c2ecf20Sopenharmony_ci			debug("i should be here, [%x - %x]\n", res->start, res->end);
6798c2ecf20Sopenharmony_ci			res_prev->nextRange = res;
6808c2ecf20Sopenharmony_ci			res->next = NULL;
6818c2ecf20Sopenharmony_ci			res->nextRange = NULL;
6828c2ecf20Sopenharmony_ci		} else if (res_cur->rangeno == res->rangeno) {
6838c2ecf20Sopenharmony_ci			/* in the same range */
6848c2ecf20Sopenharmony_ci			while (res_cur) {
6858c2ecf20Sopenharmony_ci				if (res->start < res_cur->start)
6868c2ecf20Sopenharmony_ci					break;
6878c2ecf20Sopenharmony_ci				res_prev = res_cur;
6888c2ecf20Sopenharmony_ci				res_cur = res_cur->next;
6898c2ecf20Sopenharmony_ci			}
6908c2ecf20Sopenharmony_ci			if (!res_cur) {
6918c2ecf20Sopenharmony_ci				/* the last resource in this range */
6928c2ecf20Sopenharmony_ci				res_prev->next = res;
6938c2ecf20Sopenharmony_ci				res->next = NULL;
6948c2ecf20Sopenharmony_ci				res->nextRange = res_prev->nextRange;
6958c2ecf20Sopenharmony_ci				res_prev->nextRange = NULL;
6968c2ecf20Sopenharmony_ci			} else if (res->start < res_cur->start) {
6978c2ecf20Sopenharmony_ci				/* at the beginning or middle of the range */
6988c2ecf20Sopenharmony_ci				if (!res_prev)	{
6998c2ecf20Sopenharmony_ci					switch (res->type) {
7008c2ecf20Sopenharmony_ci						case IO:
7018c2ecf20Sopenharmony_ci							bus_cur->firstIO = res;
7028c2ecf20Sopenharmony_ci							break;
7038c2ecf20Sopenharmony_ci						case MEM:
7048c2ecf20Sopenharmony_ci							bus_cur->firstMem = res;
7058c2ecf20Sopenharmony_ci							break;
7068c2ecf20Sopenharmony_ci						case PFMEM:
7078c2ecf20Sopenharmony_ci							bus_cur->firstPFMem = res;
7088c2ecf20Sopenharmony_ci							break;
7098c2ecf20Sopenharmony_ci					}
7108c2ecf20Sopenharmony_ci				} else if (res_prev->rangeno == res_cur->rangeno)
7118c2ecf20Sopenharmony_ci					res_prev->next = res;
7128c2ecf20Sopenharmony_ci				else
7138c2ecf20Sopenharmony_ci					res_prev->nextRange = res;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci				res->next = res_cur;
7168c2ecf20Sopenharmony_ci				res->nextRange = NULL;
7178c2ecf20Sopenharmony_ci			}
7188c2ecf20Sopenharmony_ci		} else {
7198c2ecf20Sopenharmony_ci			/* this is the case where it is 1st occurrence of the range */
7208c2ecf20Sopenharmony_ci			if (!res_prev) {
7218c2ecf20Sopenharmony_ci				/* at the beginning of the resource list */
7228c2ecf20Sopenharmony_ci				res->next = NULL;
7238c2ecf20Sopenharmony_ci				switch (res->type) {
7248c2ecf20Sopenharmony_ci					case IO:
7258c2ecf20Sopenharmony_ci						res->nextRange = bus_cur->firstIO;
7268c2ecf20Sopenharmony_ci						bus_cur->firstIO = res;
7278c2ecf20Sopenharmony_ci						break;
7288c2ecf20Sopenharmony_ci					case MEM:
7298c2ecf20Sopenharmony_ci						res->nextRange = bus_cur->firstMem;
7308c2ecf20Sopenharmony_ci						bus_cur->firstMem = res;
7318c2ecf20Sopenharmony_ci						break;
7328c2ecf20Sopenharmony_ci					case PFMEM:
7338c2ecf20Sopenharmony_ci						res->nextRange = bus_cur->firstPFMem;
7348c2ecf20Sopenharmony_ci						bus_cur->firstPFMem = res;
7358c2ecf20Sopenharmony_ci						break;
7368c2ecf20Sopenharmony_ci				}
7378c2ecf20Sopenharmony_ci			} else if (res_cur->rangeno > res->rangeno) {
7388c2ecf20Sopenharmony_ci				/* in the middle of the resource list */
7398c2ecf20Sopenharmony_ci				res_prev->nextRange = res;
7408c2ecf20Sopenharmony_ci				res->next = NULL;
7418c2ecf20Sopenharmony_ci				res->nextRange = res_cur;
7428c2ecf20Sopenharmony_ci			}
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	debug("%s - exit\n", __func__);
7478c2ecf20Sopenharmony_ci	return 0;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci/****************************************************************************
7518c2ecf20Sopenharmony_ci * This routine will remove the resource from the list of resources
7528c2ecf20Sopenharmony_ci *
7538c2ecf20Sopenharmony_ci * Input: io, mem, and/or pfmem resource to be deleted
7548c2ecf20Sopenharmony_ci * Output: modified resource list
7558c2ecf20Sopenharmony_ci *        0 or error code
7568c2ecf20Sopenharmony_ci ****************************************************************************/
7578c2ecf20Sopenharmony_ciint ibmphp_remove_resource(struct resource_node *res)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
7608c2ecf20Sopenharmony_ci	struct resource_node *res_cur = NULL;
7618c2ecf20Sopenharmony_ci	struct resource_node *res_prev;
7628c2ecf20Sopenharmony_ci	struct resource_node *mem_cur;
7638c2ecf20Sopenharmony_ci	char *type = "";
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	if (!res)  {
7668c2ecf20Sopenharmony_ci		err("resource to remove is NULL\n");
7678c2ecf20Sopenharmony_ci		return -ENODEV;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	bus_cur = find_bus_wprev(res->busno, NULL, 0);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	if (!bus_cur) {
7738c2ecf20Sopenharmony_ci		err("cannot find corresponding bus of the io resource to remove  bailing out...\n");
7748c2ecf20Sopenharmony_ci		return -ENODEV;
7758c2ecf20Sopenharmony_ci	}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	switch (res->type) {
7788c2ecf20Sopenharmony_ci		case IO:
7798c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstIO;
7808c2ecf20Sopenharmony_ci			type = "io";
7818c2ecf20Sopenharmony_ci			break;
7828c2ecf20Sopenharmony_ci		case MEM:
7838c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstMem;
7848c2ecf20Sopenharmony_ci			type = "mem";
7858c2ecf20Sopenharmony_ci			break;
7868c2ecf20Sopenharmony_ci		case PFMEM:
7878c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstPFMem;
7888c2ecf20Sopenharmony_ci			type = "pfmem";
7898c2ecf20Sopenharmony_ci			break;
7908c2ecf20Sopenharmony_ci		default:
7918c2ecf20Sopenharmony_ci			err("unknown type for resource to remove\n");
7928c2ecf20Sopenharmony_ci			return -EINVAL;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci	res_prev = NULL;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	while (res_cur) {
7978c2ecf20Sopenharmony_ci		if ((res_cur->start == res->start) && (res_cur->end == res->end))
7988c2ecf20Sopenharmony_ci			break;
7998c2ecf20Sopenharmony_ci		res_prev = res_cur;
8008c2ecf20Sopenharmony_ci		if (res_cur->next)
8018c2ecf20Sopenharmony_ci			res_cur = res_cur->next;
8028c2ecf20Sopenharmony_ci		else
8038c2ecf20Sopenharmony_ci			res_cur = res_cur->nextRange;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (!res_cur) {
8078c2ecf20Sopenharmony_ci		if (res->type == PFMEM) {
8088c2ecf20Sopenharmony_ci			/*
8098c2ecf20Sopenharmony_ci			 * case where pfmem might be in the PFMemFromMem list
8108c2ecf20Sopenharmony_ci			 * so will also need to remove the corresponding mem
8118c2ecf20Sopenharmony_ci			 * entry
8128c2ecf20Sopenharmony_ci			 */
8138c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstPFMemFromMem;
8148c2ecf20Sopenharmony_ci			res_prev = NULL;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci			while (res_cur) {
8178c2ecf20Sopenharmony_ci				if ((res_cur->start == res->start) && (res_cur->end == res->end)) {
8188c2ecf20Sopenharmony_ci					mem_cur = bus_cur->firstMem;
8198c2ecf20Sopenharmony_ci					while (mem_cur) {
8208c2ecf20Sopenharmony_ci						if ((mem_cur->start == res_cur->start)
8218c2ecf20Sopenharmony_ci						    && (mem_cur->end == res_cur->end))
8228c2ecf20Sopenharmony_ci							break;
8238c2ecf20Sopenharmony_ci						if (mem_cur->next)
8248c2ecf20Sopenharmony_ci							mem_cur = mem_cur->next;
8258c2ecf20Sopenharmony_ci						else
8268c2ecf20Sopenharmony_ci							mem_cur = mem_cur->nextRange;
8278c2ecf20Sopenharmony_ci					}
8288c2ecf20Sopenharmony_ci					if (!mem_cur) {
8298c2ecf20Sopenharmony_ci						err("cannot find corresponding mem node for pfmem...\n");
8308c2ecf20Sopenharmony_ci						return -EINVAL;
8318c2ecf20Sopenharmony_ci					}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci					ibmphp_remove_resource(mem_cur);
8348c2ecf20Sopenharmony_ci					if (!res_prev)
8358c2ecf20Sopenharmony_ci						bus_cur->firstPFMemFromMem = res_cur->next;
8368c2ecf20Sopenharmony_ci					else
8378c2ecf20Sopenharmony_ci						res_prev->next = res_cur->next;
8388c2ecf20Sopenharmony_ci					kfree(res_cur);
8398c2ecf20Sopenharmony_ci					return 0;
8408c2ecf20Sopenharmony_ci				}
8418c2ecf20Sopenharmony_ci				res_prev = res_cur;
8428c2ecf20Sopenharmony_ci				if (res_cur->next)
8438c2ecf20Sopenharmony_ci					res_cur = res_cur->next;
8448c2ecf20Sopenharmony_ci				else
8458c2ecf20Sopenharmony_ci					res_cur = res_cur->nextRange;
8468c2ecf20Sopenharmony_ci			}
8478c2ecf20Sopenharmony_ci			if (!res_cur) {
8488c2ecf20Sopenharmony_ci				err("cannot find pfmem to delete...\n");
8498c2ecf20Sopenharmony_ci				return -EINVAL;
8508c2ecf20Sopenharmony_ci			}
8518c2ecf20Sopenharmony_ci		} else {
8528c2ecf20Sopenharmony_ci			err("the %s resource is not in the list to be deleted...\n", type);
8538c2ecf20Sopenharmony_ci			return -EINVAL;
8548c2ecf20Sopenharmony_ci		}
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci	if (!res_prev) {
8578c2ecf20Sopenharmony_ci		/* first device to be deleted */
8588c2ecf20Sopenharmony_ci		if (res_cur->next) {
8598c2ecf20Sopenharmony_ci			switch (res->type) {
8608c2ecf20Sopenharmony_ci				case IO:
8618c2ecf20Sopenharmony_ci					bus_cur->firstIO = res_cur->next;
8628c2ecf20Sopenharmony_ci					break;
8638c2ecf20Sopenharmony_ci				case MEM:
8648c2ecf20Sopenharmony_ci					bus_cur->firstMem = res_cur->next;
8658c2ecf20Sopenharmony_ci					break;
8668c2ecf20Sopenharmony_ci				case PFMEM:
8678c2ecf20Sopenharmony_ci					bus_cur->firstPFMem = res_cur->next;
8688c2ecf20Sopenharmony_ci					break;
8698c2ecf20Sopenharmony_ci			}
8708c2ecf20Sopenharmony_ci		} else if (res_cur->nextRange) {
8718c2ecf20Sopenharmony_ci			switch (res->type) {
8728c2ecf20Sopenharmony_ci				case IO:
8738c2ecf20Sopenharmony_ci					bus_cur->firstIO = res_cur->nextRange;
8748c2ecf20Sopenharmony_ci					break;
8758c2ecf20Sopenharmony_ci				case MEM:
8768c2ecf20Sopenharmony_ci					bus_cur->firstMem = res_cur->nextRange;
8778c2ecf20Sopenharmony_ci					break;
8788c2ecf20Sopenharmony_ci				case PFMEM:
8798c2ecf20Sopenharmony_ci					bus_cur->firstPFMem = res_cur->nextRange;
8808c2ecf20Sopenharmony_ci					break;
8818c2ecf20Sopenharmony_ci			}
8828c2ecf20Sopenharmony_ci		} else {
8838c2ecf20Sopenharmony_ci			switch (res->type) {
8848c2ecf20Sopenharmony_ci				case IO:
8858c2ecf20Sopenharmony_ci					bus_cur->firstIO = NULL;
8868c2ecf20Sopenharmony_ci					break;
8878c2ecf20Sopenharmony_ci				case MEM:
8888c2ecf20Sopenharmony_ci					bus_cur->firstMem = NULL;
8898c2ecf20Sopenharmony_ci					break;
8908c2ecf20Sopenharmony_ci				case PFMEM:
8918c2ecf20Sopenharmony_ci					bus_cur->firstPFMem = NULL;
8928c2ecf20Sopenharmony_ci					break;
8938c2ecf20Sopenharmony_ci			}
8948c2ecf20Sopenharmony_ci		}
8958c2ecf20Sopenharmony_ci		kfree(res_cur);
8968c2ecf20Sopenharmony_ci		return 0;
8978c2ecf20Sopenharmony_ci	} else {
8988c2ecf20Sopenharmony_ci		if (res_cur->next) {
8998c2ecf20Sopenharmony_ci			if (res_prev->rangeno == res_cur->rangeno)
9008c2ecf20Sopenharmony_ci				res_prev->next = res_cur->next;
9018c2ecf20Sopenharmony_ci			else
9028c2ecf20Sopenharmony_ci				res_prev->nextRange = res_cur->next;
9038c2ecf20Sopenharmony_ci		} else if (res_cur->nextRange) {
9048c2ecf20Sopenharmony_ci			res_prev->next = NULL;
9058c2ecf20Sopenharmony_ci			res_prev->nextRange = res_cur->nextRange;
9068c2ecf20Sopenharmony_ci		} else {
9078c2ecf20Sopenharmony_ci			res_prev->next = NULL;
9088c2ecf20Sopenharmony_ci			res_prev->nextRange = NULL;
9098c2ecf20Sopenharmony_ci		}
9108c2ecf20Sopenharmony_ci		kfree(res_cur);
9118c2ecf20Sopenharmony_ci		return 0;
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return 0;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic struct range_node *find_range(struct bus_node *bus_cur, struct resource_node *res)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	struct range_node *range = NULL;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	switch (res->type) {
9228c2ecf20Sopenharmony_ci		case IO:
9238c2ecf20Sopenharmony_ci			range = bus_cur->rangeIO;
9248c2ecf20Sopenharmony_ci			break;
9258c2ecf20Sopenharmony_ci		case MEM:
9268c2ecf20Sopenharmony_ci			range = bus_cur->rangeMem;
9278c2ecf20Sopenharmony_ci			break;
9288c2ecf20Sopenharmony_ci		case PFMEM:
9298c2ecf20Sopenharmony_ci			range = bus_cur->rangePFMem;
9308c2ecf20Sopenharmony_ci			break;
9318c2ecf20Sopenharmony_ci		default:
9328c2ecf20Sopenharmony_ci			err("cannot read resource type in find_range\n");
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	while (range) {
9368c2ecf20Sopenharmony_ci		if (res->rangeno == range->rangeno)
9378c2ecf20Sopenharmony_ci			break;
9388c2ecf20Sopenharmony_ci		range = range->next;
9398c2ecf20Sopenharmony_ci	}
9408c2ecf20Sopenharmony_ci	return range;
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci/*****************************************************************************
9448c2ecf20Sopenharmony_ci * This routine will check to make sure the io/mem/pfmem->len that the device asked for
9458c2ecf20Sopenharmony_ci * can fit w/i our list of available IO/MEM/PFMEM resources.  If cannot, returns -EINVAL,
9468c2ecf20Sopenharmony_ci * otherwise, returns 0
9478c2ecf20Sopenharmony_ci *
9488c2ecf20Sopenharmony_ci * Input: resource
9498c2ecf20Sopenharmony_ci * Output: the correct start and end address are inputted into the resource node,
9508c2ecf20Sopenharmony_ci *        0 or -EINVAL
9518c2ecf20Sopenharmony_ci *****************************************************************************/
9528c2ecf20Sopenharmony_ciint ibmphp_check_resource(struct resource_node *res, u8 bridge)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
9558c2ecf20Sopenharmony_ci	struct range_node *range = NULL;
9568c2ecf20Sopenharmony_ci	struct resource_node *res_prev;
9578c2ecf20Sopenharmony_ci	struct resource_node *res_cur = NULL;
9588c2ecf20Sopenharmony_ci	u32 len_cur = 0, start_cur = 0, len_tmp = 0;
9598c2ecf20Sopenharmony_ci	int noranges = 0;
9608c2ecf20Sopenharmony_ci	u32 tmp_start;		/* this is to make sure start address is divisible by the length needed */
9618c2ecf20Sopenharmony_ci	u32 tmp_divide;
9628c2ecf20Sopenharmony_ci	u8 flag = 0;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (!res)
9658c2ecf20Sopenharmony_ci		return -EINVAL;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if (bridge) {
9688c2ecf20Sopenharmony_ci		/* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/
9698c2ecf20Sopenharmony_ci		if (res->type == IO)
9708c2ecf20Sopenharmony_ci			tmp_divide = IOBRIDGE;
9718c2ecf20Sopenharmony_ci		else
9728c2ecf20Sopenharmony_ci			tmp_divide = MEMBRIDGE;
9738c2ecf20Sopenharmony_ci	} else
9748c2ecf20Sopenharmony_ci		tmp_divide = res->len;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	bus_cur = find_bus_wprev(res->busno, NULL, 0);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	if (!bus_cur) {
9798c2ecf20Sopenharmony_ci		/* didn't find a bus, something's wrong!!! */
9808c2ecf20Sopenharmony_ci		debug("no bus in the system, either pci_dev's wrong or allocation failed\n");
9818c2ecf20Sopenharmony_ci		return -EINVAL;
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	debug("%s - enter\n", __func__);
9858c2ecf20Sopenharmony_ci	debug("bus_cur->busno is %d\n", bus_cur->busno);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	/* This is a quick fix to not mess up with the code very much.  i.e.,
9888c2ecf20Sopenharmony_ci	 * 2000-2fff, len = 1000, but when we compare, we need it to be fff */
9898c2ecf20Sopenharmony_ci	res->len -= 1;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	switch (res->type) {
9928c2ecf20Sopenharmony_ci		case IO:
9938c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstIO;
9948c2ecf20Sopenharmony_ci			noranges = bus_cur->noIORanges;
9958c2ecf20Sopenharmony_ci			break;
9968c2ecf20Sopenharmony_ci		case MEM:
9978c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstMem;
9988c2ecf20Sopenharmony_ci			noranges = bus_cur->noMemRanges;
9998c2ecf20Sopenharmony_ci			break;
10008c2ecf20Sopenharmony_ci		case PFMEM:
10018c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstPFMem;
10028c2ecf20Sopenharmony_ci			noranges = bus_cur->noPFMemRanges;
10038c2ecf20Sopenharmony_ci			break;
10048c2ecf20Sopenharmony_ci		default:
10058c2ecf20Sopenharmony_ci			err("wrong type of resource to check\n");
10068c2ecf20Sopenharmony_ci			return -EINVAL;
10078c2ecf20Sopenharmony_ci	}
10088c2ecf20Sopenharmony_ci	res_prev = NULL;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	while (res_cur) {
10118c2ecf20Sopenharmony_ci		range = find_range(bus_cur, res_cur);
10128c2ecf20Sopenharmony_ci		debug("%s - rangeno = %d\n", __func__, res_cur->rangeno);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		if (!range) {
10158c2ecf20Sopenharmony_ci			err("no range for the device exists... bailing out...\n");
10168c2ecf20Sopenharmony_ci			return -EINVAL;
10178c2ecf20Sopenharmony_ci		}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		/* found our range */
10208c2ecf20Sopenharmony_ci		if (!res_prev) {
10218c2ecf20Sopenharmony_ci			/* first time in the loop */
10228c2ecf20Sopenharmony_ci			len_tmp = res_cur->start - 1 - range->start;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci			if ((res_cur->start != range->start) && (len_tmp >= res->len)) {
10258c2ecf20Sopenharmony_ci				debug("len_tmp = %x\n", len_tmp);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci				if ((len_tmp < len_cur) || (len_cur == 0)) {
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci					if ((range->start % tmp_divide) == 0) {
10308c2ecf20Sopenharmony_ci						/* just perfect, starting address is divisible by length */
10318c2ecf20Sopenharmony_ci						flag = 1;
10328c2ecf20Sopenharmony_ci						len_cur = len_tmp;
10338c2ecf20Sopenharmony_ci						start_cur = range->start;
10348c2ecf20Sopenharmony_ci					} else {
10358c2ecf20Sopenharmony_ci						/* Needs adjusting */
10368c2ecf20Sopenharmony_ci						tmp_start = range->start;
10378c2ecf20Sopenharmony_ci						flag = 0;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci						while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
10408c2ecf20Sopenharmony_ci							if ((tmp_start % tmp_divide) == 0) {
10418c2ecf20Sopenharmony_ci								flag = 1;
10428c2ecf20Sopenharmony_ci								len_cur = len_tmp;
10438c2ecf20Sopenharmony_ci								start_cur = tmp_start;
10448c2ecf20Sopenharmony_ci								break;
10458c2ecf20Sopenharmony_ci							}
10468c2ecf20Sopenharmony_ci							tmp_start += tmp_divide - tmp_start % tmp_divide;
10478c2ecf20Sopenharmony_ci							if (tmp_start >= res_cur->start - 1)
10488c2ecf20Sopenharmony_ci								break;
10498c2ecf20Sopenharmony_ci						}
10508c2ecf20Sopenharmony_ci					}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci					if (flag && len_cur == res->len) {
10538c2ecf20Sopenharmony_ci						debug("but we are not here, right?\n");
10548c2ecf20Sopenharmony_ci						res->start = start_cur;
10558c2ecf20Sopenharmony_ci						res->len += 1; /* To restore the balance */
10568c2ecf20Sopenharmony_ci						res->end = res->start + res->len - 1;
10578c2ecf20Sopenharmony_ci						return 0;
10588c2ecf20Sopenharmony_ci					}
10598c2ecf20Sopenharmony_ci				}
10608c2ecf20Sopenharmony_ci			}
10618c2ecf20Sopenharmony_ci		}
10628c2ecf20Sopenharmony_ci		if (!res_cur->next) {
10638c2ecf20Sopenharmony_ci			/* last device on the range */
10648c2ecf20Sopenharmony_ci			len_tmp = range->end - (res_cur->end + 1);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci			if ((range->end != res_cur->end) && (len_tmp >= res->len)) {
10678c2ecf20Sopenharmony_ci				debug("len_tmp = %x\n", len_tmp);
10688c2ecf20Sopenharmony_ci				if ((len_tmp < len_cur) || (len_cur == 0)) {
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci					if (((res_cur->end + 1) % tmp_divide) == 0) {
10718c2ecf20Sopenharmony_ci						/* just perfect, starting address is divisible by length */
10728c2ecf20Sopenharmony_ci						flag = 1;
10738c2ecf20Sopenharmony_ci						len_cur = len_tmp;
10748c2ecf20Sopenharmony_ci						start_cur = res_cur->end + 1;
10758c2ecf20Sopenharmony_ci					} else {
10768c2ecf20Sopenharmony_ci						/* Needs adjusting */
10778c2ecf20Sopenharmony_ci						tmp_start = res_cur->end + 1;
10788c2ecf20Sopenharmony_ci						flag = 0;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci						while ((len_tmp = range->end - tmp_start) >= res->len) {
10818c2ecf20Sopenharmony_ci							if ((tmp_start % tmp_divide) == 0) {
10828c2ecf20Sopenharmony_ci								flag = 1;
10838c2ecf20Sopenharmony_ci								len_cur = len_tmp;
10848c2ecf20Sopenharmony_ci								start_cur = tmp_start;
10858c2ecf20Sopenharmony_ci								break;
10868c2ecf20Sopenharmony_ci							}
10878c2ecf20Sopenharmony_ci							tmp_start += tmp_divide - tmp_start % tmp_divide;
10888c2ecf20Sopenharmony_ci							if (tmp_start >= range->end)
10898c2ecf20Sopenharmony_ci								break;
10908c2ecf20Sopenharmony_ci						}
10918c2ecf20Sopenharmony_ci					}
10928c2ecf20Sopenharmony_ci					if (flag && len_cur == res->len) {
10938c2ecf20Sopenharmony_ci						res->start = start_cur;
10948c2ecf20Sopenharmony_ci						res->len += 1; /* To restore the balance */
10958c2ecf20Sopenharmony_ci						res->end = res->start + res->len - 1;
10968c2ecf20Sopenharmony_ci						return 0;
10978c2ecf20Sopenharmony_ci					}
10988c2ecf20Sopenharmony_ci				}
10998c2ecf20Sopenharmony_ci			}
11008c2ecf20Sopenharmony_ci		}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci		if (res_prev) {
11038c2ecf20Sopenharmony_ci			if (res_prev->rangeno != res_cur->rangeno) {
11048c2ecf20Sopenharmony_ci				/* 1st device on this range */
11058c2ecf20Sopenharmony_ci				len_tmp = res_cur->start - 1 - range->start;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci				if ((res_cur->start != range->start) &&	(len_tmp >= res->len)) {
11088c2ecf20Sopenharmony_ci					if ((len_tmp < len_cur) || (len_cur == 0)) {
11098c2ecf20Sopenharmony_ci						if ((range->start % tmp_divide) == 0) {
11108c2ecf20Sopenharmony_ci							/* just perfect, starting address is divisible by length */
11118c2ecf20Sopenharmony_ci							flag = 1;
11128c2ecf20Sopenharmony_ci							len_cur = len_tmp;
11138c2ecf20Sopenharmony_ci							start_cur = range->start;
11148c2ecf20Sopenharmony_ci						} else {
11158c2ecf20Sopenharmony_ci							/* Needs adjusting */
11168c2ecf20Sopenharmony_ci							tmp_start = range->start;
11178c2ecf20Sopenharmony_ci							flag = 0;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci							while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
11208c2ecf20Sopenharmony_ci								if ((tmp_start % tmp_divide) == 0) {
11218c2ecf20Sopenharmony_ci									flag = 1;
11228c2ecf20Sopenharmony_ci									len_cur = len_tmp;
11238c2ecf20Sopenharmony_ci									start_cur = tmp_start;
11248c2ecf20Sopenharmony_ci									break;
11258c2ecf20Sopenharmony_ci								}
11268c2ecf20Sopenharmony_ci								tmp_start += tmp_divide - tmp_start % tmp_divide;
11278c2ecf20Sopenharmony_ci								if (tmp_start >= res_cur->start - 1)
11288c2ecf20Sopenharmony_ci									break;
11298c2ecf20Sopenharmony_ci							}
11308c2ecf20Sopenharmony_ci						}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci						if (flag && len_cur == res->len) {
11338c2ecf20Sopenharmony_ci							res->start = start_cur;
11348c2ecf20Sopenharmony_ci							res->len += 1; /* To restore the balance */
11358c2ecf20Sopenharmony_ci							res->end = res->start + res->len - 1;
11368c2ecf20Sopenharmony_ci							return 0;
11378c2ecf20Sopenharmony_ci						}
11388c2ecf20Sopenharmony_ci					}
11398c2ecf20Sopenharmony_ci				}
11408c2ecf20Sopenharmony_ci			} else {
11418c2ecf20Sopenharmony_ci				/* in the same range */
11428c2ecf20Sopenharmony_ci				len_tmp = res_cur->start - 1 - res_prev->end - 1;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci				if (len_tmp >= res->len) {
11458c2ecf20Sopenharmony_ci					if ((len_tmp < len_cur) || (len_cur == 0)) {
11468c2ecf20Sopenharmony_ci						if (((res_prev->end + 1) % tmp_divide) == 0) {
11478c2ecf20Sopenharmony_ci							/* just perfect, starting address's divisible by length */
11488c2ecf20Sopenharmony_ci							flag = 1;
11498c2ecf20Sopenharmony_ci							len_cur = len_tmp;
11508c2ecf20Sopenharmony_ci							start_cur = res_prev->end + 1;
11518c2ecf20Sopenharmony_ci						} else {
11528c2ecf20Sopenharmony_ci							/* Needs adjusting */
11538c2ecf20Sopenharmony_ci							tmp_start = res_prev->end + 1;
11548c2ecf20Sopenharmony_ci							flag = 0;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci							while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
11578c2ecf20Sopenharmony_ci								if ((tmp_start % tmp_divide) == 0) {
11588c2ecf20Sopenharmony_ci									flag = 1;
11598c2ecf20Sopenharmony_ci									len_cur = len_tmp;
11608c2ecf20Sopenharmony_ci									start_cur = tmp_start;
11618c2ecf20Sopenharmony_ci									break;
11628c2ecf20Sopenharmony_ci								}
11638c2ecf20Sopenharmony_ci								tmp_start += tmp_divide - tmp_start % tmp_divide;
11648c2ecf20Sopenharmony_ci								if (tmp_start >= res_cur->start - 1)
11658c2ecf20Sopenharmony_ci									break;
11668c2ecf20Sopenharmony_ci							}
11678c2ecf20Sopenharmony_ci						}
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci						if (flag && len_cur == res->len) {
11708c2ecf20Sopenharmony_ci							res->start = start_cur;
11718c2ecf20Sopenharmony_ci							res->len += 1; /* To restore the balance */
11728c2ecf20Sopenharmony_ci							res->end = res->start + res->len - 1;
11738c2ecf20Sopenharmony_ci							return 0;
11748c2ecf20Sopenharmony_ci						}
11758c2ecf20Sopenharmony_ci					}
11768c2ecf20Sopenharmony_ci				}
11778c2ecf20Sopenharmony_ci			}
11788c2ecf20Sopenharmony_ci		}
11798c2ecf20Sopenharmony_ci		/* end if (res_prev) */
11808c2ecf20Sopenharmony_ci		res_prev = res_cur;
11818c2ecf20Sopenharmony_ci		if (res_cur->next)
11828c2ecf20Sopenharmony_ci			res_cur = res_cur->next;
11838c2ecf20Sopenharmony_ci		else
11848c2ecf20Sopenharmony_ci			res_cur = res_cur->nextRange;
11858c2ecf20Sopenharmony_ci	}	/* end of while */
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (!res_prev) {
11898c2ecf20Sopenharmony_ci		/* 1st device ever */
11908c2ecf20Sopenharmony_ci		/* need to find appropriate range */
11918c2ecf20Sopenharmony_ci		switch (res->type) {
11928c2ecf20Sopenharmony_ci			case IO:
11938c2ecf20Sopenharmony_ci				range = bus_cur->rangeIO;
11948c2ecf20Sopenharmony_ci				break;
11958c2ecf20Sopenharmony_ci			case MEM:
11968c2ecf20Sopenharmony_ci				range = bus_cur->rangeMem;
11978c2ecf20Sopenharmony_ci				break;
11988c2ecf20Sopenharmony_ci			case PFMEM:
11998c2ecf20Sopenharmony_ci				range = bus_cur->rangePFMem;
12008c2ecf20Sopenharmony_ci				break;
12018c2ecf20Sopenharmony_ci		}
12028c2ecf20Sopenharmony_ci		while (range) {
12038c2ecf20Sopenharmony_ci			len_tmp = range->end - range->start;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci			if (len_tmp >= res->len) {
12068c2ecf20Sopenharmony_ci				if ((len_tmp < len_cur) || (len_cur == 0)) {
12078c2ecf20Sopenharmony_ci					if ((range->start % tmp_divide) == 0) {
12088c2ecf20Sopenharmony_ci						/* just perfect, starting address's divisible by length */
12098c2ecf20Sopenharmony_ci						flag = 1;
12108c2ecf20Sopenharmony_ci						len_cur = len_tmp;
12118c2ecf20Sopenharmony_ci						start_cur = range->start;
12128c2ecf20Sopenharmony_ci					} else {
12138c2ecf20Sopenharmony_ci						/* Needs adjusting */
12148c2ecf20Sopenharmony_ci						tmp_start = range->start;
12158c2ecf20Sopenharmony_ci						flag = 0;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci						while ((len_tmp = range->end - tmp_start) >= res->len) {
12188c2ecf20Sopenharmony_ci							if ((tmp_start % tmp_divide) == 0) {
12198c2ecf20Sopenharmony_ci								flag = 1;
12208c2ecf20Sopenharmony_ci								len_cur = len_tmp;
12218c2ecf20Sopenharmony_ci								start_cur = tmp_start;
12228c2ecf20Sopenharmony_ci								break;
12238c2ecf20Sopenharmony_ci							}
12248c2ecf20Sopenharmony_ci							tmp_start += tmp_divide - tmp_start % tmp_divide;
12258c2ecf20Sopenharmony_ci							if (tmp_start >= range->end)
12268c2ecf20Sopenharmony_ci								break;
12278c2ecf20Sopenharmony_ci						}
12288c2ecf20Sopenharmony_ci					}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci					if (flag && len_cur == res->len) {
12318c2ecf20Sopenharmony_ci						res->start = start_cur;
12328c2ecf20Sopenharmony_ci						res->len += 1; /* To restore the balance */
12338c2ecf20Sopenharmony_ci						res->end = res->start + res->len - 1;
12348c2ecf20Sopenharmony_ci						return 0;
12358c2ecf20Sopenharmony_ci					}
12368c2ecf20Sopenharmony_ci				}
12378c2ecf20Sopenharmony_ci			}
12388c2ecf20Sopenharmony_ci			range = range->next;
12398c2ecf20Sopenharmony_ci		}		/* end of while */
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci		if ((!range) && (len_cur == 0)) {
12428c2ecf20Sopenharmony_ci			/* have gone through the list of devices and ranges and haven't found n.e.thing */
12438c2ecf20Sopenharmony_ci			err("no appropriate range.. bailing out...\n");
12448c2ecf20Sopenharmony_ci			return -EINVAL;
12458c2ecf20Sopenharmony_ci		} else if (len_cur) {
12468c2ecf20Sopenharmony_ci			res->start = start_cur;
12478c2ecf20Sopenharmony_ci			res->len += 1; /* To restore the balance */
12488c2ecf20Sopenharmony_ci			res->end = res->start + res->len - 1;
12498c2ecf20Sopenharmony_ci			return 0;
12508c2ecf20Sopenharmony_ci		}
12518c2ecf20Sopenharmony_ci	}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	if (!res_cur) {
12548c2ecf20Sopenharmony_ci		debug("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges);
12558c2ecf20Sopenharmony_ci		if (res_prev->rangeno < noranges) {
12568c2ecf20Sopenharmony_ci			/* if there're more ranges out there to check */
12578c2ecf20Sopenharmony_ci			switch (res->type) {
12588c2ecf20Sopenharmony_ci				case IO:
12598c2ecf20Sopenharmony_ci					range = bus_cur->rangeIO;
12608c2ecf20Sopenharmony_ci					break;
12618c2ecf20Sopenharmony_ci				case MEM:
12628c2ecf20Sopenharmony_ci					range = bus_cur->rangeMem;
12638c2ecf20Sopenharmony_ci					break;
12648c2ecf20Sopenharmony_ci				case PFMEM:
12658c2ecf20Sopenharmony_ci					range = bus_cur->rangePFMem;
12668c2ecf20Sopenharmony_ci					break;
12678c2ecf20Sopenharmony_ci			}
12688c2ecf20Sopenharmony_ci			while (range) {
12698c2ecf20Sopenharmony_ci				len_tmp = range->end - range->start;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci				if (len_tmp >= res->len) {
12728c2ecf20Sopenharmony_ci					if ((len_tmp < len_cur) || (len_cur == 0)) {
12738c2ecf20Sopenharmony_ci						if ((range->start % tmp_divide) == 0) {
12748c2ecf20Sopenharmony_ci							/* just perfect, starting address's divisible by length */
12758c2ecf20Sopenharmony_ci							flag = 1;
12768c2ecf20Sopenharmony_ci							len_cur = len_tmp;
12778c2ecf20Sopenharmony_ci							start_cur = range->start;
12788c2ecf20Sopenharmony_ci						} else {
12798c2ecf20Sopenharmony_ci							/* Needs adjusting */
12808c2ecf20Sopenharmony_ci							tmp_start = range->start;
12818c2ecf20Sopenharmony_ci							flag = 0;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci							while ((len_tmp = range->end - tmp_start) >= res->len) {
12848c2ecf20Sopenharmony_ci								if ((tmp_start % tmp_divide) == 0) {
12858c2ecf20Sopenharmony_ci									flag = 1;
12868c2ecf20Sopenharmony_ci									len_cur = len_tmp;
12878c2ecf20Sopenharmony_ci									start_cur = tmp_start;
12888c2ecf20Sopenharmony_ci									break;
12898c2ecf20Sopenharmony_ci								}
12908c2ecf20Sopenharmony_ci								tmp_start += tmp_divide - tmp_start % tmp_divide;
12918c2ecf20Sopenharmony_ci								if (tmp_start >= range->end)
12928c2ecf20Sopenharmony_ci									break;
12938c2ecf20Sopenharmony_ci							}
12948c2ecf20Sopenharmony_ci						}
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci						if (flag && len_cur == res->len) {
12978c2ecf20Sopenharmony_ci							res->start = start_cur;
12988c2ecf20Sopenharmony_ci							res->len += 1; /* To restore the balance */
12998c2ecf20Sopenharmony_ci							res->end = res->start + res->len - 1;
13008c2ecf20Sopenharmony_ci							return 0;
13018c2ecf20Sopenharmony_ci						}
13028c2ecf20Sopenharmony_ci					}
13038c2ecf20Sopenharmony_ci				}
13048c2ecf20Sopenharmony_ci				range = range->next;
13058c2ecf20Sopenharmony_ci			}	/* end of while */
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci			if ((!range) && (len_cur == 0)) {
13088c2ecf20Sopenharmony_ci				/* have gone through the list of devices and ranges and haven't found n.e.thing */
13098c2ecf20Sopenharmony_ci				err("no appropriate range.. bailing out...\n");
13108c2ecf20Sopenharmony_ci				return -EINVAL;
13118c2ecf20Sopenharmony_ci			} else if (len_cur) {
13128c2ecf20Sopenharmony_ci				res->start = start_cur;
13138c2ecf20Sopenharmony_ci				res->len += 1; /* To restore the balance */
13148c2ecf20Sopenharmony_ci				res->end = res->start + res->len - 1;
13158c2ecf20Sopenharmony_ci				return 0;
13168c2ecf20Sopenharmony_ci			}
13178c2ecf20Sopenharmony_ci		} else {
13188c2ecf20Sopenharmony_ci			/* no more ranges to check on */
13198c2ecf20Sopenharmony_ci			if (len_cur) {
13208c2ecf20Sopenharmony_ci				res->start = start_cur;
13218c2ecf20Sopenharmony_ci				res->len += 1; /* To restore the balance */
13228c2ecf20Sopenharmony_ci				res->end = res->start + res->len - 1;
13238c2ecf20Sopenharmony_ci				return 0;
13248c2ecf20Sopenharmony_ci			} else {
13258c2ecf20Sopenharmony_ci				/* have gone through the list of devices and haven't found n.e.thing */
13268c2ecf20Sopenharmony_ci				err("no appropriate range.. bailing out...\n");
13278c2ecf20Sopenharmony_ci				return -EINVAL;
13288c2ecf20Sopenharmony_ci			}
13298c2ecf20Sopenharmony_ci		}
13308c2ecf20Sopenharmony_ci	}	/* end if (!res_cur) */
13318c2ecf20Sopenharmony_ci	return -EINVAL;
13328c2ecf20Sopenharmony_ci}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci/********************************************************************************
13358c2ecf20Sopenharmony_ci * This routine is called from remove_card if the card contained PPB.
13368c2ecf20Sopenharmony_ci * It will remove all the resources on the bus as well as the bus itself
13378c2ecf20Sopenharmony_ci * Input: Bus
13388c2ecf20Sopenharmony_ci * Output: 0, -ENODEV
13398c2ecf20Sopenharmony_ci ********************************************************************************/
13408c2ecf20Sopenharmony_ciint ibmphp_remove_bus(struct bus_node *bus, u8 parent_busno)
13418c2ecf20Sopenharmony_ci{
13428c2ecf20Sopenharmony_ci	struct resource_node *res_cur;
13438c2ecf20Sopenharmony_ci	struct resource_node *res_tmp;
13448c2ecf20Sopenharmony_ci	struct bus_node *prev_bus;
13458c2ecf20Sopenharmony_ci	int rc;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	prev_bus = find_bus_wprev(parent_busno, NULL, 0);
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	if (!prev_bus) {
13508c2ecf20Sopenharmony_ci		debug("something terribly wrong. Cannot find parent bus to the one to remove\n");
13518c2ecf20Sopenharmony_ci		return -ENODEV;
13528c2ecf20Sopenharmony_ci	}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	debug("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	rc = remove_ranges(bus, prev_bus);
13578c2ecf20Sopenharmony_ci	if (rc)
13588c2ecf20Sopenharmony_ci		return rc;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	if (bus->firstIO) {
13618c2ecf20Sopenharmony_ci		res_cur = bus->firstIO;
13628c2ecf20Sopenharmony_ci		while (res_cur) {
13638c2ecf20Sopenharmony_ci			res_tmp = res_cur;
13648c2ecf20Sopenharmony_ci			if (res_cur->next)
13658c2ecf20Sopenharmony_ci				res_cur = res_cur->next;
13668c2ecf20Sopenharmony_ci			else
13678c2ecf20Sopenharmony_ci				res_cur = res_cur->nextRange;
13688c2ecf20Sopenharmony_ci			kfree(res_tmp);
13698c2ecf20Sopenharmony_ci			res_tmp = NULL;
13708c2ecf20Sopenharmony_ci		}
13718c2ecf20Sopenharmony_ci		bus->firstIO = NULL;
13728c2ecf20Sopenharmony_ci	}
13738c2ecf20Sopenharmony_ci	if (bus->firstMem) {
13748c2ecf20Sopenharmony_ci		res_cur = bus->firstMem;
13758c2ecf20Sopenharmony_ci		while (res_cur) {
13768c2ecf20Sopenharmony_ci			res_tmp = res_cur;
13778c2ecf20Sopenharmony_ci			if (res_cur->next)
13788c2ecf20Sopenharmony_ci				res_cur = res_cur->next;
13798c2ecf20Sopenharmony_ci			else
13808c2ecf20Sopenharmony_ci				res_cur = res_cur->nextRange;
13818c2ecf20Sopenharmony_ci			kfree(res_tmp);
13828c2ecf20Sopenharmony_ci			res_tmp = NULL;
13838c2ecf20Sopenharmony_ci		}
13848c2ecf20Sopenharmony_ci		bus->firstMem = NULL;
13858c2ecf20Sopenharmony_ci	}
13868c2ecf20Sopenharmony_ci	if (bus->firstPFMem) {
13878c2ecf20Sopenharmony_ci		res_cur = bus->firstPFMem;
13888c2ecf20Sopenharmony_ci		while (res_cur) {
13898c2ecf20Sopenharmony_ci			res_tmp = res_cur;
13908c2ecf20Sopenharmony_ci			if (res_cur->next)
13918c2ecf20Sopenharmony_ci				res_cur = res_cur->next;
13928c2ecf20Sopenharmony_ci			else
13938c2ecf20Sopenharmony_ci				res_cur = res_cur->nextRange;
13948c2ecf20Sopenharmony_ci			kfree(res_tmp);
13958c2ecf20Sopenharmony_ci			res_tmp = NULL;
13968c2ecf20Sopenharmony_ci		}
13978c2ecf20Sopenharmony_ci		bus->firstPFMem = NULL;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	if (bus->firstPFMemFromMem) {
14018c2ecf20Sopenharmony_ci		res_cur = bus->firstPFMemFromMem;
14028c2ecf20Sopenharmony_ci		while (res_cur) {
14038c2ecf20Sopenharmony_ci			res_tmp = res_cur;
14048c2ecf20Sopenharmony_ci			res_cur = res_cur->next;
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci			kfree(res_tmp);
14078c2ecf20Sopenharmony_ci			res_tmp = NULL;
14088c2ecf20Sopenharmony_ci		}
14098c2ecf20Sopenharmony_ci		bus->firstPFMemFromMem = NULL;
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	list_del(&bus->bus_list);
14138c2ecf20Sopenharmony_ci	kfree(bus);
14148c2ecf20Sopenharmony_ci	return 0;
14158c2ecf20Sopenharmony_ci}
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci/******************************************************************************
14188c2ecf20Sopenharmony_ci * This routine deletes the ranges from a given bus, and the entries from the
14198c2ecf20Sopenharmony_ci * parent's bus in the resources
14208c2ecf20Sopenharmony_ci * Input: current bus, previous bus
14218c2ecf20Sopenharmony_ci * Output: 0, -EINVAL
14228c2ecf20Sopenharmony_ci ******************************************************************************/
14238c2ecf20Sopenharmony_cistatic int remove_ranges(struct bus_node *bus_cur, struct bus_node *bus_prev)
14248c2ecf20Sopenharmony_ci{
14258c2ecf20Sopenharmony_ci	struct range_node *range_cur;
14268c2ecf20Sopenharmony_ci	struct range_node *range_tmp;
14278c2ecf20Sopenharmony_ci	int i;
14288c2ecf20Sopenharmony_ci	struct resource_node *res = NULL;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (bus_cur->noIORanges) {
14318c2ecf20Sopenharmony_ci		range_cur = bus_cur->rangeIO;
14328c2ecf20Sopenharmony_ci		for (i = 0; i < bus_cur->noIORanges; i++) {
14338c2ecf20Sopenharmony_ci			if (ibmphp_find_resource(bus_prev, range_cur->start, &res, IO) < 0)
14348c2ecf20Sopenharmony_ci				return -EINVAL;
14358c2ecf20Sopenharmony_ci			ibmphp_remove_resource(res);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci			range_tmp = range_cur;
14388c2ecf20Sopenharmony_ci			range_cur = range_cur->next;
14398c2ecf20Sopenharmony_ci			kfree(range_tmp);
14408c2ecf20Sopenharmony_ci			range_tmp = NULL;
14418c2ecf20Sopenharmony_ci		}
14428c2ecf20Sopenharmony_ci		bus_cur->rangeIO = NULL;
14438c2ecf20Sopenharmony_ci	}
14448c2ecf20Sopenharmony_ci	if (bus_cur->noMemRanges) {
14458c2ecf20Sopenharmony_ci		range_cur = bus_cur->rangeMem;
14468c2ecf20Sopenharmony_ci		for (i = 0; i < bus_cur->noMemRanges; i++) {
14478c2ecf20Sopenharmony_ci			if (ibmphp_find_resource(bus_prev, range_cur->start, &res, MEM) < 0)
14488c2ecf20Sopenharmony_ci				return -EINVAL;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci			ibmphp_remove_resource(res);
14518c2ecf20Sopenharmony_ci			range_tmp = range_cur;
14528c2ecf20Sopenharmony_ci			range_cur = range_cur->next;
14538c2ecf20Sopenharmony_ci			kfree(range_tmp);
14548c2ecf20Sopenharmony_ci			range_tmp = NULL;
14558c2ecf20Sopenharmony_ci		}
14568c2ecf20Sopenharmony_ci		bus_cur->rangeMem = NULL;
14578c2ecf20Sopenharmony_ci	}
14588c2ecf20Sopenharmony_ci	if (bus_cur->noPFMemRanges) {
14598c2ecf20Sopenharmony_ci		range_cur = bus_cur->rangePFMem;
14608c2ecf20Sopenharmony_ci		for (i = 0; i < bus_cur->noPFMemRanges; i++) {
14618c2ecf20Sopenharmony_ci			if (ibmphp_find_resource(bus_prev, range_cur->start, &res, PFMEM) < 0)
14628c2ecf20Sopenharmony_ci				return -EINVAL;
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci			ibmphp_remove_resource(res);
14658c2ecf20Sopenharmony_ci			range_tmp = range_cur;
14668c2ecf20Sopenharmony_ci			range_cur = range_cur->next;
14678c2ecf20Sopenharmony_ci			kfree(range_tmp);
14688c2ecf20Sopenharmony_ci			range_tmp = NULL;
14698c2ecf20Sopenharmony_ci		}
14708c2ecf20Sopenharmony_ci		bus_cur->rangePFMem = NULL;
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci	return 0;
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci/*
14768c2ecf20Sopenharmony_ci * find the resource node in the bus
14778c2ecf20Sopenharmony_ci * Input: Resource needed, start address of the resource, type of resource
14788c2ecf20Sopenharmony_ci */
14798c2ecf20Sopenharmony_ciint ibmphp_find_resource(struct bus_node *bus, u32 start_address, struct resource_node **res, int flag)
14808c2ecf20Sopenharmony_ci{
14818c2ecf20Sopenharmony_ci	struct resource_node *res_cur = NULL;
14828c2ecf20Sopenharmony_ci	char *type = "";
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	if (!bus) {
14858c2ecf20Sopenharmony_ci		err("The bus passed in NULL to find resource\n");
14868c2ecf20Sopenharmony_ci		return -ENODEV;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	switch (flag) {
14908c2ecf20Sopenharmony_ci		case IO:
14918c2ecf20Sopenharmony_ci			res_cur = bus->firstIO;
14928c2ecf20Sopenharmony_ci			type = "io";
14938c2ecf20Sopenharmony_ci			break;
14948c2ecf20Sopenharmony_ci		case MEM:
14958c2ecf20Sopenharmony_ci			res_cur = bus->firstMem;
14968c2ecf20Sopenharmony_ci			type = "mem";
14978c2ecf20Sopenharmony_ci			break;
14988c2ecf20Sopenharmony_ci		case PFMEM:
14998c2ecf20Sopenharmony_ci			res_cur = bus->firstPFMem;
15008c2ecf20Sopenharmony_ci			type = "pfmem";
15018c2ecf20Sopenharmony_ci			break;
15028c2ecf20Sopenharmony_ci		default:
15038c2ecf20Sopenharmony_ci			err("wrong type of flag\n");
15048c2ecf20Sopenharmony_ci			return -EINVAL;
15058c2ecf20Sopenharmony_ci	}
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	while (res_cur) {
15088c2ecf20Sopenharmony_ci		if (res_cur->start == start_address) {
15098c2ecf20Sopenharmony_ci			*res = res_cur;
15108c2ecf20Sopenharmony_ci			break;
15118c2ecf20Sopenharmony_ci		}
15128c2ecf20Sopenharmony_ci		if (res_cur->next)
15138c2ecf20Sopenharmony_ci			res_cur = res_cur->next;
15148c2ecf20Sopenharmony_ci		else
15158c2ecf20Sopenharmony_ci			res_cur = res_cur->nextRange;
15168c2ecf20Sopenharmony_ci	}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	if (!res_cur) {
15198c2ecf20Sopenharmony_ci		if (flag == PFMEM) {
15208c2ecf20Sopenharmony_ci			res_cur = bus->firstPFMemFromMem;
15218c2ecf20Sopenharmony_ci			while (res_cur) {
15228c2ecf20Sopenharmony_ci				if (res_cur->start == start_address) {
15238c2ecf20Sopenharmony_ci					*res = res_cur;
15248c2ecf20Sopenharmony_ci					break;
15258c2ecf20Sopenharmony_ci				}
15268c2ecf20Sopenharmony_ci				res_cur = res_cur->next;
15278c2ecf20Sopenharmony_ci			}
15288c2ecf20Sopenharmony_ci			if (!res_cur) {
15298c2ecf20Sopenharmony_ci				debug("SOS...cannot find %s resource in the bus.\n", type);
15308c2ecf20Sopenharmony_ci				return -EINVAL;
15318c2ecf20Sopenharmony_ci			}
15328c2ecf20Sopenharmony_ci		} else {
15338c2ecf20Sopenharmony_ci			debug("SOS... cannot find %s resource in the bus.\n", type);
15348c2ecf20Sopenharmony_ci			return -EINVAL;
15358c2ecf20Sopenharmony_ci		}
15368c2ecf20Sopenharmony_ci	}
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (*res)
15398c2ecf20Sopenharmony_ci		debug("*res->start = %x\n", (*res)->start);
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	return 0;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci/***********************************************************************
15458c2ecf20Sopenharmony_ci * This routine will free the resource structures used by the
15468c2ecf20Sopenharmony_ci * system.  It is called from cleanup routine for the module
15478c2ecf20Sopenharmony_ci * Parameters: none
15488c2ecf20Sopenharmony_ci * Returns: none
15498c2ecf20Sopenharmony_ci ***********************************************************************/
15508c2ecf20Sopenharmony_civoid ibmphp_free_resources(void)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci	struct bus_node *bus_cur = NULL, *next;
15538c2ecf20Sopenharmony_ci	struct bus_node *bus_tmp;
15548c2ecf20Sopenharmony_ci	struct range_node *range_cur;
15558c2ecf20Sopenharmony_ci	struct range_node *range_tmp;
15568c2ecf20Sopenharmony_ci	struct resource_node *res_cur;
15578c2ecf20Sopenharmony_ci	struct resource_node *res_tmp;
15588c2ecf20Sopenharmony_ci	int i = 0;
15598c2ecf20Sopenharmony_ci	flags = 1;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	list_for_each_entry_safe(bus_cur, next, &gbuses, bus_list) {
15628c2ecf20Sopenharmony_ci		if (bus_cur->noIORanges) {
15638c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeIO;
15648c2ecf20Sopenharmony_ci			for (i = 0; i < bus_cur->noIORanges; i++) {
15658c2ecf20Sopenharmony_ci				if (!range_cur)
15668c2ecf20Sopenharmony_ci					break;
15678c2ecf20Sopenharmony_ci				range_tmp = range_cur;
15688c2ecf20Sopenharmony_ci				range_cur = range_cur->next;
15698c2ecf20Sopenharmony_ci				kfree(range_tmp);
15708c2ecf20Sopenharmony_ci				range_tmp = NULL;
15718c2ecf20Sopenharmony_ci			}
15728c2ecf20Sopenharmony_ci		}
15738c2ecf20Sopenharmony_ci		if (bus_cur->noMemRanges) {
15748c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeMem;
15758c2ecf20Sopenharmony_ci			for (i = 0; i < bus_cur->noMemRanges; i++) {
15768c2ecf20Sopenharmony_ci				if (!range_cur)
15778c2ecf20Sopenharmony_ci					break;
15788c2ecf20Sopenharmony_ci				range_tmp = range_cur;
15798c2ecf20Sopenharmony_ci				range_cur = range_cur->next;
15808c2ecf20Sopenharmony_ci				kfree(range_tmp);
15818c2ecf20Sopenharmony_ci				range_tmp = NULL;
15828c2ecf20Sopenharmony_ci			}
15838c2ecf20Sopenharmony_ci		}
15848c2ecf20Sopenharmony_ci		if (bus_cur->noPFMemRanges) {
15858c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangePFMem;
15868c2ecf20Sopenharmony_ci			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
15878c2ecf20Sopenharmony_ci				if (!range_cur)
15888c2ecf20Sopenharmony_ci					break;
15898c2ecf20Sopenharmony_ci				range_tmp = range_cur;
15908c2ecf20Sopenharmony_ci				range_cur = range_cur->next;
15918c2ecf20Sopenharmony_ci				kfree(range_tmp);
15928c2ecf20Sopenharmony_ci				range_tmp = NULL;
15938c2ecf20Sopenharmony_ci			}
15948c2ecf20Sopenharmony_ci		}
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		if (bus_cur->firstIO) {
15978c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstIO;
15988c2ecf20Sopenharmony_ci			while (res_cur) {
15998c2ecf20Sopenharmony_ci				res_tmp = res_cur;
16008c2ecf20Sopenharmony_ci				if (res_cur->next)
16018c2ecf20Sopenharmony_ci					res_cur = res_cur->next;
16028c2ecf20Sopenharmony_ci				else
16038c2ecf20Sopenharmony_ci					res_cur = res_cur->nextRange;
16048c2ecf20Sopenharmony_ci				kfree(res_tmp);
16058c2ecf20Sopenharmony_ci				res_tmp = NULL;
16068c2ecf20Sopenharmony_ci			}
16078c2ecf20Sopenharmony_ci			bus_cur->firstIO = NULL;
16088c2ecf20Sopenharmony_ci		}
16098c2ecf20Sopenharmony_ci		if (bus_cur->firstMem) {
16108c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstMem;
16118c2ecf20Sopenharmony_ci			while (res_cur) {
16128c2ecf20Sopenharmony_ci				res_tmp = res_cur;
16138c2ecf20Sopenharmony_ci				if (res_cur->next)
16148c2ecf20Sopenharmony_ci					res_cur = res_cur->next;
16158c2ecf20Sopenharmony_ci				else
16168c2ecf20Sopenharmony_ci					res_cur = res_cur->nextRange;
16178c2ecf20Sopenharmony_ci				kfree(res_tmp);
16188c2ecf20Sopenharmony_ci				res_tmp = NULL;
16198c2ecf20Sopenharmony_ci			}
16208c2ecf20Sopenharmony_ci			bus_cur->firstMem = NULL;
16218c2ecf20Sopenharmony_ci		}
16228c2ecf20Sopenharmony_ci		if (bus_cur->firstPFMem) {
16238c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstPFMem;
16248c2ecf20Sopenharmony_ci			while (res_cur) {
16258c2ecf20Sopenharmony_ci				res_tmp = res_cur;
16268c2ecf20Sopenharmony_ci				if (res_cur->next)
16278c2ecf20Sopenharmony_ci					res_cur = res_cur->next;
16288c2ecf20Sopenharmony_ci				else
16298c2ecf20Sopenharmony_ci					res_cur = res_cur->nextRange;
16308c2ecf20Sopenharmony_ci				kfree(res_tmp);
16318c2ecf20Sopenharmony_ci				res_tmp = NULL;
16328c2ecf20Sopenharmony_ci			}
16338c2ecf20Sopenharmony_ci			bus_cur->firstPFMem = NULL;
16348c2ecf20Sopenharmony_ci		}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci		if (bus_cur->firstPFMemFromMem) {
16378c2ecf20Sopenharmony_ci			res_cur = bus_cur->firstPFMemFromMem;
16388c2ecf20Sopenharmony_ci			while (res_cur) {
16398c2ecf20Sopenharmony_ci				res_tmp = res_cur;
16408c2ecf20Sopenharmony_ci				res_cur = res_cur->next;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci				kfree(res_tmp);
16438c2ecf20Sopenharmony_ci				res_tmp = NULL;
16448c2ecf20Sopenharmony_ci			}
16458c2ecf20Sopenharmony_ci			bus_cur->firstPFMemFromMem = NULL;
16468c2ecf20Sopenharmony_ci		}
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci		bus_tmp = bus_cur;
16498c2ecf20Sopenharmony_ci		list_del(&bus_cur->bus_list);
16508c2ecf20Sopenharmony_ci		kfree(bus_tmp);
16518c2ecf20Sopenharmony_ci		bus_tmp = NULL;
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci}
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci/*********************************************************************************
16568c2ecf20Sopenharmony_ci * This function will go over the PFmem resources to check if the EBDA allocated
16578c2ecf20Sopenharmony_ci * pfmem out of memory buckets of the bus.  If so, it will change the range numbers
16588c2ecf20Sopenharmony_ci * and a flag to indicate that this resource is out of memory. It will also move the
16598c2ecf20Sopenharmony_ci * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create
16608c2ecf20Sopenharmony_ci * a new Mem node
16618c2ecf20Sopenharmony_ci * This routine is called right after initialization
16628c2ecf20Sopenharmony_ci *******************************************************************************/
16638c2ecf20Sopenharmony_cistatic int __init once_over(void)
16648c2ecf20Sopenharmony_ci{
16658c2ecf20Sopenharmony_ci	struct resource_node *pfmem_cur;
16668c2ecf20Sopenharmony_ci	struct resource_node *pfmem_prev;
16678c2ecf20Sopenharmony_ci	struct resource_node *mem;
16688c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	list_for_each_entry(bus_cur, &gbuses, bus_list) {
16718c2ecf20Sopenharmony_ci		if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) {
16728c2ecf20Sopenharmony_ci			for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) {
16738c2ecf20Sopenharmony_ci				pfmem_cur->fromMem = 1;
16748c2ecf20Sopenharmony_ci				if (pfmem_prev)
16758c2ecf20Sopenharmony_ci					pfmem_prev->next = pfmem_cur->next;
16768c2ecf20Sopenharmony_ci				else
16778c2ecf20Sopenharmony_ci					bus_cur->firstPFMem = pfmem_cur->next;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci				if (!bus_cur->firstPFMemFromMem)
16808c2ecf20Sopenharmony_ci					pfmem_cur->next = NULL;
16818c2ecf20Sopenharmony_ci				else
16828c2ecf20Sopenharmony_ci					/* we don't need to sort PFMemFromMem since we're using mem node for
16838c2ecf20Sopenharmony_ci					   all the real work anyways, so just insert at the beginning of the
16848c2ecf20Sopenharmony_ci					   list
16858c2ecf20Sopenharmony_ci					 */
16868c2ecf20Sopenharmony_ci					pfmem_cur->next = bus_cur->firstPFMemFromMem;
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci				bus_cur->firstPFMemFromMem = pfmem_cur;
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci				mem = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
16918c2ecf20Sopenharmony_ci				if (!mem)
16928c2ecf20Sopenharmony_ci					return -ENOMEM;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci				mem->type = MEM;
16958c2ecf20Sopenharmony_ci				mem->busno = pfmem_cur->busno;
16968c2ecf20Sopenharmony_ci				mem->devfunc = pfmem_cur->devfunc;
16978c2ecf20Sopenharmony_ci				mem->start = pfmem_cur->start;
16988c2ecf20Sopenharmony_ci				mem->end = pfmem_cur->end;
16998c2ecf20Sopenharmony_ci				mem->len = pfmem_cur->len;
17008c2ecf20Sopenharmony_ci				if (ibmphp_add_resource(mem) < 0)
17018c2ecf20Sopenharmony_ci					err("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n");
17028c2ecf20Sopenharmony_ci				pfmem_cur->rangeno = mem->rangeno;
17038c2ecf20Sopenharmony_ci			}	/* end for pfmem */
17048c2ecf20Sopenharmony_ci		}	/* end if */
17058c2ecf20Sopenharmony_ci	}	/* end list_for_each bus */
17068c2ecf20Sopenharmony_ci	return 0;
17078c2ecf20Sopenharmony_ci}
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ciint ibmphp_add_pfmem_from_mem(struct resource_node *pfmem)
17108c2ecf20Sopenharmony_ci{
17118c2ecf20Sopenharmony_ci	struct bus_node *bus_cur = find_bus_wprev(pfmem->busno, NULL, 0);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	if (!bus_cur) {
17148c2ecf20Sopenharmony_ci		err("cannot find bus of pfmem to add...\n");
17158c2ecf20Sopenharmony_ci		return -ENODEV;
17168c2ecf20Sopenharmony_ci	}
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	if (bus_cur->firstPFMemFromMem)
17198c2ecf20Sopenharmony_ci		pfmem->next = bus_cur->firstPFMemFromMem;
17208c2ecf20Sopenharmony_ci	else
17218c2ecf20Sopenharmony_ci		pfmem->next = NULL;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	bus_cur->firstPFMemFromMem = pfmem;
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	return 0;
17268c2ecf20Sopenharmony_ci}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci/* This routine just goes through the buses to see if the bus already exists.
17298c2ecf20Sopenharmony_ci * It is called from ibmphp_find_sec_number, to find out a secondary bus number for
17308c2ecf20Sopenharmony_ci * bridged cards
17318c2ecf20Sopenharmony_ci * Parameters: bus_number
17328c2ecf20Sopenharmony_ci * Returns: Bus pointer or NULL
17338c2ecf20Sopenharmony_ci */
17348c2ecf20Sopenharmony_cistruct bus_node *ibmphp_find_res_bus(u8 bus_number)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	return find_bus_wprev(bus_number, NULL, 0);
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_cistatic struct bus_node *find_bus_wprev(u8 bus_number, struct bus_node **prev, u8 flag)
17408c2ecf20Sopenharmony_ci{
17418c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	list_for_each_entry(bus_cur, &gbuses, bus_list) {
17448c2ecf20Sopenharmony_ci		if (flag)
17458c2ecf20Sopenharmony_ci			*prev = list_prev_entry(bus_cur, bus_list);
17468c2ecf20Sopenharmony_ci		if (bus_cur->busno == bus_number)
17478c2ecf20Sopenharmony_ci			return bus_cur;
17488c2ecf20Sopenharmony_ci	}
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	return NULL;
17518c2ecf20Sopenharmony_ci}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_civoid ibmphp_print_test(void)
17548c2ecf20Sopenharmony_ci{
17558c2ecf20Sopenharmony_ci	int i = 0;
17568c2ecf20Sopenharmony_ci	struct bus_node *bus_cur = NULL;
17578c2ecf20Sopenharmony_ci	struct range_node *range;
17588c2ecf20Sopenharmony_ci	struct resource_node *res;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	debug_pci("*****************START**********************\n");
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	if ((!list_empty(&gbuses)) && flags) {
17638c2ecf20Sopenharmony_ci		err("The GBUSES is not NULL?!?!?!?!?\n");
17648c2ecf20Sopenharmony_ci		return;
17658c2ecf20Sopenharmony_ci	}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	list_for_each_entry(bus_cur, &gbuses, bus_list) {
17688c2ecf20Sopenharmony_ci		debug_pci ("This is bus # %d.  There are\n", bus_cur->busno);
17698c2ecf20Sopenharmony_ci		debug_pci ("IORanges = %d\t", bus_cur->noIORanges);
17708c2ecf20Sopenharmony_ci		debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges);
17718c2ecf20Sopenharmony_ci		debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
17728c2ecf20Sopenharmony_ci		debug_pci ("The IO Ranges are as follows:\n");
17738c2ecf20Sopenharmony_ci		if (bus_cur->rangeIO) {
17748c2ecf20Sopenharmony_ci			range = bus_cur->rangeIO;
17758c2ecf20Sopenharmony_ci			for (i = 0; i < bus_cur->noIORanges; i++) {
17768c2ecf20Sopenharmony_ci				debug_pci("rangeno is %d\n", range->rangeno);
17778c2ecf20Sopenharmony_ci				debug_pci("[%x - %x]\n", range->start, range->end);
17788c2ecf20Sopenharmony_ci				range = range->next;
17798c2ecf20Sopenharmony_ci			}
17808c2ecf20Sopenharmony_ci		}
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci		debug_pci("The Mem Ranges are as follows:\n");
17838c2ecf20Sopenharmony_ci		if (bus_cur->rangeMem) {
17848c2ecf20Sopenharmony_ci			range = bus_cur->rangeMem;
17858c2ecf20Sopenharmony_ci			for (i = 0; i < bus_cur->noMemRanges; i++) {
17868c2ecf20Sopenharmony_ci				debug_pci("rangeno is %d\n", range->rangeno);
17878c2ecf20Sopenharmony_ci				debug_pci("[%x - %x]\n", range->start, range->end);
17888c2ecf20Sopenharmony_ci				range = range->next;
17898c2ecf20Sopenharmony_ci			}
17908c2ecf20Sopenharmony_ci		}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci		debug_pci("The PFMem Ranges are as follows:\n");
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci		if (bus_cur->rangePFMem) {
17958c2ecf20Sopenharmony_ci			range = bus_cur->rangePFMem;
17968c2ecf20Sopenharmony_ci			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
17978c2ecf20Sopenharmony_ci				debug_pci("rangeno is %d\n", range->rangeno);
17988c2ecf20Sopenharmony_ci				debug_pci("[%x - %x]\n", range->start, range->end);
17998c2ecf20Sopenharmony_ci				range = range->next;
18008c2ecf20Sopenharmony_ci			}
18018c2ecf20Sopenharmony_ci		}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci		debug_pci("The resources on this bus are as follows\n");
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci		debug_pci("IO...\n");
18068c2ecf20Sopenharmony_ci		if (bus_cur->firstIO) {
18078c2ecf20Sopenharmony_ci			res = bus_cur->firstIO;
18088c2ecf20Sopenharmony_ci			while (res) {
18098c2ecf20Sopenharmony_ci				debug_pci("The range # is %d\n", res->rangeno);
18108c2ecf20Sopenharmony_ci				debug_pci("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
18118c2ecf20Sopenharmony_ci				debug_pci("[%x - %x], len=%x\n", res->start, res->end, res->len);
18128c2ecf20Sopenharmony_ci				if (res->next)
18138c2ecf20Sopenharmony_ci					res = res->next;
18148c2ecf20Sopenharmony_ci				else if (res->nextRange)
18158c2ecf20Sopenharmony_ci					res = res->nextRange;
18168c2ecf20Sopenharmony_ci				else
18178c2ecf20Sopenharmony_ci					break;
18188c2ecf20Sopenharmony_ci			}
18198c2ecf20Sopenharmony_ci		}
18208c2ecf20Sopenharmony_ci		debug_pci("Mem...\n");
18218c2ecf20Sopenharmony_ci		if (bus_cur->firstMem) {
18228c2ecf20Sopenharmony_ci			res = bus_cur->firstMem;
18238c2ecf20Sopenharmony_ci			while (res) {
18248c2ecf20Sopenharmony_ci				debug_pci("The range # is %d\n", res->rangeno);
18258c2ecf20Sopenharmony_ci				debug_pci("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
18268c2ecf20Sopenharmony_ci				debug_pci("[%x - %x], len=%x\n", res->start, res->end, res->len);
18278c2ecf20Sopenharmony_ci				if (res->next)
18288c2ecf20Sopenharmony_ci					res = res->next;
18298c2ecf20Sopenharmony_ci				else if (res->nextRange)
18308c2ecf20Sopenharmony_ci					res = res->nextRange;
18318c2ecf20Sopenharmony_ci				else
18328c2ecf20Sopenharmony_ci					break;
18338c2ecf20Sopenharmony_ci			}
18348c2ecf20Sopenharmony_ci		}
18358c2ecf20Sopenharmony_ci		debug_pci("PFMem...\n");
18368c2ecf20Sopenharmony_ci		if (bus_cur->firstPFMem) {
18378c2ecf20Sopenharmony_ci			res = bus_cur->firstPFMem;
18388c2ecf20Sopenharmony_ci			while (res) {
18398c2ecf20Sopenharmony_ci				debug_pci("The range # is %d\n", res->rangeno);
18408c2ecf20Sopenharmony_ci				debug_pci("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
18418c2ecf20Sopenharmony_ci				debug_pci("[%x - %x], len=%x\n", res->start, res->end, res->len);
18428c2ecf20Sopenharmony_ci				if (res->next)
18438c2ecf20Sopenharmony_ci					res = res->next;
18448c2ecf20Sopenharmony_ci				else if (res->nextRange)
18458c2ecf20Sopenharmony_ci					res = res->nextRange;
18468c2ecf20Sopenharmony_ci				else
18478c2ecf20Sopenharmony_ci					break;
18488c2ecf20Sopenharmony_ci			}
18498c2ecf20Sopenharmony_ci		}
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci		debug_pci("PFMemFromMem...\n");
18528c2ecf20Sopenharmony_ci		if (bus_cur->firstPFMemFromMem) {
18538c2ecf20Sopenharmony_ci			res = bus_cur->firstPFMemFromMem;
18548c2ecf20Sopenharmony_ci			while (res) {
18558c2ecf20Sopenharmony_ci				debug_pci("The range # is %d\n", res->rangeno);
18568c2ecf20Sopenharmony_ci				debug_pci("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
18578c2ecf20Sopenharmony_ci				debug_pci("[%x - %x], len=%x\n", res->start, res->end, res->len);
18588c2ecf20Sopenharmony_ci				res = res->next;
18598c2ecf20Sopenharmony_ci			}
18608c2ecf20Sopenharmony_ci		}
18618c2ecf20Sopenharmony_ci	}
18628c2ecf20Sopenharmony_ci	debug_pci("***********************END***********************\n");
18638c2ecf20Sopenharmony_ci}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_cistatic int range_exists_already(struct range_node *range, struct bus_node *bus_cur, u8 type)
18668c2ecf20Sopenharmony_ci{
18678c2ecf20Sopenharmony_ci	struct range_node *range_cur = NULL;
18688c2ecf20Sopenharmony_ci	switch (type) {
18698c2ecf20Sopenharmony_ci		case IO:
18708c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeIO;
18718c2ecf20Sopenharmony_ci			break;
18728c2ecf20Sopenharmony_ci		case MEM:
18738c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangeMem;
18748c2ecf20Sopenharmony_ci			break;
18758c2ecf20Sopenharmony_ci		case PFMEM:
18768c2ecf20Sopenharmony_ci			range_cur = bus_cur->rangePFMem;
18778c2ecf20Sopenharmony_ci			break;
18788c2ecf20Sopenharmony_ci		default:
18798c2ecf20Sopenharmony_ci			err("wrong type passed to find out if range already exists\n");
18808c2ecf20Sopenharmony_ci			return -ENODEV;
18818c2ecf20Sopenharmony_ci	}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	while (range_cur) {
18848c2ecf20Sopenharmony_ci		if ((range_cur->start == range->start) && (range_cur->end == range->end))
18858c2ecf20Sopenharmony_ci			return 1;
18868c2ecf20Sopenharmony_ci		range_cur = range_cur->next;
18878c2ecf20Sopenharmony_ci	}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	return 0;
18908c2ecf20Sopenharmony_ci}
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci/* This routine will read the windows for any PPB we have and update the
18938c2ecf20Sopenharmony_ci * range info for the secondary bus, and will also input this info into
18948c2ecf20Sopenharmony_ci * primary bus, since BIOS doesn't. This is for PPB that are in the system
18958c2ecf20Sopenharmony_ci * on bootup.  For bridged cards that were added during previous load of the
18968c2ecf20Sopenharmony_ci * driver, only the ranges and the bus structure are added, the devices are
18978c2ecf20Sopenharmony_ci * added from NVRAM
18988c2ecf20Sopenharmony_ci * Input: primary busno
18998c2ecf20Sopenharmony_ci * Returns: none
19008c2ecf20Sopenharmony_ci * Note: this function doesn't take into account IO restrictions etc,
19018c2ecf20Sopenharmony_ci *	 so will only work for bridges with no video/ISA devices behind them It
19028c2ecf20Sopenharmony_ci *	 also will not work for onboard PPBs that can have more than 1 *bus
19038c2ecf20Sopenharmony_ci *	 behind them All these are TO DO.
19048c2ecf20Sopenharmony_ci *	 Also need to add more error checkings... (from fnc returns etc)
19058c2ecf20Sopenharmony_ci */
19068c2ecf20Sopenharmony_cistatic int __init update_bridge_ranges(struct bus_node **bus)
19078c2ecf20Sopenharmony_ci{
19088c2ecf20Sopenharmony_ci	u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address;
19098c2ecf20Sopenharmony_ci	u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
19108c2ecf20Sopenharmony_ci	u32 start_address, end_address, upper_start, upper_end;
19118c2ecf20Sopenharmony_ci	struct bus_node *bus_sec;
19128c2ecf20Sopenharmony_ci	struct bus_node *bus_cur;
19138c2ecf20Sopenharmony_ci	struct resource_node *io;
19148c2ecf20Sopenharmony_ci	struct resource_node *mem;
19158c2ecf20Sopenharmony_ci	struct resource_node *pfmem;
19168c2ecf20Sopenharmony_ci	struct range_node *range;
19178c2ecf20Sopenharmony_ci	unsigned int devfn;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	bus_cur = *bus;
19208c2ecf20Sopenharmony_ci	if (!bus_cur)
19218c2ecf20Sopenharmony_ci		return -ENODEV;
19228c2ecf20Sopenharmony_ci	ibmphp_pci_bus->number = bus_cur->busno;
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	debug("inside %s\n", __func__);
19258c2ecf20Sopenharmony_ci	debug("bus_cur->busno = %x\n", bus_cur->busno);
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	for (device = 0; device < 32; device++) {
19288c2ecf20Sopenharmony_ci		for (function = 0x00; function < 0x08; function++) {
19298c2ecf20Sopenharmony_ci			devfn = PCI_DEVFN(device, function);
19308c2ecf20Sopenharmony_ci			pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
19338c2ecf20Sopenharmony_ci				/* found correct device!!! */
19348c2ecf20Sopenharmony_ci				pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci				switch (hdr_type) {
19378c2ecf20Sopenharmony_ci					case PCI_HEADER_TYPE_NORMAL:
19388c2ecf20Sopenharmony_ci						function = 0x8;
19398c2ecf20Sopenharmony_ci						break;
19408c2ecf20Sopenharmony_ci					case PCI_HEADER_TYPE_MULTIDEVICE:
19418c2ecf20Sopenharmony_ci						break;
19428c2ecf20Sopenharmony_ci					case PCI_HEADER_TYPE_BRIDGE:
19438c2ecf20Sopenharmony_ci						function = 0x8;
19448c2ecf20Sopenharmony_ci						fallthrough;
19458c2ecf20Sopenharmony_ci					case PCI_HEADER_TYPE_MULTIBRIDGE:
19468c2ecf20Sopenharmony_ci						/* We assume here that only 1 bus behind the bridge
19478c2ecf20Sopenharmony_ci						   TO DO: add functionality for several:
19488c2ecf20Sopenharmony_ci						   temp = secondary;
19498c2ecf20Sopenharmony_ci						   while (temp < subordinate) {
19508c2ecf20Sopenharmony_ci						   ...
19518c2ecf20Sopenharmony_ci						   temp++;
19528c2ecf20Sopenharmony_ci						   }
19538c2ecf20Sopenharmony_ci						 */
19548c2ecf20Sopenharmony_ci						pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno);
19558c2ecf20Sopenharmony_ci						bus_sec = find_bus_wprev(sec_busno, NULL, 0);
19568c2ecf20Sopenharmony_ci						/* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */
19578c2ecf20Sopenharmony_ci						if (!bus_sec) {
19588c2ecf20Sopenharmony_ci							bus_sec = alloc_error_bus(NULL, sec_busno, 1);
19598c2ecf20Sopenharmony_ci							/* the rest will be populated during NVRAM call */
19608c2ecf20Sopenharmony_ci							return 0;
19618c2ecf20Sopenharmony_ci						}
19628c2ecf20Sopenharmony_ci						pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address);
19638c2ecf20Sopenharmony_ci						pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address);
19648c2ecf20Sopenharmony_ci						pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start);
19658c2ecf20Sopenharmony_ci						pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end);
19668c2ecf20Sopenharmony_ci						start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8;
19678c2ecf20Sopenharmony_ci						start_address |= (upper_io_start << 16);
19688c2ecf20Sopenharmony_ci						end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8;
19698c2ecf20Sopenharmony_ci						end_address |= (upper_io_end << 16);
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci						if ((start_address) && (start_address <= end_address)) {
19728c2ecf20Sopenharmony_ci							range = kzalloc(sizeof(struct range_node), GFP_KERNEL);
19738c2ecf20Sopenharmony_ci							if (!range)
19748c2ecf20Sopenharmony_ci								return -ENOMEM;
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci							range->start = start_address;
19778c2ecf20Sopenharmony_ci							range->end = end_address + 0xfff;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci							if (bus_sec->noIORanges > 0) {
19808c2ecf20Sopenharmony_ci								if (!range_exists_already(range, bus_sec, IO)) {
19818c2ecf20Sopenharmony_ci									add_bus_range(IO, range, bus_sec);
19828c2ecf20Sopenharmony_ci									++bus_sec->noIORanges;
19838c2ecf20Sopenharmony_ci								} else {
19848c2ecf20Sopenharmony_ci									kfree(range);
19858c2ecf20Sopenharmony_ci									range = NULL;
19868c2ecf20Sopenharmony_ci								}
19878c2ecf20Sopenharmony_ci							} else {
19888c2ecf20Sopenharmony_ci								/* 1st IO Range on the bus */
19898c2ecf20Sopenharmony_ci								range->rangeno = 1;
19908c2ecf20Sopenharmony_ci								bus_sec->rangeIO = range;
19918c2ecf20Sopenharmony_ci								++bus_sec->noIORanges;
19928c2ecf20Sopenharmony_ci							}
19938c2ecf20Sopenharmony_ci							fix_resources(bus_sec);
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci							if (ibmphp_find_resource(bus_cur, start_address, &io, IO)) {
19968c2ecf20Sopenharmony_ci								io = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
19978c2ecf20Sopenharmony_ci								if (!io) {
19988c2ecf20Sopenharmony_ci									kfree(range);
19998c2ecf20Sopenharmony_ci									return -ENOMEM;
20008c2ecf20Sopenharmony_ci								}
20018c2ecf20Sopenharmony_ci								io->type = IO;
20028c2ecf20Sopenharmony_ci								io->busno = bus_cur->busno;
20038c2ecf20Sopenharmony_ci								io->devfunc = ((device << 3) | (function & 0x7));
20048c2ecf20Sopenharmony_ci								io->start = start_address;
20058c2ecf20Sopenharmony_ci								io->end = end_address + 0xfff;
20068c2ecf20Sopenharmony_ci								io->len = io->end - io->start + 1;
20078c2ecf20Sopenharmony_ci								ibmphp_add_resource(io);
20088c2ecf20Sopenharmony_ci							}
20098c2ecf20Sopenharmony_ci						}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci						pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address);
20128c2ecf20Sopenharmony_ci						pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address);
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
20158c2ecf20Sopenharmony_ci						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci						if ((start_address) && (start_address <= end_address)) {
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci							range = kzalloc(sizeof(struct range_node), GFP_KERNEL);
20208c2ecf20Sopenharmony_ci							if (!range)
20218c2ecf20Sopenharmony_ci								return -ENOMEM;
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci							range->start = start_address;
20248c2ecf20Sopenharmony_ci							range->end = end_address + 0xfffff;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci							if (bus_sec->noMemRanges > 0) {
20278c2ecf20Sopenharmony_ci								if (!range_exists_already(range, bus_sec, MEM)) {
20288c2ecf20Sopenharmony_ci									add_bus_range(MEM, range, bus_sec);
20298c2ecf20Sopenharmony_ci									++bus_sec->noMemRanges;
20308c2ecf20Sopenharmony_ci								} else {
20318c2ecf20Sopenharmony_ci									kfree(range);
20328c2ecf20Sopenharmony_ci									range = NULL;
20338c2ecf20Sopenharmony_ci								}
20348c2ecf20Sopenharmony_ci							} else {
20358c2ecf20Sopenharmony_ci								/* 1st Mem Range on the bus */
20368c2ecf20Sopenharmony_ci								range->rangeno = 1;
20378c2ecf20Sopenharmony_ci								bus_sec->rangeMem = range;
20388c2ecf20Sopenharmony_ci								++bus_sec->noMemRanges;
20398c2ecf20Sopenharmony_ci							}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci							fix_resources(bus_sec);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci							if (ibmphp_find_resource(bus_cur, start_address, &mem, MEM)) {
20448c2ecf20Sopenharmony_ci								mem = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
20458c2ecf20Sopenharmony_ci								if (!mem) {
20468c2ecf20Sopenharmony_ci									kfree(range);
20478c2ecf20Sopenharmony_ci									return -ENOMEM;
20488c2ecf20Sopenharmony_ci								}
20498c2ecf20Sopenharmony_ci								mem->type = MEM;
20508c2ecf20Sopenharmony_ci								mem->busno = bus_cur->busno;
20518c2ecf20Sopenharmony_ci								mem->devfunc = ((device << 3) | (function & 0x7));
20528c2ecf20Sopenharmony_ci								mem->start = start_address;
20538c2ecf20Sopenharmony_ci								mem->end = end_address + 0xfffff;
20548c2ecf20Sopenharmony_ci								mem->len = mem->end - mem->start + 1;
20558c2ecf20Sopenharmony_ci								ibmphp_add_resource(mem);
20568c2ecf20Sopenharmony_ci							}
20578c2ecf20Sopenharmony_ci						}
20588c2ecf20Sopenharmony_ci						pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address);
20598c2ecf20Sopenharmony_ci						pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address);
20608c2ecf20Sopenharmony_ci						pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start);
20618c2ecf20Sopenharmony_ci						pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end);
20628c2ecf20Sopenharmony_ci						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
20638c2ecf20Sopenharmony_ci						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
20648c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 64
20658c2ecf20Sopenharmony_ci						start_address |= ((long) upper_start) << 32;
20668c2ecf20Sopenharmony_ci						end_address |= ((long) upper_end) << 32;
20678c2ecf20Sopenharmony_ci#endif
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci						if ((start_address) && (start_address <= end_address)) {
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci							range = kzalloc(sizeof(struct range_node), GFP_KERNEL);
20728c2ecf20Sopenharmony_ci							if (!range)
20738c2ecf20Sopenharmony_ci								return -ENOMEM;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci							range->start = start_address;
20768c2ecf20Sopenharmony_ci							range->end = end_address + 0xfffff;
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci							if (bus_sec->noPFMemRanges > 0) {
20798c2ecf20Sopenharmony_ci								if (!range_exists_already(range, bus_sec, PFMEM)) {
20808c2ecf20Sopenharmony_ci									add_bus_range(PFMEM, range, bus_sec);
20818c2ecf20Sopenharmony_ci									++bus_sec->noPFMemRanges;
20828c2ecf20Sopenharmony_ci								} else {
20838c2ecf20Sopenharmony_ci									kfree(range);
20848c2ecf20Sopenharmony_ci									range = NULL;
20858c2ecf20Sopenharmony_ci								}
20868c2ecf20Sopenharmony_ci							} else {
20878c2ecf20Sopenharmony_ci								/* 1st PFMem Range on the bus */
20888c2ecf20Sopenharmony_ci								range->rangeno = 1;
20898c2ecf20Sopenharmony_ci								bus_sec->rangePFMem = range;
20908c2ecf20Sopenharmony_ci								++bus_sec->noPFMemRanges;
20918c2ecf20Sopenharmony_ci							}
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci							fix_resources(bus_sec);
20948c2ecf20Sopenharmony_ci							if (ibmphp_find_resource(bus_cur, start_address, &pfmem, PFMEM)) {
20958c2ecf20Sopenharmony_ci								pfmem = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
20968c2ecf20Sopenharmony_ci								if (!pfmem) {
20978c2ecf20Sopenharmony_ci									kfree(range);
20988c2ecf20Sopenharmony_ci									return -ENOMEM;
20998c2ecf20Sopenharmony_ci								}
21008c2ecf20Sopenharmony_ci								pfmem->type = PFMEM;
21018c2ecf20Sopenharmony_ci								pfmem->busno = bus_cur->busno;
21028c2ecf20Sopenharmony_ci								pfmem->devfunc = ((device << 3) | (function & 0x7));
21038c2ecf20Sopenharmony_ci								pfmem->start = start_address;
21048c2ecf20Sopenharmony_ci								pfmem->end = end_address + 0xfffff;
21058c2ecf20Sopenharmony_ci								pfmem->len = pfmem->end - pfmem->start + 1;
21068c2ecf20Sopenharmony_ci								pfmem->fromMem = 0;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci								ibmphp_add_resource(pfmem);
21098c2ecf20Sopenharmony_ci							}
21108c2ecf20Sopenharmony_ci						}
21118c2ecf20Sopenharmony_ci						break;
21128c2ecf20Sopenharmony_ci				}	/* end of switch */
21138c2ecf20Sopenharmony_ci			}	/* end if vendor */
21148c2ecf20Sopenharmony_ci		}	/* end for function */
21158c2ecf20Sopenharmony_ci	}	/* end for device */
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	bus = &bus_cur;
21188c2ecf20Sopenharmony_ci	return 0;
21198c2ecf20Sopenharmony_ci}
2120