18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * IBM Hot Plug Controller Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Written By: Tong Yu, IBM Corporation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
88c2ecf20Sopenharmony_ci * Copyright (C) 2001-2003 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/errno.h>
188c2ecf20Sopenharmony_ci#include <linux/mm.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/pci.h>
218c2ecf20Sopenharmony_ci#include <linux/list.h>
228c2ecf20Sopenharmony_ci#include <linux/init.h>
238c2ecf20Sopenharmony_ci#include "ibmphp.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/*
268c2ecf20Sopenharmony_ci * POST builds data blocks(in this data block definition, a char-1
278c2ecf20Sopenharmony_ci * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended
288c2ecf20Sopenharmony_ci * BIOS Data Area which describe the configuration of the hot-plug
298c2ecf20Sopenharmony_ci * controllers and resources used by the PCI Hot-Plug devices.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * This file walks EBDA, maps data block from physical addr,
328c2ecf20Sopenharmony_ci * reconstruct linked lists about all system resource(MEM, PFM, IO)
338c2ecf20Sopenharmony_ci * already assigned by POST, as well as linked lists about hot plug
348c2ecf20Sopenharmony_ci * controllers (ctlr#, slot#, bus&slot features...)
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* Global lists */
388c2ecf20Sopenharmony_ciLIST_HEAD(ibmphp_ebda_pci_rsrc_head);
398c2ecf20Sopenharmony_ciLIST_HEAD(ibmphp_slot_head);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* Local variables */
428c2ecf20Sopenharmony_cistatic struct ebda_hpc_list *hpc_list_ptr;
438c2ecf20Sopenharmony_cistatic struct ebda_rsrc_list *rsrc_list_ptr;
448c2ecf20Sopenharmony_cistatic struct rio_table_hdr *rio_table_ptr = NULL;
458c2ecf20Sopenharmony_cistatic LIST_HEAD(ebda_hpc_head);
468c2ecf20Sopenharmony_cistatic LIST_HEAD(bus_info_head);
478c2ecf20Sopenharmony_cistatic LIST_HEAD(rio_vg_head);
488c2ecf20Sopenharmony_cistatic LIST_HEAD(rio_lo_head);
498c2ecf20Sopenharmony_cistatic LIST_HEAD(opt_vg_head);
508c2ecf20Sopenharmony_cistatic LIST_HEAD(opt_lo_head);
518c2ecf20Sopenharmony_cistatic void __iomem *io_mem;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* Local functions */
548c2ecf20Sopenharmony_cistatic int ebda_rsrc_controller(void);
558c2ecf20Sopenharmony_cistatic int ebda_rsrc_rsrc(void);
568c2ecf20Sopenharmony_cistatic int ebda_rio_table(void);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic struct ebda_hpc_list * __init alloc_ebda_hpc_list(void)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	return kzalloc(sizeof(struct ebda_hpc_list), GFP_KERNEL);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic struct controller *alloc_ebda_hpc(u32 slot_count, u32 bus_count)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct controller *controller;
668c2ecf20Sopenharmony_ci	struct ebda_hpc_slot *slots;
678c2ecf20Sopenharmony_ci	struct ebda_hpc_bus *buses;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	controller = kzalloc(sizeof(struct controller), GFP_KERNEL);
708c2ecf20Sopenharmony_ci	if (!controller)
718c2ecf20Sopenharmony_ci		goto error;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	slots = kcalloc(slot_count, sizeof(struct ebda_hpc_slot), GFP_KERNEL);
748c2ecf20Sopenharmony_ci	if (!slots)
758c2ecf20Sopenharmony_ci		goto error_contr;
768c2ecf20Sopenharmony_ci	controller->slots = slots;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	buses = kcalloc(bus_count, sizeof(struct ebda_hpc_bus), GFP_KERNEL);
798c2ecf20Sopenharmony_ci	if (!buses)
808c2ecf20Sopenharmony_ci		goto error_slots;
818c2ecf20Sopenharmony_ci	controller->buses = buses;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return controller;
848c2ecf20Sopenharmony_cierror_slots:
858c2ecf20Sopenharmony_ci	kfree(controller->slots);
868c2ecf20Sopenharmony_cierror_contr:
878c2ecf20Sopenharmony_ci	kfree(controller);
888c2ecf20Sopenharmony_cierror:
898c2ecf20Sopenharmony_ci	return NULL;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void free_ebda_hpc(struct controller *controller)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	kfree(controller->slots);
958c2ecf20Sopenharmony_ci	kfree(controller->buses);
968c2ecf20Sopenharmony_ci	kfree(controller);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic struct ebda_rsrc_list * __init alloc_ebda_rsrc_list(void)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	return kzalloc(sizeof(struct ebda_rsrc_list), GFP_KERNEL);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic struct ebda_pci_rsrc *alloc_ebda_pci_rsrc(void)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	return kzalloc(sizeof(struct ebda_pci_rsrc), GFP_KERNEL);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void __init print_bus_info(void)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct bus_info *ptr;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
1148c2ecf20Sopenharmony_ci		debug("%s - slot_min = %x\n", __func__, ptr->slot_min);
1158c2ecf20Sopenharmony_ci		debug("%s - slot_max = %x\n", __func__, ptr->slot_max);
1168c2ecf20Sopenharmony_ci		debug("%s - slot_count = %x\n", __func__, ptr->slot_count);
1178c2ecf20Sopenharmony_ci		debug("%s - bus# = %x\n", __func__, ptr->busno);
1188c2ecf20Sopenharmony_ci		debug("%s - current_speed = %x\n", __func__, ptr->current_speed);
1198c2ecf20Sopenharmony_ci		debug("%s - controller_id = %x\n", __func__, ptr->controller_id);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		debug("%s - slots_at_33_conv = %x\n", __func__, ptr->slots_at_33_conv);
1228c2ecf20Sopenharmony_ci		debug("%s - slots_at_66_conv = %x\n", __func__, ptr->slots_at_66_conv);
1238c2ecf20Sopenharmony_ci		debug("%s - slots_at_66_pcix = %x\n", __func__, ptr->slots_at_66_pcix);
1248c2ecf20Sopenharmony_ci		debug("%s - slots_at_100_pcix = %x\n", __func__, ptr->slots_at_100_pcix);
1258c2ecf20Sopenharmony_ci		debug("%s - slots_at_133_pcix = %x\n", __func__, ptr->slots_at_133_pcix);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void print_lo_info(void)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct rio_detail *ptr;
1338c2ecf20Sopenharmony_ci	debug("print_lo_info ----\n");
1348c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &rio_lo_head, rio_detail_list) {
1358c2ecf20Sopenharmony_ci		debug("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
1368c2ecf20Sopenharmony_ci		debug("%s - rio_type = %x\n", __func__, ptr->rio_type);
1378c2ecf20Sopenharmony_ci		debug("%s - owner_id = %x\n", __func__, ptr->owner_id);
1388c2ecf20Sopenharmony_ci		debug("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
1398c2ecf20Sopenharmony_ci		debug("%s - wpindex = %x\n", __func__, ptr->wpindex);
1408c2ecf20Sopenharmony_ci		debug("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void print_vg_info(void)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct rio_detail *ptr;
1488c2ecf20Sopenharmony_ci	debug("%s ---\n", __func__);
1498c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &rio_vg_head, rio_detail_list) {
1508c2ecf20Sopenharmony_ci		debug("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
1518c2ecf20Sopenharmony_ci		debug("%s - rio_type = %x\n", __func__, ptr->rio_type);
1528c2ecf20Sopenharmony_ci		debug("%s - owner_id = %x\n", __func__, ptr->owner_id);
1538c2ecf20Sopenharmony_ci		debug("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
1548c2ecf20Sopenharmony_ci		debug("%s - wpindex = %x\n", __func__, ptr->wpindex);
1558c2ecf20Sopenharmony_ci		debug("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic void __init print_ebda_pci_rsrc(void)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct ebda_pci_rsrc *ptr;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &ibmphp_ebda_pci_rsrc_head, ebda_pci_rsrc_list) {
1658c2ecf20Sopenharmony_ci		debug("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
1668c2ecf20Sopenharmony_ci			__func__, ptr->rsrc_type, ptr->bus_num, ptr->dev_fun, ptr->start_addr, ptr->end_addr);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic void __init print_ibm_slot(void)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct slot *ptr;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &ibmphp_slot_head, ibm_slot_list) {
1758c2ecf20Sopenharmony_ci		debug("%s - slot_number: %x\n", __func__, ptr->number);
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic void __init print_opt_vg(void)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct opt_rio *ptr;
1828c2ecf20Sopenharmony_ci	debug("%s ---\n", __func__);
1838c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
1848c2ecf20Sopenharmony_ci		debug("%s - rio_type %x\n", __func__, ptr->rio_type);
1858c2ecf20Sopenharmony_ci		debug("%s - chassis_num: %x\n", __func__, ptr->chassis_num);
1868c2ecf20Sopenharmony_ci		debug("%s - first_slot_num: %x\n", __func__, ptr->first_slot_num);
1878c2ecf20Sopenharmony_ci		debug("%s - middle_num: %x\n", __func__, ptr->middle_num);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void __init print_ebda_hpc(void)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct controller *hpc_ptr;
1948c2ecf20Sopenharmony_ci	u16 index;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	list_for_each_entry(hpc_ptr, &ebda_hpc_head, ebda_hpc_list) {
1978c2ecf20Sopenharmony_ci		for (index = 0; index < hpc_ptr->slot_count; index++) {
1988c2ecf20Sopenharmony_ci			debug("%s - physical slot#: %x\n", __func__, hpc_ptr->slots[index].slot_num);
1998c2ecf20Sopenharmony_ci			debug("%s - pci bus# of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_bus_num);
2008c2ecf20Sopenharmony_ci			debug("%s - index into ctlr addr: %x\n", __func__, hpc_ptr->slots[index].ctl_index);
2018c2ecf20Sopenharmony_ci			debug("%s - cap of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_cap);
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		for (index = 0; index < hpc_ptr->bus_count; index++)
2058c2ecf20Sopenharmony_ci			debug("%s - bus# of each bus controlled by this ctlr: %x\n", __func__, hpc_ptr->buses[index].bus_num);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		debug("%s - type of hpc: %x\n", __func__, hpc_ptr->ctlr_type);
2088c2ecf20Sopenharmony_ci		switch (hpc_ptr->ctlr_type) {
2098c2ecf20Sopenharmony_ci		case 1:
2108c2ecf20Sopenharmony_ci			debug("%s - bus: %x\n", __func__, hpc_ptr->u.pci_ctlr.bus);
2118c2ecf20Sopenharmony_ci			debug("%s - dev_fun: %x\n", __func__, hpc_ptr->u.pci_ctlr.dev_fun);
2128c2ecf20Sopenharmony_ci			debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
2138c2ecf20Sopenharmony_ci			break;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		case 0:
2168c2ecf20Sopenharmony_ci			debug("%s - io_start: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_start);
2178c2ecf20Sopenharmony_ci			debug("%s - io_end: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_end);
2188c2ecf20Sopenharmony_ci			debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
2198c2ecf20Sopenharmony_ci			break;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		case 2:
2228c2ecf20Sopenharmony_ci		case 4:
2238c2ecf20Sopenharmony_ci			debug("%s - wpegbbar: %lx\n", __func__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
2248c2ecf20Sopenharmony_ci			debug("%s - i2c_addr: %x\n", __func__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
2258c2ecf20Sopenharmony_ci			debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
2268c2ecf20Sopenharmony_ci			break;
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ciint __init ibmphp_access_ebda(void)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	u8 format, num_ctlrs, rio_complete, hs_complete, ebda_sz;
2348c2ecf20Sopenharmony_ci	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
2358c2ecf20Sopenharmony_ci	int rc = 0;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	rio_complete = 0;
2398c2ecf20Sopenharmony_ci	hs_complete = 0;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	io_mem = ioremap((0x40 << 4) + 0x0e, 2);
2428c2ecf20Sopenharmony_ci	if (!io_mem)
2438c2ecf20Sopenharmony_ci		return -ENOMEM;
2448c2ecf20Sopenharmony_ci	ebda_seg = readw(io_mem);
2458c2ecf20Sopenharmony_ci	iounmap(io_mem);
2468c2ecf20Sopenharmony_ci	debug("returned ebda segment: %x\n", ebda_seg);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	io_mem = ioremap(ebda_seg<<4, 1);
2498c2ecf20Sopenharmony_ci	if (!io_mem)
2508c2ecf20Sopenharmony_ci		return -ENOMEM;
2518c2ecf20Sopenharmony_ci	ebda_sz = readb(io_mem);
2528c2ecf20Sopenharmony_ci	iounmap(io_mem);
2538c2ecf20Sopenharmony_ci	debug("ebda size: %d(KiB)\n", ebda_sz);
2548c2ecf20Sopenharmony_ci	if (ebda_sz == 0)
2558c2ecf20Sopenharmony_ci		return -ENOMEM;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	io_mem = ioremap(ebda_seg<<4, (ebda_sz * 1024));
2588c2ecf20Sopenharmony_ci	if (!io_mem)
2598c2ecf20Sopenharmony_ci		return -ENOMEM;
2608c2ecf20Sopenharmony_ci	next_offset = 0x180;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	for (;;) {
2638c2ecf20Sopenharmony_ci		offset = next_offset;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		/* Make sure what we read is still in the mapped section */
2668c2ecf20Sopenharmony_ci		if (WARN(offset > (ebda_sz * 1024 - 4),
2678c2ecf20Sopenharmony_ci			 "ibmphp_ebda: next read is beyond ebda_sz\n"))
2688c2ecf20Sopenharmony_ci			break;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		next_offset = readw(io_mem + offset);	/* offset of next blk */
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		offset += 2;
2738c2ecf20Sopenharmony_ci		if (next_offset == 0)	/* 0 indicate it's last blk */
2748c2ecf20Sopenharmony_ci			break;
2758c2ecf20Sopenharmony_ci		blk_id = readw(io_mem + offset);	/* this blk id */
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		offset += 2;
2788c2ecf20Sopenharmony_ci		/* check if it is hot swap block or rio block */
2798c2ecf20Sopenharmony_ci		if (blk_id != 0x4853 && blk_id != 0x4752)
2808c2ecf20Sopenharmony_ci			continue;
2818c2ecf20Sopenharmony_ci		/* found hs table */
2828c2ecf20Sopenharmony_ci		if (blk_id == 0x4853) {
2838c2ecf20Sopenharmony_ci			debug("now enter hot swap block---\n");
2848c2ecf20Sopenharmony_ci			debug("hot blk id: %x\n", blk_id);
2858c2ecf20Sopenharmony_ci			format = readb(io_mem + offset);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci			offset += 1;
2888c2ecf20Sopenharmony_ci			if (format != 4)
2898c2ecf20Sopenharmony_ci				goto error_nodev;
2908c2ecf20Sopenharmony_ci			debug("hot blk format: %x\n", format);
2918c2ecf20Sopenharmony_ci			/* hot swap sub blk */
2928c2ecf20Sopenharmony_ci			base = offset;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci			sub_addr = base;
2958c2ecf20Sopenharmony_ci			re = readw(io_mem + sub_addr);	/* next sub blk */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci			sub_addr += 2;
2988c2ecf20Sopenharmony_ci			rc_id = readw(io_mem + sub_addr);	/* sub blk id */
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci			sub_addr += 2;
3018c2ecf20Sopenharmony_ci			if (rc_id != 0x5243)
3028c2ecf20Sopenharmony_ci				goto error_nodev;
3038c2ecf20Sopenharmony_ci			/* rc sub blk signature  */
3048c2ecf20Sopenharmony_ci			num_ctlrs = readb(io_mem + sub_addr);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci			sub_addr += 1;
3078c2ecf20Sopenharmony_ci			hpc_list_ptr = alloc_ebda_hpc_list();
3088c2ecf20Sopenharmony_ci			if (!hpc_list_ptr) {
3098c2ecf20Sopenharmony_ci				rc = -ENOMEM;
3108c2ecf20Sopenharmony_ci				goto out;
3118c2ecf20Sopenharmony_ci			}
3128c2ecf20Sopenharmony_ci			hpc_list_ptr->format = format;
3138c2ecf20Sopenharmony_ci			hpc_list_ptr->num_ctlrs = num_ctlrs;
3148c2ecf20Sopenharmony_ci			hpc_list_ptr->phys_addr = sub_addr;	/*  offset of RSRC_CONTROLLER blk */
3158c2ecf20Sopenharmony_ci			debug("info about hpc descriptor---\n");
3168c2ecf20Sopenharmony_ci			debug("hot blk format: %x\n", format);
3178c2ecf20Sopenharmony_ci			debug("num of controller: %x\n", num_ctlrs);
3188c2ecf20Sopenharmony_ci			debug("offset of hpc data structure entries: %x\n ", sub_addr);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci			sub_addr = base + re;	/* re sub blk */
3218c2ecf20Sopenharmony_ci			/* FIXME: rc is never used/checked */
3228c2ecf20Sopenharmony_ci			rc = readw(io_mem + sub_addr);	/* next sub blk */
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci			sub_addr += 2;
3258c2ecf20Sopenharmony_ci			re_id = readw(io_mem + sub_addr);	/* sub blk id */
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci			sub_addr += 2;
3288c2ecf20Sopenharmony_ci			if (re_id != 0x5245)
3298c2ecf20Sopenharmony_ci				goto error_nodev;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci			/* signature of re */
3328c2ecf20Sopenharmony_ci			num_entries = readw(io_mem + sub_addr);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci			sub_addr += 2;	/* offset of RSRC_ENTRIES blk */
3358c2ecf20Sopenharmony_ci			rsrc_list_ptr = alloc_ebda_rsrc_list();
3368c2ecf20Sopenharmony_ci			if (!rsrc_list_ptr) {
3378c2ecf20Sopenharmony_ci				rc = -ENOMEM;
3388c2ecf20Sopenharmony_ci				goto out;
3398c2ecf20Sopenharmony_ci			}
3408c2ecf20Sopenharmony_ci			rsrc_list_ptr->format = format;
3418c2ecf20Sopenharmony_ci			rsrc_list_ptr->num_entries = num_entries;
3428c2ecf20Sopenharmony_ci			rsrc_list_ptr->phys_addr = sub_addr;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci			debug("info about rsrc descriptor---\n");
3458c2ecf20Sopenharmony_ci			debug("format: %x\n", format);
3468c2ecf20Sopenharmony_ci			debug("num of rsrc: %x\n", num_entries);
3478c2ecf20Sopenharmony_ci			debug("offset of rsrc data structure entries: %x\n ", sub_addr);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci			hs_complete = 1;
3508c2ecf20Sopenharmony_ci		} else {
3518c2ecf20Sopenharmony_ci		/* found rio table, blk_id == 0x4752 */
3528c2ecf20Sopenharmony_ci			debug("now enter io table ---\n");
3538c2ecf20Sopenharmony_ci			debug("rio blk id: %x\n", blk_id);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci			rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL);
3568c2ecf20Sopenharmony_ci			if (!rio_table_ptr) {
3578c2ecf20Sopenharmony_ci				rc = -ENOMEM;
3588c2ecf20Sopenharmony_ci				goto out;
3598c2ecf20Sopenharmony_ci			}
3608c2ecf20Sopenharmony_ci			rio_table_ptr->ver_num = readb(io_mem + offset);
3618c2ecf20Sopenharmony_ci			rio_table_ptr->scal_count = readb(io_mem + offset + 1);
3628c2ecf20Sopenharmony_ci			rio_table_ptr->riodev_count = readb(io_mem + offset + 2);
3638c2ecf20Sopenharmony_ci			rio_table_ptr->offset = offset + 3 ;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci			debug("info about rio table hdr ---\n");
3668c2ecf20Sopenharmony_ci			debug("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ",
3678c2ecf20Sopenharmony_ci				rio_table_ptr->ver_num, rio_table_ptr->scal_count,
3688c2ecf20Sopenharmony_ci				rio_table_ptr->riodev_count, rio_table_ptr->offset);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci			rio_complete = 1;
3718c2ecf20Sopenharmony_ci		}
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (!hs_complete && !rio_complete)
3758c2ecf20Sopenharmony_ci		goto error_nodev;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if (rio_table_ptr) {
3788c2ecf20Sopenharmony_ci		if (rio_complete && rio_table_ptr->ver_num == 3) {
3798c2ecf20Sopenharmony_ci			rc = ebda_rio_table();
3808c2ecf20Sopenharmony_ci			if (rc)
3818c2ecf20Sopenharmony_ci				goto out;
3828c2ecf20Sopenharmony_ci		}
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci	rc = ebda_rsrc_controller();
3858c2ecf20Sopenharmony_ci	if (rc)
3868c2ecf20Sopenharmony_ci		goto out;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	rc = ebda_rsrc_rsrc();
3898c2ecf20Sopenharmony_ci	goto out;
3908c2ecf20Sopenharmony_cierror_nodev:
3918c2ecf20Sopenharmony_ci	rc = -ENODEV;
3928c2ecf20Sopenharmony_ciout:
3938c2ecf20Sopenharmony_ci	iounmap(io_mem);
3948c2ecf20Sopenharmony_ci	return rc;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci/*
3988c2ecf20Sopenharmony_ci * map info of scalability details and rio details from physical address
3998c2ecf20Sopenharmony_ci */
4008c2ecf20Sopenharmony_cistatic int __init ebda_rio_table(void)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	u16 offset;
4038c2ecf20Sopenharmony_ci	u8 i;
4048c2ecf20Sopenharmony_ci	struct rio_detail *rio_detail_ptr;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	offset = rio_table_ptr->offset;
4078c2ecf20Sopenharmony_ci	offset += 12 * rio_table_ptr->scal_count;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	// we do concern about rio details
4108c2ecf20Sopenharmony_ci	for (i = 0; i < rio_table_ptr->riodev_count; i++) {
4118c2ecf20Sopenharmony_ci		rio_detail_ptr = kzalloc(sizeof(struct rio_detail), GFP_KERNEL);
4128c2ecf20Sopenharmony_ci		if (!rio_detail_ptr)
4138c2ecf20Sopenharmony_ci			return -ENOMEM;
4148c2ecf20Sopenharmony_ci		rio_detail_ptr->rio_node_id = readb(io_mem + offset);
4158c2ecf20Sopenharmony_ci		rio_detail_ptr->bbar = readl(io_mem + offset + 1);
4168c2ecf20Sopenharmony_ci		rio_detail_ptr->rio_type = readb(io_mem + offset + 5);
4178c2ecf20Sopenharmony_ci		rio_detail_ptr->owner_id = readb(io_mem + offset + 6);
4188c2ecf20Sopenharmony_ci		rio_detail_ptr->port0_node_connect = readb(io_mem + offset + 7);
4198c2ecf20Sopenharmony_ci		rio_detail_ptr->port0_port_connect = readb(io_mem + offset + 8);
4208c2ecf20Sopenharmony_ci		rio_detail_ptr->port1_node_connect = readb(io_mem + offset + 9);
4218c2ecf20Sopenharmony_ci		rio_detail_ptr->port1_port_connect = readb(io_mem + offset + 10);
4228c2ecf20Sopenharmony_ci		rio_detail_ptr->first_slot_num = readb(io_mem + offset + 11);
4238c2ecf20Sopenharmony_ci		rio_detail_ptr->status = readb(io_mem + offset + 12);
4248c2ecf20Sopenharmony_ci		rio_detail_ptr->wpindex = readb(io_mem + offset + 13);
4258c2ecf20Sopenharmony_ci		rio_detail_ptr->chassis_num = readb(io_mem + offset + 14);
4268c2ecf20Sopenharmony_ci//		debug("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
4278c2ecf20Sopenharmony_ci		//create linked list of chassis
4288c2ecf20Sopenharmony_ci		if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5)
4298c2ecf20Sopenharmony_ci			list_add(&rio_detail_ptr->rio_detail_list, &rio_vg_head);
4308c2ecf20Sopenharmony_ci		//create linked list of expansion box
4318c2ecf20Sopenharmony_ci		else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7)
4328c2ecf20Sopenharmony_ci			list_add(&rio_detail_ptr->rio_detail_list, &rio_lo_head);
4338c2ecf20Sopenharmony_ci		else
4348c2ecf20Sopenharmony_ci			// not in my concern
4358c2ecf20Sopenharmony_ci			kfree(rio_detail_ptr);
4368c2ecf20Sopenharmony_ci		offset += 15;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci	print_lo_info();
4398c2ecf20Sopenharmony_ci	print_vg_info();
4408c2ecf20Sopenharmony_ci	return 0;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci/*
4448c2ecf20Sopenharmony_ci * reorganizing linked list of chassis
4458c2ecf20Sopenharmony_ci */
4468c2ecf20Sopenharmony_cistatic struct opt_rio *search_opt_vg(u8 chassis_num)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct opt_rio *ptr;
4498c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
4508c2ecf20Sopenharmony_ci		if (ptr->chassis_num == chassis_num)
4518c2ecf20Sopenharmony_ci			return ptr;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci	return NULL;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic int __init combine_wpg_for_chassis(void)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	struct opt_rio *opt_rio_ptr = NULL;
4598c2ecf20Sopenharmony_ci	struct rio_detail *rio_detail_ptr = NULL;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	list_for_each_entry(rio_detail_ptr, &rio_vg_head, rio_detail_list) {
4628c2ecf20Sopenharmony_ci		opt_rio_ptr = search_opt_vg(rio_detail_ptr->chassis_num);
4638c2ecf20Sopenharmony_ci		if (!opt_rio_ptr) {
4648c2ecf20Sopenharmony_ci			opt_rio_ptr = kzalloc(sizeof(struct opt_rio), GFP_KERNEL);
4658c2ecf20Sopenharmony_ci			if (!opt_rio_ptr)
4668c2ecf20Sopenharmony_ci				return -ENOMEM;
4678c2ecf20Sopenharmony_ci			opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
4688c2ecf20Sopenharmony_ci			opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
4698c2ecf20Sopenharmony_ci			opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
4708c2ecf20Sopenharmony_ci			opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
4718c2ecf20Sopenharmony_ci			list_add(&opt_rio_ptr->opt_rio_list, &opt_vg_head);
4728c2ecf20Sopenharmony_ci		} else {
4738c2ecf20Sopenharmony_ci			opt_rio_ptr->first_slot_num = min(opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
4748c2ecf20Sopenharmony_ci			opt_rio_ptr->middle_num = max(opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci	print_opt_vg();
4788c2ecf20Sopenharmony_ci	return 0;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/*
4828c2ecf20Sopenharmony_ci * reorganizing linked list of expansion box
4838c2ecf20Sopenharmony_ci */
4848c2ecf20Sopenharmony_cistatic struct opt_rio_lo *search_opt_lo(u8 chassis_num)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct opt_rio_lo *ptr;
4878c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &opt_lo_head, opt_rio_lo_list) {
4888c2ecf20Sopenharmony_ci		if (ptr->chassis_num == chassis_num)
4898c2ecf20Sopenharmony_ci			return ptr;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci	return NULL;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic int combine_wpg_for_expansion(void)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct opt_rio_lo *opt_rio_lo_ptr = NULL;
4978c2ecf20Sopenharmony_ci	struct rio_detail *rio_detail_ptr = NULL;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	list_for_each_entry(rio_detail_ptr, &rio_lo_head, rio_detail_list) {
5008c2ecf20Sopenharmony_ci		opt_rio_lo_ptr = search_opt_lo(rio_detail_ptr->chassis_num);
5018c2ecf20Sopenharmony_ci		if (!opt_rio_lo_ptr) {
5028c2ecf20Sopenharmony_ci			opt_rio_lo_ptr = kzalloc(sizeof(struct opt_rio_lo), GFP_KERNEL);
5038c2ecf20Sopenharmony_ci			if (!opt_rio_lo_ptr)
5048c2ecf20Sopenharmony_ci				return -ENOMEM;
5058c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
5068c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
5078c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
5088c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
5098c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->pack_count = 1;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci			list_add(&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
5128c2ecf20Sopenharmony_ci		} else {
5138c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->first_slot_num = min(opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
5148c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->middle_num = max(opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
5158c2ecf20Sopenharmony_ci			opt_rio_lo_ptr->pack_count = 2;
5168c2ecf20Sopenharmony_ci		}
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci	return 0;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci/* Since we don't know the max slot number per each chassis, hence go
5238c2ecf20Sopenharmony_ci * through the list of all chassis to find out the range
5248c2ecf20Sopenharmony_ci * Arguments: slot_num, 1st slot number of the chassis we think we are on,
5258c2ecf20Sopenharmony_ci * var (0 = chassis, 1 = expansion box)
5268c2ecf20Sopenharmony_ci */
5278c2ecf20Sopenharmony_cistatic int first_slot_num(u8 slot_num, u8 first_slot, u8 var)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct opt_rio *opt_vg_ptr = NULL;
5308c2ecf20Sopenharmony_ci	struct opt_rio_lo *opt_lo_ptr = NULL;
5318c2ecf20Sopenharmony_ci	int rc = 0;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (!var) {
5348c2ecf20Sopenharmony_ci		list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
5358c2ecf20Sopenharmony_ci			if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) {
5368c2ecf20Sopenharmony_ci				rc = -ENODEV;
5378c2ecf20Sopenharmony_ci				break;
5388c2ecf20Sopenharmony_ci			}
5398c2ecf20Sopenharmony_ci		}
5408c2ecf20Sopenharmony_ci	} else {
5418c2ecf20Sopenharmony_ci		list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
5428c2ecf20Sopenharmony_ci			if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
5438c2ecf20Sopenharmony_ci				rc = -ENODEV;
5448c2ecf20Sopenharmony_ci				break;
5458c2ecf20Sopenharmony_ci			}
5468c2ecf20Sopenharmony_ci		}
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci	return rc;
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic struct opt_rio_lo *find_rxe_num(u8 slot_num)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct opt_rio_lo *opt_lo_ptr;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
5568c2ecf20Sopenharmony_ci		//check to see if this slot_num belongs to expansion box
5578c2ecf20Sopenharmony_ci		if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num(slot_num, opt_lo_ptr->first_slot_num, 1)))
5588c2ecf20Sopenharmony_ci			return opt_lo_ptr;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci	return NULL;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic struct opt_rio *find_chassis_num(u8 slot_num)
5648c2ecf20Sopenharmony_ci{
5658c2ecf20Sopenharmony_ci	struct opt_rio *opt_vg_ptr;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
5688c2ecf20Sopenharmony_ci		//check to see if this slot_num belongs to chassis
5698c2ecf20Sopenharmony_ci		if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num(slot_num, opt_vg_ptr->first_slot_num, 0)))
5708c2ecf20Sopenharmony_ci			return opt_vg_ptr;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci	return NULL;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/* This routine will find out how many slots are in the chassis, so that
5768c2ecf20Sopenharmony_ci * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
5778c2ecf20Sopenharmony_ci */
5788c2ecf20Sopenharmony_cistatic u8 calculate_first_slot(u8 slot_num)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	u8 first_slot = 1;
5818c2ecf20Sopenharmony_ci	struct slot *slot_cur;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) {
5848c2ecf20Sopenharmony_ci		if (slot_cur->ctrl) {
5858c2ecf20Sopenharmony_ci			if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num))
5868c2ecf20Sopenharmony_ci				first_slot = slot_cur->ctrl->ending_slot_num;
5878c2ecf20Sopenharmony_ci		}
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci	return first_slot + 1;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci#define SLOT_NAME_SIZE 30
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic char *create_file_name(struct slot *slot_cur)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	struct opt_rio *opt_vg_ptr = NULL;
5988c2ecf20Sopenharmony_ci	struct opt_rio_lo *opt_lo_ptr = NULL;
5998c2ecf20Sopenharmony_ci	static char str[SLOT_NAME_SIZE];
6008c2ecf20Sopenharmony_ci	int which = 0; /* rxe = 1, chassis = 0 */
6018c2ecf20Sopenharmony_ci	u8 number = 1; /* either chassis or rxe # */
6028c2ecf20Sopenharmony_ci	u8 first_slot = 1;
6038c2ecf20Sopenharmony_ci	u8 slot_num;
6048c2ecf20Sopenharmony_ci	u8 flag = 0;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (!slot_cur) {
6078c2ecf20Sopenharmony_ci		err("Structure passed is empty\n");
6088c2ecf20Sopenharmony_ci		return NULL;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	slot_num = slot_cur->number;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	memset(str, 0, sizeof(str));
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	if (rio_table_ptr) {
6168c2ecf20Sopenharmony_ci		if (rio_table_ptr->ver_num == 3) {
6178c2ecf20Sopenharmony_ci			opt_vg_ptr = find_chassis_num(slot_num);
6188c2ecf20Sopenharmony_ci			opt_lo_ptr = find_rxe_num(slot_num);
6198c2ecf20Sopenharmony_ci		}
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci	if (opt_vg_ptr) {
6228c2ecf20Sopenharmony_ci		if (opt_lo_ptr) {
6238c2ecf20Sopenharmony_ci			if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
6248c2ecf20Sopenharmony_ci				number = opt_lo_ptr->chassis_num;
6258c2ecf20Sopenharmony_ci				first_slot = opt_lo_ptr->first_slot_num;
6268c2ecf20Sopenharmony_ci				which = 1; /* it is RXE */
6278c2ecf20Sopenharmony_ci			} else {
6288c2ecf20Sopenharmony_ci				first_slot = opt_vg_ptr->first_slot_num;
6298c2ecf20Sopenharmony_ci				number = opt_vg_ptr->chassis_num;
6308c2ecf20Sopenharmony_ci				which = 0;
6318c2ecf20Sopenharmony_ci			}
6328c2ecf20Sopenharmony_ci		} else {
6338c2ecf20Sopenharmony_ci			first_slot = opt_vg_ptr->first_slot_num;
6348c2ecf20Sopenharmony_ci			number = opt_vg_ptr->chassis_num;
6358c2ecf20Sopenharmony_ci			which = 0;
6368c2ecf20Sopenharmony_ci		}
6378c2ecf20Sopenharmony_ci		++flag;
6388c2ecf20Sopenharmony_ci	} else if (opt_lo_ptr) {
6398c2ecf20Sopenharmony_ci		number = opt_lo_ptr->chassis_num;
6408c2ecf20Sopenharmony_ci		first_slot = opt_lo_ptr->first_slot_num;
6418c2ecf20Sopenharmony_ci		which = 1;
6428c2ecf20Sopenharmony_ci		++flag;
6438c2ecf20Sopenharmony_ci	} else if (rio_table_ptr) {
6448c2ecf20Sopenharmony_ci		if (rio_table_ptr->ver_num == 3) {
6458c2ecf20Sopenharmony_ci			/* if both NULL and we DO have correct RIO table in BIOS */
6468c2ecf20Sopenharmony_ci			return NULL;
6478c2ecf20Sopenharmony_ci		}
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci	if (!flag) {
6508c2ecf20Sopenharmony_ci		if (slot_cur->ctrl->ctlr_type == 4) {
6518c2ecf20Sopenharmony_ci			first_slot = calculate_first_slot(slot_num);
6528c2ecf20Sopenharmony_ci			which = 1;
6538c2ecf20Sopenharmony_ci		} else {
6548c2ecf20Sopenharmony_ci			which = 0;
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	sprintf(str, "%s%dslot%d",
6598c2ecf20Sopenharmony_ci		which == 0 ? "chassis" : "rxe",
6608c2ecf20Sopenharmony_ci		number, slot_num - first_slot + 1);
6618c2ecf20Sopenharmony_ci	return str;
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_cistatic int fillslotinfo(struct hotplug_slot *hotplug_slot)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	struct slot *slot;
6678c2ecf20Sopenharmony_ci	int rc = 0;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	slot = to_slot(hotplug_slot);
6708c2ecf20Sopenharmony_ci	rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL);
6718c2ecf20Sopenharmony_ci	return rc;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic struct pci_driver ibmphp_driver;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci/*
6778c2ecf20Sopenharmony_ci * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
6788c2ecf20Sopenharmony_ci * each hpc from physical address to a list of hot plug controllers based on
6798c2ecf20Sopenharmony_ci * hpc descriptors.
6808c2ecf20Sopenharmony_ci */
6818c2ecf20Sopenharmony_cistatic int __init ebda_rsrc_controller(void)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	u16 addr, addr_slot, addr_bus;
6848c2ecf20Sopenharmony_ci	u8 ctlr_id, temp, bus_index;
6858c2ecf20Sopenharmony_ci	u16 ctlr, slot, bus;
6868c2ecf20Sopenharmony_ci	u16 slot_num, bus_num, index;
6878c2ecf20Sopenharmony_ci	struct controller *hpc_ptr;
6888c2ecf20Sopenharmony_ci	struct ebda_hpc_bus *bus_ptr;
6898c2ecf20Sopenharmony_ci	struct ebda_hpc_slot *slot_ptr;
6908c2ecf20Sopenharmony_ci	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
6918c2ecf20Sopenharmony_ci	int rc;
6928c2ecf20Sopenharmony_ci	struct slot *tmp_slot;
6938c2ecf20Sopenharmony_ci	char name[SLOT_NAME_SIZE];
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	addr = hpc_list_ptr->phys_addr;
6968c2ecf20Sopenharmony_ci	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
6978c2ecf20Sopenharmony_ci		bus_index = 1;
6988c2ecf20Sopenharmony_ci		ctlr_id = readb(io_mem + addr);
6998c2ecf20Sopenharmony_ci		addr += 1;
7008c2ecf20Sopenharmony_ci		slot_num = readb(io_mem + addr);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci		addr += 1;
7038c2ecf20Sopenharmony_ci		addr_slot = addr;	/* offset of slot structure */
7048c2ecf20Sopenharmony_ci		addr += (slot_num * 4);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci		bus_num = readb(io_mem + addr);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci		addr += 1;
7098c2ecf20Sopenharmony_ci		addr_bus = addr;	/* offset of bus */
7108c2ecf20Sopenharmony_ci		addr += (bus_num * 9);	/* offset of ctlr_type */
7118c2ecf20Sopenharmony_ci		temp = readb(io_mem + addr);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci		addr += 1;
7148c2ecf20Sopenharmony_ci		/* init hpc structure */
7158c2ecf20Sopenharmony_ci		hpc_ptr = alloc_ebda_hpc(slot_num, bus_num);
7168c2ecf20Sopenharmony_ci		if (!hpc_ptr) {
7178c2ecf20Sopenharmony_ci			return -ENOMEM;
7188c2ecf20Sopenharmony_ci		}
7198c2ecf20Sopenharmony_ci		hpc_ptr->ctlr_id = ctlr_id;
7208c2ecf20Sopenharmony_ci		hpc_ptr->ctlr_relative_id = ctlr;
7218c2ecf20Sopenharmony_ci		hpc_ptr->slot_count = slot_num;
7228c2ecf20Sopenharmony_ci		hpc_ptr->bus_count = bus_num;
7238c2ecf20Sopenharmony_ci		debug("now enter ctlr data structure ---\n");
7248c2ecf20Sopenharmony_ci		debug("ctlr id: %x\n", ctlr_id);
7258c2ecf20Sopenharmony_ci		debug("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id);
7268c2ecf20Sopenharmony_ci		debug("count of slots controlled by this ctlr: %x\n", slot_num);
7278c2ecf20Sopenharmony_ci		debug("count of buses controlled by this ctlr: %x\n", bus_num);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci		/* init slot structure, fetch slot, bus, cap... */
7308c2ecf20Sopenharmony_ci		slot_ptr = hpc_ptr->slots;
7318c2ecf20Sopenharmony_ci		for (slot = 0; slot < slot_num; slot++) {
7328c2ecf20Sopenharmony_ci			slot_ptr->slot_num = readb(io_mem + addr_slot);
7338c2ecf20Sopenharmony_ci			slot_ptr->slot_bus_num = readb(io_mem + addr_slot + slot_num);
7348c2ecf20Sopenharmony_ci			slot_ptr->ctl_index = readb(io_mem + addr_slot + 2*slot_num);
7358c2ecf20Sopenharmony_ci			slot_ptr->slot_cap = readb(io_mem + addr_slot + 3*slot_num);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci			// create bus_info lined list --- if only one slot per bus: slot_min = slot_max
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci			bus_info_ptr2 = ibmphp_find_same_bus_num(slot_ptr->slot_bus_num);
7408c2ecf20Sopenharmony_ci			if (!bus_info_ptr2) {
7418c2ecf20Sopenharmony_ci				bus_info_ptr1 = kzalloc(sizeof(struct bus_info), GFP_KERNEL);
7428c2ecf20Sopenharmony_ci				if (!bus_info_ptr1) {
7438c2ecf20Sopenharmony_ci					rc = -ENOMEM;
7448c2ecf20Sopenharmony_ci					goto error_no_slot;
7458c2ecf20Sopenharmony_ci				}
7468c2ecf20Sopenharmony_ci				bus_info_ptr1->slot_min = slot_ptr->slot_num;
7478c2ecf20Sopenharmony_ci				bus_info_ptr1->slot_max = slot_ptr->slot_num;
7488c2ecf20Sopenharmony_ci				bus_info_ptr1->slot_count += 1;
7498c2ecf20Sopenharmony_ci				bus_info_ptr1->busno = slot_ptr->slot_bus_num;
7508c2ecf20Sopenharmony_ci				bus_info_ptr1->index = bus_index++;
7518c2ecf20Sopenharmony_ci				bus_info_ptr1->current_speed = 0xff;
7528c2ecf20Sopenharmony_ci				bus_info_ptr1->current_bus_mode = 0xff;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci				list_add_tail(&bus_info_ptr1->bus_info_list, &bus_info_head);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci			} else {
7598c2ecf20Sopenharmony_ci				bus_info_ptr2->slot_min = min(bus_info_ptr2->slot_min, slot_ptr->slot_num);
7608c2ecf20Sopenharmony_ci				bus_info_ptr2->slot_max = max(bus_info_ptr2->slot_max, slot_ptr->slot_num);
7618c2ecf20Sopenharmony_ci				bus_info_ptr2->slot_count += 1;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci			}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci			// end of creating the bus_info linked list
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci			slot_ptr++;
7688c2ecf20Sopenharmony_ci			addr_slot += 1;
7698c2ecf20Sopenharmony_ci		}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		/* init bus structure */
7728c2ecf20Sopenharmony_ci		bus_ptr = hpc_ptr->buses;
7738c2ecf20Sopenharmony_ci		for (bus = 0; bus < bus_num; bus++) {
7748c2ecf20Sopenharmony_ci			bus_ptr->bus_num = readb(io_mem + addr_bus + bus);
7758c2ecf20Sopenharmony_ci			bus_ptr->slots_at_33_conv = readb(io_mem + addr_bus + bus_num + 8 * bus);
7768c2ecf20Sopenharmony_ci			bus_ptr->slots_at_66_conv = readb(io_mem + addr_bus + bus_num + 8 * bus + 1);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci			bus_ptr->slots_at_66_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 2);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci			bus_ptr->slots_at_100_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 3);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci			bus_ptr->slots_at_133_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 4);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci			bus_info_ptr2 = ibmphp_find_same_bus_num(bus_ptr->bus_num);
7858c2ecf20Sopenharmony_ci			if (bus_info_ptr2) {
7868c2ecf20Sopenharmony_ci				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
7878c2ecf20Sopenharmony_ci				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
7888c2ecf20Sopenharmony_ci				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
7898c2ecf20Sopenharmony_ci				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
7908c2ecf20Sopenharmony_ci				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix;
7918c2ecf20Sopenharmony_ci			}
7928c2ecf20Sopenharmony_ci			bus_ptr++;
7938c2ecf20Sopenharmony_ci		}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci		hpc_ptr->ctlr_type = temp;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		switch (hpc_ptr->ctlr_type) {
7988c2ecf20Sopenharmony_ci			case 1:
7998c2ecf20Sopenharmony_ci				hpc_ptr->u.pci_ctlr.bus = readb(io_mem + addr);
8008c2ecf20Sopenharmony_ci				hpc_ptr->u.pci_ctlr.dev_fun = readb(io_mem + addr + 1);
8018c2ecf20Sopenharmony_ci				hpc_ptr->irq = readb(io_mem + addr + 2);
8028c2ecf20Sopenharmony_ci				addr += 3;
8038c2ecf20Sopenharmony_ci				debug("ctrl bus = %x, ctlr devfun = %x, irq = %x\n",
8048c2ecf20Sopenharmony_ci					hpc_ptr->u.pci_ctlr.bus,
8058c2ecf20Sopenharmony_ci					hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
8068c2ecf20Sopenharmony_ci				break;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci			case 0:
8098c2ecf20Sopenharmony_ci				hpc_ptr->u.isa_ctlr.io_start = readw(io_mem + addr);
8108c2ecf20Sopenharmony_ci				hpc_ptr->u.isa_ctlr.io_end = readw(io_mem + addr + 2);
8118c2ecf20Sopenharmony_ci				if (!request_region(hpc_ptr->u.isa_ctlr.io_start,
8128c2ecf20Sopenharmony_ci						     (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
8138c2ecf20Sopenharmony_ci						     "ibmphp")) {
8148c2ecf20Sopenharmony_ci					rc = -ENODEV;
8158c2ecf20Sopenharmony_ci					goto error_no_slot;
8168c2ecf20Sopenharmony_ci				}
8178c2ecf20Sopenharmony_ci				hpc_ptr->irq = readb(io_mem + addr + 4);
8188c2ecf20Sopenharmony_ci				addr += 5;
8198c2ecf20Sopenharmony_ci				break;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci			case 2:
8228c2ecf20Sopenharmony_ci			case 4:
8238c2ecf20Sopenharmony_ci				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl(io_mem + addr);
8248c2ecf20Sopenharmony_ci				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb(io_mem + addr + 4);
8258c2ecf20Sopenharmony_ci				hpc_ptr->irq = readb(io_mem + addr + 5);
8268c2ecf20Sopenharmony_ci				addr += 6;
8278c2ecf20Sopenharmony_ci				break;
8288c2ecf20Sopenharmony_ci			default:
8298c2ecf20Sopenharmony_ci				rc = -ENODEV;
8308c2ecf20Sopenharmony_ci				goto error_no_slot;
8318c2ecf20Sopenharmony_ci		}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci		//reorganize chassis' linked list
8348c2ecf20Sopenharmony_ci		combine_wpg_for_chassis();
8358c2ecf20Sopenharmony_ci		combine_wpg_for_expansion();
8368c2ecf20Sopenharmony_ci		hpc_ptr->revision = 0xff;
8378c2ecf20Sopenharmony_ci		hpc_ptr->options = 0xff;
8388c2ecf20Sopenharmony_ci		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
8398c2ecf20Sopenharmony_ci		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		// register slots with hpc core as well as create linked list of ibm slot
8428c2ecf20Sopenharmony_ci		for (index = 0; index < hpc_ptr->slot_count; index++) {
8438c2ecf20Sopenharmony_ci			tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL);
8448c2ecf20Sopenharmony_ci			if (!tmp_slot) {
8458c2ecf20Sopenharmony_ci				rc = -ENOMEM;
8468c2ecf20Sopenharmony_ci				goto error_no_slot;
8478c2ecf20Sopenharmony_ci			}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci			tmp_slot->flag = 1;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci			tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
8528c2ecf20Sopenharmony_ci			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
8538c2ecf20Sopenharmony_ci				tmp_slot->supported_speed =  3;
8548c2ecf20Sopenharmony_ci			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
8558c2ecf20Sopenharmony_ci				tmp_slot->supported_speed =  2;
8568c2ecf20Sopenharmony_ci			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
8578c2ecf20Sopenharmony_ci				tmp_slot->supported_speed =  1;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
8608c2ecf20Sopenharmony_ci				tmp_slot->supported_bus_mode = 1;
8618c2ecf20Sopenharmony_ci			else
8628c2ecf20Sopenharmony_ci				tmp_slot->supported_bus_mode = 0;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci			tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci			bus_info_ptr1 = ibmphp_find_same_bus_num(hpc_ptr->slots[index].slot_bus_num);
8688c2ecf20Sopenharmony_ci			if (!bus_info_ptr1) {
8698c2ecf20Sopenharmony_ci				rc = -ENODEV;
8708c2ecf20Sopenharmony_ci				goto error;
8718c2ecf20Sopenharmony_ci			}
8728c2ecf20Sopenharmony_ci			tmp_slot->bus_on = bus_info_ptr1;
8738c2ecf20Sopenharmony_ci			bus_info_ptr1 = NULL;
8748c2ecf20Sopenharmony_ci			tmp_slot->ctrl = hpc_ptr;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci			tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
8778c2ecf20Sopenharmony_ci			tmp_slot->number = hpc_ptr->slots[index].slot_num;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci			rc = fillslotinfo(&tmp_slot->hotplug_slot);
8808c2ecf20Sopenharmony_ci			if (rc)
8818c2ecf20Sopenharmony_ci				goto error;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci			rc = ibmphp_init_devno(&tmp_slot);
8848c2ecf20Sopenharmony_ci			if (rc)
8858c2ecf20Sopenharmony_ci				goto error;
8868c2ecf20Sopenharmony_ci			tmp_slot->hotplug_slot.ops = &ibmphp_hotplug_slot_ops;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci			// end of registering ibm slot with hotplug core
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci			list_add(&tmp_slot->ibm_slot_list, &ibmphp_slot_head);
8918c2ecf20Sopenharmony_ci		}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		print_bus_info();
8948c2ecf20Sopenharmony_ci		list_add(&hpc_ptr->ebda_hpc_list, &ebda_hpc_head);
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	}			/* each hpc  */
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) {
8998c2ecf20Sopenharmony_ci		snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot));
9008c2ecf20Sopenharmony_ci		pci_hp_register(&tmp_slot->hotplug_slot,
9018c2ecf20Sopenharmony_ci			pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name);
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	print_ebda_hpc();
9058c2ecf20Sopenharmony_ci	print_ibm_slot();
9068c2ecf20Sopenharmony_ci	return 0;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cierror:
9098c2ecf20Sopenharmony_ci	kfree(tmp_slot);
9108c2ecf20Sopenharmony_cierror_no_slot:
9118c2ecf20Sopenharmony_ci	free_ebda_hpc(hpc_ptr);
9128c2ecf20Sopenharmony_ci	return rc;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci/*
9168c2ecf20Sopenharmony_ci * map info (bus, devfun, start addr, end addr..) of i/o, memory,
9178c2ecf20Sopenharmony_ci * pfm from the physical addr to a list of resource.
9188c2ecf20Sopenharmony_ci */
9198c2ecf20Sopenharmony_cistatic int __init ebda_rsrc_rsrc(void)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	u16 addr;
9228c2ecf20Sopenharmony_ci	short rsrc;
9238c2ecf20Sopenharmony_ci	u8 type, rsrc_type;
9248c2ecf20Sopenharmony_ci	struct ebda_pci_rsrc *rsrc_ptr;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	addr = rsrc_list_ptr->phys_addr;
9278c2ecf20Sopenharmony_ci	debug("now entering rsrc land\n");
9288c2ecf20Sopenharmony_ci	debug("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) {
9318c2ecf20Sopenharmony_ci		type = readb(io_mem + addr);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci		addr += 1;
9348c2ecf20Sopenharmony_ci		rsrc_type = type & EBDA_RSRC_TYPE_MASK;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci		if (rsrc_type == EBDA_IO_RSRC_TYPE) {
9378c2ecf20Sopenharmony_ci			rsrc_ptr = alloc_ebda_pci_rsrc();
9388c2ecf20Sopenharmony_ci			if (!rsrc_ptr) {
9398c2ecf20Sopenharmony_ci				iounmap(io_mem);
9408c2ecf20Sopenharmony_ci				return -ENOMEM;
9418c2ecf20Sopenharmony_ci			}
9428c2ecf20Sopenharmony_ci			rsrc_ptr->rsrc_type = type;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci			rsrc_ptr->bus_num = readb(io_mem + addr);
9458c2ecf20Sopenharmony_ci			rsrc_ptr->dev_fun = readb(io_mem + addr + 1);
9468c2ecf20Sopenharmony_ci			rsrc_ptr->start_addr = readw(io_mem + addr + 2);
9478c2ecf20Sopenharmony_ci			rsrc_ptr->end_addr = readw(io_mem + addr + 4);
9488c2ecf20Sopenharmony_ci			addr += 6;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci			debug("rsrc from io type ----\n");
9518c2ecf20Sopenharmony_ci			debug("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
9528c2ecf20Sopenharmony_ci				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci			list_add(&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
9558c2ecf20Sopenharmony_ci		}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci		if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) {
9588c2ecf20Sopenharmony_ci			rsrc_ptr = alloc_ebda_pci_rsrc();
9598c2ecf20Sopenharmony_ci			if (!rsrc_ptr) {
9608c2ecf20Sopenharmony_ci				iounmap(io_mem);
9618c2ecf20Sopenharmony_ci				return -ENOMEM;
9628c2ecf20Sopenharmony_ci			}
9638c2ecf20Sopenharmony_ci			rsrc_ptr->rsrc_type = type;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci			rsrc_ptr->bus_num = readb(io_mem + addr);
9668c2ecf20Sopenharmony_ci			rsrc_ptr->dev_fun = readb(io_mem + addr + 1);
9678c2ecf20Sopenharmony_ci			rsrc_ptr->start_addr = readl(io_mem + addr + 2);
9688c2ecf20Sopenharmony_ci			rsrc_ptr->end_addr = readl(io_mem + addr + 6);
9698c2ecf20Sopenharmony_ci			addr += 10;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci			debug("rsrc from mem or pfm ---\n");
9728c2ecf20Sopenharmony_ci			debug("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
9738c2ecf20Sopenharmony_ci				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci			list_add(&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
9768c2ecf20Sopenharmony_ci		}
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci	kfree(rsrc_list_ptr);
9798c2ecf20Sopenharmony_ci	rsrc_list_ptr = NULL;
9808c2ecf20Sopenharmony_ci	print_ebda_pci_rsrc();
9818c2ecf20Sopenharmony_ci	return 0;
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ciu16 ibmphp_get_total_controllers(void)
9858c2ecf20Sopenharmony_ci{
9868c2ecf20Sopenharmony_ci	return hpc_list_ptr->num_ctlrs;
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_cistruct slot *ibmphp_get_slot_from_physical_num(u8 physical_num)
9908c2ecf20Sopenharmony_ci{
9918c2ecf20Sopenharmony_ci	struct slot *slot;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	list_for_each_entry(slot, &ibmphp_slot_head, ibm_slot_list) {
9948c2ecf20Sopenharmony_ci		if (slot->number == physical_num)
9958c2ecf20Sopenharmony_ci			return slot;
9968c2ecf20Sopenharmony_ci	}
9978c2ecf20Sopenharmony_ci	return NULL;
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci/* To find:
10018c2ecf20Sopenharmony_ci *	- the smallest slot number
10028c2ecf20Sopenharmony_ci *	- the largest slot number
10038c2ecf20Sopenharmony_ci *	- the total number of the slots based on each bus
10048c2ecf20Sopenharmony_ci *	  (if only one slot per bus slot_min = slot_max )
10058c2ecf20Sopenharmony_ci */
10068c2ecf20Sopenharmony_cistruct bus_info *ibmphp_find_same_bus_num(u32 num)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct bus_info *ptr;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
10118c2ecf20Sopenharmony_ci		if (ptr->busno == num)
10128c2ecf20Sopenharmony_ci			 return ptr;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci	return NULL;
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci/*  Finding relative bus number, in order to map corresponding
10188c2ecf20Sopenharmony_ci *  bus register
10198c2ecf20Sopenharmony_ci */
10208c2ecf20Sopenharmony_ciint ibmphp_get_bus_index(u8 num)
10218c2ecf20Sopenharmony_ci{
10228c2ecf20Sopenharmony_ci	struct bus_info *ptr;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
10258c2ecf20Sopenharmony_ci		if (ptr->busno == num)
10268c2ecf20Sopenharmony_ci			return ptr->index;
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci	return -ENODEV;
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_civoid ibmphp_free_bus_info_queue(void)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct bus_info *bus_info, *next;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	list_for_each_entry_safe(bus_info, next, &bus_info_head,
10368c2ecf20Sopenharmony_ci				 bus_info_list) {
10378c2ecf20Sopenharmony_ci		kfree (bus_info);
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_civoid ibmphp_free_ebda_hpc_queue(void)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	struct controller *controller = NULL, *next;
10448c2ecf20Sopenharmony_ci	int pci_flag = 0;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	list_for_each_entry_safe(controller, next, &ebda_hpc_head,
10478c2ecf20Sopenharmony_ci				 ebda_hpc_list) {
10488c2ecf20Sopenharmony_ci		if (controller->ctlr_type == 0)
10498c2ecf20Sopenharmony_ci			release_region(controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
10508c2ecf20Sopenharmony_ci		else if ((controller->ctlr_type == 1) && (!pci_flag)) {
10518c2ecf20Sopenharmony_ci			++pci_flag;
10528c2ecf20Sopenharmony_ci			pci_unregister_driver(&ibmphp_driver);
10538c2ecf20Sopenharmony_ci		}
10548c2ecf20Sopenharmony_ci		free_ebda_hpc(controller);
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_civoid ibmphp_free_ebda_pci_rsrc_queue(void)
10598c2ecf20Sopenharmony_ci{
10608c2ecf20Sopenharmony_ci	struct ebda_pci_rsrc *resource, *next;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	list_for_each_entry_safe(resource, next, &ibmphp_ebda_pci_rsrc_head,
10638c2ecf20Sopenharmony_ci				 ebda_pci_rsrc_list) {
10648c2ecf20Sopenharmony_ci		kfree (resource);
10658c2ecf20Sopenharmony_ci		resource = NULL;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_cistatic const struct pci_device_id id_table[] = {
10708c2ecf20Sopenharmony_ci	{
10718c2ecf20Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_IBM,
10728c2ecf20Sopenharmony_ci		.device		= HPC_DEVICE_ID,
10738c2ecf20Sopenharmony_ci		.subvendor	= PCI_VENDOR_ID_IBM,
10748c2ecf20Sopenharmony_ci		.subdevice	= HPC_SUBSYSTEM_ID,
10758c2ecf20Sopenharmony_ci		.class		= ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
10768c2ecf20Sopenharmony_ci	}, {}
10778c2ecf20Sopenharmony_ci};
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, id_table);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_cistatic int ibmphp_probe(struct pci_dev *, const struct pci_device_id *);
10828c2ecf20Sopenharmony_cistatic struct pci_driver ibmphp_driver = {
10838c2ecf20Sopenharmony_ci	.name		= "ibmphp",
10848c2ecf20Sopenharmony_ci	.id_table	= id_table,
10858c2ecf20Sopenharmony_ci	.probe		= ibmphp_probe,
10868c2ecf20Sopenharmony_ci};
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ciint ibmphp_register_pci(void)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	struct controller *ctrl;
10918c2ecf20Sopenharmony_ci	int rc = 0;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
10948c2ecf20Sopenharmony_ci		if (ctrl->ctlr_type == 1) {
10958c2ecf20Sopenharmony_ci			rc = pci_register_driver(&ibmphp_driver);
10968c2ecf20Sopenharmony_ci			break;
10978c2ecf20Sopenharmony_ci		}
10988c2ecf20Sopenharmony_ci	}
10998c2ecf20Sopenharmony_ci	return rc;
11008c2ecf20Sopenharmony_ci}
11018c2ecf20Sopenharmony_cistatic int ibmphp_probe(struct pci_dev *dev, const struct pci_device_id *ids)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	struct controller *ctrl;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	debug("inside ibmphp_probe\n");
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
11088c2ecf20Sopenharmony_ci		if (ctrl->ctlr_type == 1) {
11098c2ecf20Sopenharmony_ci			if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
11108c2ecf20Sopenharmony_ci				ctrl->ctrl_dev = dev;
11118c2ecf20Sopenharmony_ci				debug("found device!!!\n");
11128c2ecf20Sopenharmony_ci				debug("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
11138c2ecf20Sopenharmony_ci				return 0;
11148c2ecf20Sopenharmony_ci			}
11158c2ecf20Sopenharmony_ci		}
11168c2ecf20Sopenharmony_ci	}
11178c2ecf20Sopenharmony_ci	return -ENODEV;
11188c2ecf20Sopenharmony_ci}
1119