1736759efSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * IBM Hot Plug Controller Driver
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Written By: Tong Yu, IBM Corporation
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
81da177e4SLinus Torvalds  * Copyright (C) 2001-2003 IBM Corp.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * All rights reserved.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Send feedback to <gregkh@us.ibm.com>
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/errno.h>
181da177e4SLinus Torvalds #include <linux/mm.h>
191da177e4SLinus Torvalds #include <linux/slab.h>
201da177e4SLinus Torvalds #include <linux/pci.h>
211da177e4SLinus Torvalds #include <linux/list.h>
221da177e4SLinus Torvalds #include <linux/init.h>
231da177e4SLinus Torvalds #include "ibmphp.h"
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds /*
261da177e4SLinus Torvalds  * POST builds data blocks(in this data block definition, a char-1
271da177e4SLinus Torvalds  * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended
281da177e4SLinus Torvalds  * BIOS Data Area which describe the configuration of the hot-plug
291da177e4SLinus Torvalds  * controllers and resources used by the PCI Hot-Plug devices.
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  * This file walks EBDA, maps data block from physical addr,
321da177e4SLinus Torvalds  * reconstruct linked lists about all system resource(MEM, PFM, IO)
331da177e4SLinus Torvalds  * already assigned by POST, as well as linked lists about hot plug
341da177e4SLinus Torvalds  * controllers (ctlr#, slot#, bus&slot features...)
351da177e4SLinus Torvalds  */
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds /* Global lists */
381da177e4SLinus Torvalds LIST_HEAD(ibmphp_ebda_pci_rsrc_head);
391da177e4SLinus Torvalds LIST_HEAD(ibmphp_slot_head);
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds /* Local variables */
421da177e4SLinus Torvalds static struct ebda_hpc_list *hpc_list_ptr;
431da177e4SLinus Torvalds static struct ebda_rsrc_list *rsrc_list_ptr;
441da177e4SLinus Torvalds static struct rio_table_hdr *rio_table_ptr = NULL;
451da177e4SLinus Torvalds static LIST_HEAD(ebda_hpc_head);
461da177e4SLinus Torvalds static LIST_HEAD(bus_info_head);
471da177e4SLinus Torvalds static LIST_HEAD(rio_vg_head);
481da177e4SLinus Torvalds static LIST_HEAD(rio_lo_head);
491da177e4SLinus Torvalds static LIST_HEAD(opt_vg_head);
501da177e4SLinus Torvalds static LIST_HEAD(opt_lo_head);
511da177e4SLinus Torvalds static void __iomem *io_mem;
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds /* Local functions */
541da177e4SLinus Torvalds static int ebda_rsrc_controller(void);
551da177e4SLinus Torvalds static int ebda_rsrc_rsrc(void);
561da177e4SLinus Torvalds static int ebda_rio_table(void);
571da177e4SLinus Torvalds 
alloc_ebda_hpc_list(void)581da177e4SLinus Torvalds static struct ebda_hpc_list * __init alloc_ebda_hpc_list(void)
591da177e4SLinus Torvalds {
60f5afe806SEric Sesterhenn 	return kzalloc(sizeof(struct ebda_hpc_list), GFP_KERNEL);
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
alloc_ebda_hpc(u32 slot_count,u32 bus_count)631da177e4SLinus Torvalds static struct controller *alloc_ebda_hpc(u32 slot_count, u32 bus_count)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	struct controller *controller;
661da177e4SLinus Torvalds 	struct ebda_hpc_slot *slots;
671da177e4SLinus Torvalds 	struct ebda_hpc_bus *buses;
681da177e4SLinus Torvalds 
69f5afe806SEric Sesterhenn 	controller = kzalloc(sizeof(struct controller), GFP_KERNEL);
701da177e4SLinus Torvalds 	if (!controller)
711da177e4SLinus Torvalds 		goto error;
721da177e4SLinus Torvalds 
73f5afe806SEric Sesterhenn 	slots = kcalloc(slot_count, sizeof(struct ebda_hpc_slot), GFP_KERNEL);
741da177e4SLinus Torvalds 	if (!slots)
751da177e4SLinus Torvalds 		goto error_contr;
761da177e4SLinus Torvalds 	controller->slots = slots;
771da177e4SLinus Torvalds 
78f5afe806SEric Sesterhenn 	buses = kcalloc(bus_count, sizeof(struct ebda_hpc_bus), GFP_KERNEL);
791da177e4SLinus Torvalds 	if (!buses)
801da177e4SLinus Torvalds 		goto error_slots;
811da177e4SLinus Torvalds 	controller->buses = buses;
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds 	return controller;
841da177e4SLinus Torvalds error_slots:
851da177e4SLinus Torvalds 	kfree(controller->slots);
861da177e4SLinus Torvalds error_contr:
871da177e4SLinus Torvalds 	kfree(controller);
881da177e4SLinus Torvalds error:
891da177e4SLinus Torvalds 	return NULL;
901da177e4SLinus Torvalds }
911da177e4SLinus Torvalds 
free_ebda_hpc(struct controller * controller)921da177e4SLinus Torvalds static void free_ebda_hpc(struct controller *controller)
931da177e4SLinus Torvalds {
941da177e4SLinus Torvalds 	kfree(controller->slots);
951da177e4SLinus Torvalds 	kfree(controller->buses);
961da177e4SLinus Torvalds 	kfree(controller);
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
alloc_ebda_rsrc_list(void)991da177e4SLinus Torvalds static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list(void)
1001da177e4SLinus Torvalds {
101f5afe806SEric Sesterhenn 	return kzalloc(sizeof(struct ebda_rsrc_list), GFP_KERNEL);
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds 
alloc_ebda_pci_rsrc(void)1041da177e4SLinus Torvalds static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc(void)
1051da177e4SLinus Torvalds {
106f5afe806SEric Sesterhenn 	return kzalloc(sizeof(struct ebda_pci_rsrc), GFP_KERNEL);
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds 
print_bus_info(void)1091da177e4SLinus Torvalds static void __init print_bus_info(void)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds 	struct bus_info *ptr;
1121da177e4SLinus Torvalds 
113a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
11466bef8c0SHarvey Harrison 		debug("%s - slot_min = %x\n", __func__, ptr->slot_min);
11566bef8c0SHarvey Harrison 		debug("%s - slot_max = %x\n", __func__, ptr->slot_max);
11666bef8c0SHarvey Harrison 		debug("%s - slot_count = %x\n", __func__, ptr->slot_count);
11766bef8c0SHarvey Harrison 		debug("%s - bus# = %x\n", __func__, ptr->busno);
11866bef8c0SHarvey Harrison 		debug("%s - current_speed = %x\n", __func__, ptr->current_speed);
11966bef8c0SHarvey Harrison 		debug("%s - controller_id = %x\n", __func__, ptr->controller_id);
1201da177e4SLinus Torvalds 
12166bef8c0SHarvey Harrison 		debug("%s - slots_at_33_conv = %x\n", __func__, ptr->slots_at_33_conv);
12266bef8c0SHarvey Harrison 		debug("%s - slots_at_66_conv = %x\n", __func__, ptr->slots_at_66_conv);
12366bef8c0SHarvey Harrison 		debug("%s - slots_at_66_pcix = %x\n", __func__, ptr->slots_at_66_pcix);
12466bef8c0SHarvey Harrison 		debug("%s - slots_at_100_pcix = %x\n", __func__, ptr->slots_at_100_pcix);
12566bef8c0SHarvey Harrison 		debug("%s - slots_at_133_pcix = %x\n", __func__, ptr->slots_at_133_pcix);
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	}
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds 
print_lo_info(void)1301da177e4SLinus Torvalds static void print_lo_info(void)
1311da177e4SLinus Torvalds {
1321da177e4SLinus Torvalds 	struct rio_detail *ptr;
1331da177e4SLinus Torvalds 	debug("print_lo_info ----\n");
134a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &rio_lo_head, rio_detail_list) {
13566bef8c0SHarvey Harrison 		debug("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
13666bef8c0SHarvey Harrison 		debug("%s - rio_type = %x\n", __func__, ptr->rio_type);
13766bef8c0SHarvey Harrison 		debug("%s - owner_id = %x\n", __func__, ptr->owner_id);
13866bef8c0SHarvey Harrison 		debug("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
13966bef8c0SHarvey Harrison 		debug("%s - wpindex = %x\n", __func__, ptr->wpindex);
14066bef8c0SHarvey Harrison 		debug("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 	}
1431da177e4SLinus Torvalds }
1441da177e4SLinus Torvalds 
print_vg_info(void)1451da177e4SLinus Torvalds static void print_vg_info(void)
1461da177e4SLinus Torvalds {
1471da177e4SLinus Torvalds 	struct rio_detail *ptr;
14866bef8c0SHarvey Harrison 	debug("%s ---\n", __func__);
149a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &rio_vg_head, rio_detail_list) {
15066bef8c0SHarvey Harrison 		debug("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
15166bef8c0SHarvey Harrison 		debug("%s - rio_type = %x\n", __func__, ptr->rio_type);
15266bef8c0SHarvey Harrison 		debug("%s - owner_id = %x\n", __func__, ptr->owner_id);
15366bef8c0SHarvey Harrison 		debug("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
15466bef8c0SHarvey Harrison 		debug("%s - wpindex = %x\n", __func__, ptr->wpindex);
15566bef8c0SHarvey Harrison 		debug("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	}
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
print_ebda_pci_rsrc(void)1601da177e4SLinus Torvalds static void __init print_ebda_pci_rsrc(void)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds 	struct ebda_pci_rsrc *ptr;
1631da177e4SLinus Torvalds 
164a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &ibmphp_ebda_pci_rsrc_head, ebda_pci_rsrc_list) {
1651da177e4SLinus Torvalds 		debug("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
16666bef8c0SHarvey Harrison 			__func__, ptr->rsrc_type, ptr->bus_num, ptr->dev_fun, ptr->start_addr, ptr->end_addr);
1671da177e4SLinus Torvalds 	}
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
print_ibm_slot(void)1701da177e4SLinus Torvalds static void __init print_ibm_slot(void)
1711da177e4SLinus Torvalds {
1721da177e4SLinus Torvalds 	struct slot *ptr;
1731da177e4SLinus Torvalds 
174a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &ibmphp_slot_head, ibm_slot_list) {
17566bef8c0SHarvey Harrison 		debug("%s - slot_number: %x\n", __func__, ptr->number);
1761da177e4SLinus Torvalds 	}
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
print_opt_vg(void)1791da177e4SLinus Torvalds static void __init print_opt_vg(void)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 	struct opt_rio *ptr;
18266bef8c0SHarvey Harrison 	debug("%s ---\n", __func__);
183a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
18466bef8c0SHarvey Harrison 		debug("%s - rio_type %x\n", __func__, ptr->rio_type);
18566bef8c0SHarvey Harrison 		debug("%s - chassis_num: %x\n", __func__, ptr->chassis_num);
18666bef8c0SHarvey Harrison 		debug("%s - first_slot_num: %x\n", __func__, ptr->first_slot_num);
18766bef8c0SHarvey Harrison 		debug("%s - middle_num: %x\n", __func__, ptr->middle_num);
1881da177e4SLinus Torvalds 	}
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds 
print_ebda_hpc(void)1911da177e4SLinus Torvalds static void __init print_ebda_hpc(void)
1921da177e4SLinus Torvalds {
1931da177e4SLinus Torvalds 	struct controller *hpc_ptr;
1941da177e4SLinus Torvalds 	u16 index;
1951da177e4SLinus Torvalds 
196a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(hpc_ptr, &ebda_hpc_head, ebda_hpc_list) {
1971da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->slot_count; index++) {
19866bef8c0SHarvey Harrison 			debug("%s - physical slot#: %x\n", __func__, hpc_ptr->slots[index].slot_num);
19966bef8c0SHarvey Harrison 			debug("%s - pci bus# of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_bus_num);
20066bef8c0SHarvey Harrison 			debug("%s - index into ctlr addr: %x\n", __func__, hpc_ptr->slots[index].ctl_index);
20166bef8c0SHarvey Harrison 			debug("%s - cap of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_cap);
2021da177e4SLinus Torvalds 		}
2031da177e4SLinus Torvalds 
204656f978fSQuentin Lambert 		for (index = 0; index < hpc_ptr->bus_count; index++)
20566bef8c0SHarvey Harrison 			debug("%s - bus# of each bus controlled by this ctlr: %x\n", __func__, hpc_ptr->buses[index].bus_num);
2061da177e4SLinus Torvalds 
20766bef8c0SHarvey Harrison 		debug("%s - type of hpc: %x\n", __func__, hpc_ptr->ctlr_type);
2081da177e4SLinus Torvalds 		switch (hpc_ptr->ctlr_type) {
2091da177e4SLinus Torvalds 		case 1:
21066bef8c0SHarvey Harrison 			debug("%s - bus: %x\n", __func__, hpc_ptr->u.pci_ctlr.bus);
21166bef8c0SHarvey Harrison 			debug("%s - dev_fun: %x\n", __func__, hpc_ptr->u.pci_ctlr.dev_fun);
21266bef8c0SHarvey Harrison 			debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
2131da177e4SLinus Torvalds 			break;
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 		case 0:
21666bef8c0SHarvey Harrison 			debug("%s - io_start: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_start);
21766bef8c0SHarvey Harrison 			debug("%s - io_end: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_end);
21866bef8c0SHarvey Harrison 			debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
2191da177e4SLinus Torvalds 			break;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 		case 2:
2221da177e4SLinus Torvalds 		case 4:
22366bef8c0SHarvey Harrison 			debug("%s - wpegbbar: %lx\n", __func__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
22466bef8c0SHarvey Harrison 			debug("%s - i2c_addr: %x\n", __func__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
22566bef8c0SHarvey Harrison 			debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
2261da177e4SLinus Torvalds 			break;
2271da177e4SLinus Torvalds 		}
2281da177e4SLinus Torvalds 	}
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
ibmphp_access_ebda(void)2311da177e4SLinus Torvalds int __init ibmphp_access_ebda(void)
2321da177e4SLinus Torvalds {
233b0fc889cSChandru 	u8 format, num_ctlrs, rio_complete, hs_complete, ebda_sz;
2341da177e4SLinus Torvalds 	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
2351da177e4SLinus Torvalds 	int rc = 0;
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 	rio_complete = 0;
2391da177e4SLinus Torvalds 	hs_complete = 0;
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds 	io_mem = ioremap((0x40 << 4) + 0x0e, 2);
2421da177e4SLinus Torvalds 	if (!io_mem)
2431da177e4SLinus Torvalds 		return -ENOMEM;
2441da177e4SLinus Torvalds 	ebda_seg = readw(io_mem);
2451da177e4SLinus Torvalds 	iounmap(io_mem);
2461da177e4SLinus Torvalds 	debug("returned ebda segment: %x\n", ebda_seg);
2471da177e4SLinus Torvalds 
248b0fc889cSChandru 	io_mem = ioremap(ebda_seg<<4, 1);
249ba02b242SAndrew Morton 	if (!io_mem)
250ba02b242SAndrew Morton 		return -ENOMEM;
251b0fc889cSChandru 	ebda_sz = readb(io_mem);
252b0fc889cSChandru 	iounmap(io_mem);
253b0fc889cSChandru 	debug("ebda size: %d(KiB)\n", ebda_sz);
254b0fc889cSChandru 	if (ebda_sz == 0)
255b0fc889cSChandru 		return -ENOMEM;
256b0fc889cSChandru 
257b0fc889cSChandru 	io_mem = ioremap(ebda_seg<<4, (ebda_sz * 1024));
2581da177e4SLinus Torvalds 	if (!io_mem)
2591da177e4SLinus Torvalds 		return -ENOMEM;
2601da177e4SLinus Torvalds 	next_offset = 0x180;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	for (;;) {
2631da177e4SLinus Torvalds 		offset = next_offset;
264ac3abf2cSSteven Rostedt 
265ac3abf2cSSteven Rostedt 		/* Make sure what we read is still in the mapped section */
266ac3abf2cSSteven Rostedt 		if (WARN(offset > (ebda_sz * 1024 - 4),
267ac3abf2cSSteven Rostedt 			 "ibmphp_ebda: next read is beyond ebda_sz\n"))
268ac3abf2cSSteven Rostedt 			break;
269ac3abf2cSSteven Rostedt 
2701da177e4SLinus Torvalds 		next_offset = readw(io_mem + offset);	/* offset of next blk */
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 		offset += 2;
2731da177e4SLinus Torvalds 		if (next_offset == 0)	/* 0 indicate it's last blk */
2741da177e4SLinus Torvalds 			break;
2751da177e4SLinus Torvalds 		blk_id = readw(io_mem + offset);	/* this blk id */
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 		offset += 2;
2781da177e4SLinus Torvalds 		/* check if it is hot swap block or rio block */
2791da177e4SLinus Torvalds 		if (blk_id != 0x4853 && blk_id != 0x4752)
2801da177e4SLinus Torvalds 			continue;
2811da177e4SLinus Torvalds 		/* found hs table */
2821da177e4SLinus Torvalds 		if (blk_id == 0x4853) {
2831da177e4SLinus Torvalds 			debug("now enter hot swap block---\n");
2841da177e4SLinus Torvalds 			debug("hot blk id: %x\n", blk_id);
2851da177e4SLinus Torvalds 			format = readb(io_mem + offset);
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 			offset += 1;
2881da177e4SLinus Torvalds 			if (format != 4)
2891da177e4SLinus Torvalds 				goto error_nodev;
2901da177e4SLinus Torvalds 			debug("hot blk format: %x\n", format);
2911da177e4SLinus Torvalds 			/* hot swap sub blk */
2921da177e4SLinus Torvalds 			base = offset;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 			sub_addr = base;
2951da177e4SLinus Torvalds 			re = readw(io_mem + sub_addr);	/* next sub blk */
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 			sub_addr += 2;
2981da177e4SLinus Torvalds 			rc_id = readw(io_mem + sub_addr);	/* sub blk id */
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 			sub_addr += 2;
3011da177e4SLinus Torvalds 			if (rc_id != 0x5243)
3021da177e4SLinus Torvalds 				goto error_nodev;
3031da177e4SLinus Torvalds 			/* rc sub blk signature  */
3041da177e4SLinus Torvalds 			num_ctlrs = readb(io_mem + sub_addr);
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 			sub_addr += 1;
3071da177e4SLinus Torvalds 			hpc_list_ptr = alloc_ebda_hpc_list();
3081da177e4SLinus Torvalds 			if (!hpc_list_ptr) {
3091da177e4SLinus Torvalds 				rc = -ENOMEM;
3101da177e4SLinus Torvalds 				goto out;
3111da177e4SLinus Torvalds 			}
3121da177e4SLinus Torvalds 			hpc_list_ptr->format = format;
3131da177e4SLinus Torvalds 			hpc_list_ptr->num_ctlrs = num_ctlrs;
3141da177e4SLinus Torvalds 			hpc_list_ptr->phys_addr = sub_addr;	/*  offset of RSRC_CONTROLLER blk */
3151da177e4SLinus Torvalds 			debug("info about hpc descriptor---\n");
3161da177e4SLinus Torvalds 			debug("hot blk format: %x\n", format);
3171da177e4SLinus Torvalds 			debug("num of controller: %x\n", num_ctlrs);
318f7625980SBjorn Helgaas 			debug("offset of hpc data structure entries: %x\n ", sub_addr);
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 			sub_addr = base + re;	/* re sub blk */
3211da177e4SLinus Torvalds 			/* FIXME: rc is never used/checked */
3221da177e4SLinus Torvalds 			rc = readw(io_mem + sub_addr);	/* next sub blk */
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 			sub_addr += 2;
3251da177e4SLinus Torvalds 			re_id = readw(io_mem + sub_addr);	/* sub blk id */
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 			sub_addr += 2;
3281da177e4SLinus Torvalds 			if (re_id != 0x5245)
3291da177e4SLinus Torvalds 				goto error_nodev;
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 			/* signature of re */
3321da177e4SLinus Torvalds 			num_entries = readw(io_mem + sub_addr);
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 			sub_addr += 2;	/* offset of RSRC_ENTRIES blk */
3351da177e4SLinus Torvalds 			rsrc_list_ptr = alloc_ebda_rsrc_list();
3361da177e4SLinus Torvalds 			if (!rsrc_list_ptr) {
3371da177e4SLinus Torvalds 				rc = -ENOMEM;
3381da177e4SLinus Torvalds 				goto out;
3391da177e4SLinus Torvalds 			}
3401da177e4SLinus Torvalds 			rsrc_list_ptr->format = format;
3411da177e4SLinus Torvalds 			rsrc_list_ptr->num_entries = num_entries;
3421da177e4SLinus Torvalds 			rsrc_list_ptr->phys_addr = sub_addr;
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 			debug("info about rsrc descriptor---\n");
3451da177e4SLinus Torvalds 			debug("format: %x\n", format);
3461da177e4SLinus Torvalds 			debug("num of rsrc: %x\n", num_entries);
347f7625980SBjorn Helgaas 			debug("offset of rsrc data structure entries: %x\n ", sub_addr);
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 			hs_complete = 1;
3501da177e4SLinus Torvalds 		} else {
3511da177e4SLinus Torvalds 		/* found rio table, blk_id == 0x4752 */
3521da177e4SLinus Torvalds 			debug("now enter io table ---\n");
3531da177e4SLinus Torvalds 			debug("rio blk id: %x\n", blk_id);
3541da177e4SLinus Torvalds 
355f5afe806SEric Sesterhenn 			rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL);
3568f0cdddcSJulia Lawall 			if (!rio_table_ptr) {
3578f0cdddcSJulia Lawall 				rc = -ENOMEM;
3588f0cdddcSJulia Lawall 				goto out;
3598f0cdddcSJulia Lawall 			}
3601da177e4SLinus Torvalds 			rio_table_ptr->ver_num = readb(io_mem + offset);
3611da177e4SLinus Torvalds 			rio_table_ptr->scal_count = readb(io_mem + offset + 1);
3621da177e4SLinus Torvalds 			rio_table_ptr->riodev_count = readb(io_mem + offset + 2);
3631da177e4SLinus Torvalds 			rio_table_ptr->offset = offset + 3 ;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 			debug("info about rio table hdr ---\n");
3661da177e4SLinus Torvalds 			debug("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ",
3671da177e4SLinus Torvalds 				rio_table_ptr->ver_num, rio_table_ptr->scal_count,
3681da177e4SLinus Torvalds 				rio_table_ptr->riodev_count, rio_table_ptr->offset);
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 			rio_complete = 1;
3711da177e4SLinus Torvalds 		}
3721da177e4SLinus Torvalds 	}
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	if (!hs_complete && !rio_complete)
3751da177e4SLinus Torvalds 		goto error_nodev;
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	if (rio_table_ptr) {
3781da177e4SLinus Torvalds 		if (rio_complete && rio_table_ptr->ver_num == 3) {
3791da177e4SLinus Torvalds 			rc = ebda_rio_table();
3801da177e4SLinus Torvalds 			if (rc)
3811da177e4SLinus Torvalds 				goto out;
3821da177e4SLinus Torvalds 		}
3831da177e4SLinus Torvalds 	}
3841da177e4SLinus Torvalds 	rc = ebda_rsrc_controller();
3851da177e4SLinus Torvalds 	if (rc)
3861da177e4SLinus Torvalds 		goto out;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	rc = ebda_rsrc_rsrc();
3891da177e4SLinus Torvalds 	goto out;
3901da177e4SLinus Torvalds error_nodev:
3911da177e4SLinus Torvalds 	rc = -ENODEV;
3921da177e4SLinus Torvalds out:
3931da177e4SLinus Torvalds 	iounmap(io_mem);
3941da177e4SLinus Torvalds 	return rc;
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds /*
3981da177e4SLinus Torvalds  * map info of scalability details and rio details from physical address
3991da177e4SLinus Torvalds  */
ebda_rio_table(void)4001da177e4SLinus Torvalds static int __init ebda_rio_table(void)
4011da177e4SLinus Torvalds {
4021da177e4SLinus Torvalds 	u16 offset;
4031da177e4SLinus Torvalds 	u8 i;
4041da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr;
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 	offset = rio_table_ptr->offset;
4071da177e4SLinus Torvalds 	offset += 12 * rio_table_ptr->scal_count;
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 	// we do concern about rio details
4101da177e4SLinus Torvalds 	for (i = 0; i < rio_table_ptr->riodev_count; i++) {
411f5afe806SEric Sesterhenn 		rio_detail_ptr = kzalloc(sizeof(struct rio_detail), GFP_KERNEL);
4121da177e4SLinus Torvalds 		if (!rio_detail_ptr)
4131da177e4SLinus Torvalds 			return -ENOMEM;
4141da177e4SLinus Torvalds 		rio_detail_ptr->rio_node_id = readb(io_mem + offset);
4151da177e4SLinus Torvalds 		rio_detail_ptr->bbar = readl(io_mem + offset + 1);
4161da177e4SLinus Torvalds 		rio_detail_ptr->rio_type = readb(io_mem + offset + 5);
4171da177e4SLinus Torvalds 		rio_detail_ptr->owner_id = readb(io_mem + offset + 6);
4181da177e4SLinus Torvalds 		rio_detail_ptr->port0_node_connect = readb(io_mem + offset + 7);
4191da177e4SLinus Torvalds 		rio_detail_ptr->port0_port_connect = readb(io_mem + offset + 8);
4201da177e4SLinus Torvalds 		rio_detail_ptr->port1_node_connect = readb(io_mem + offset + 9);
4211da177e4SLinus Torvalds 		rio_detail_ptr->port1_port_connect = readb(io_mem + offset + 10);
4221da177e4SLinus Torvalds 		rio_detail_ptr->first_slot_num = readb(io_mem + offset + 11);
4231da177e4SLinus Torvalds 		rio_detail_ptr->status = readb(io_mem + offset + 12);
4241da177e4SLinus Torvalds 		rio_detail_ptr->wpindex = readb(io_mem + offset + 13);
4251da177e4SLinus Torvalds 		rio_detail_ptr->chassis_num = readb(io_mem + offset + 14);
4261da177e4SLinus Torvalds //		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);
4271da177e4SLinus Torvalds 		//create linked list of chassis
4281da177e4SLinus Torvalds 		if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5)
4291da177e4SLinus Torvalds 			list_add(&rio_detail_ptr->rio_detail_list, &rio_vg_head);
4301da177e4SLinus Torvalds 		//create linked list of expansion box
4311da177e4SLinus Torvalds 		else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7)
4321da177e4SLinus Torvalds 			list_add(&rio_detail_ptr->rio_detail_list, &rio_lo_head);
4331da177e4SLinus Torvalds 		else
4341da177e4SLinus Torvalds 			// not in my concern
4351da177e4SLinus Torvalds 			kfree(rio_detail_ptr);
4361da177e4SLinus Torvalds 		offset += 15;
4371da177e4SLinus Torvalds 	}
4381da177e4SLinus Torvalds 	print_lo_info();
4391da177e4SLinus Torvalds 	print_vg_info();
4401da177e4SLinus Torvalds 	return 0;
4411da177e4SLinus Torvalds }
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds /*
4441da177e4SLinus Torvalds  * reorganizing linked list of chassis
4451da177e4SLinus Torvalds  */
search_opt_vg(u8 chassis_num)4461da177e4SLinus Torvalds static struct opt_rio *search_opt_vg(u8 chassis_num)
4471da177e4SLinus Torvalds {
4481da177e4SLinus Torvalds 	struct opt_rio *ptr;
449a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
4501da177e4SLinus Torvalds 		if (ptr->chassis_num == chassis_num)
4511da177e4SLinus Torvalds 			return ptr;
4521da177e4SLinus Torvalds 	}
4531da177e4SLinus Torvalds 	return NULL;
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds 
combine_wpg_for_chassis(void)4561da177e4SLinus Torvalds static int __init combine_wpg_for_chassis(void)
4571da177e4SLinus Torvalds {
4581da177e4SLinus Torvalds 	struct opt_rio *opt_rio_ptr = NULL;
4591da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr = NULL;
4601da177e4SLinus Torvalds 
461a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(rio_detail_ptr, &rio_vg_head, rio_detail_list) {
4621da177e4SLinus Torvalds 		opt_rio_ptr = search_opt_vg(rio_detail_ptr->chassis_num);
4631da177e4SLinus Torvalds 		if (!opt_rio_ptr) {
464f5afe806SEric Sesterhenn 			opt_rio_ptr = kzalloc(sizeof(struct opt_rio), GFP_KERNEL);
4651da177e4SLinus Torvalds 			if (!opt_rio_ptr)
4661da177e4SLinus Torvalds 				return -ENOMEM;
4671da177e4SLinus Torvalds 			opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
4681da177e4SLinus Torvalds 			opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
4691da177e4SLinus Torvalds 			opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
4701da177e4SLinus Torvalds 			opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
4711da177e4SLinus Torvalds 			list_add(&opt_rio_ptr->opt_rio_list, &opt_vg_head);
4721da177e4SLinus Torvalds 		} else {
4731da177e4SLinus Torvalds 			opt_rio_ptr->first_slot_num = min(opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
4741da177e4SLinus Torvalds 			opt_rio_ptr->middle_num = max(opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
4751da177e4SLinus Torvalds 		}
4761da177e4SLinus Torvalds 	}
4771da177e4SLinus Torvalds 	print_opt_vg();
4781da177e4SLinus Torvalds 	return 0;
4791da177e4SLinus Torvalds }
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds /*
482a8d2dbd3Sakpm@linux-foundation.org  * reorganizing linked list of expansion box
4831da177e4SLinus Torvalds  */
search_opt_lo(u8 chassis_num)4841da177e4SLinus Torvalds static struct opt_rio_lo *search_opt_lo(u8 chassis_num)
4851da177e4SLinus Torvalds {
4861da177e4SLinus Torvalds 	struct opt_rio_lo *ptr;
487a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &opt_lo_head, opt_rio_lo_list) {
4881da177e4SLinus Torvalds 		if (ptr->chassis_num == chassis_num)
4891da177e4SLinus Torvalds 			return ptr;
4901da177e4SLinus Torvalds 	}
4911da177e4SLinus Torvalds 	return NULL;
4921da177e4SLinus Torvalds }
4931da177e4SLinus Torvalds 
combine_wpg_for_expansion(void)4941da177e4SLinus Torvalds static int combine_wpg_for_expansion(void)
4951da177e4SLinus Torvalds {
4961da177e4SLinus Torvalds 	struct opt_rio_lo *opt_rio_lo_ptr = NULL;
4971da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr = NULL;
4981da177e4SLinus Torvalds 
499a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(rio_detail_ptr, &rio_lo_head, rio_detail_list) {
5001da177e4SLinus Torvalds 		opt_rio_lo_ptr = search_opt_lo(rio_detail_ptr->chassis_num);
5011da177e4SLinus Torvalds 		if (!opt_rio_lo_ptr) {
502f5afe806SEric Sesterhenn 			opt_rio_lo_ptr = kzalloc(sizeof(struct opt_rio_lo), GFP_KERNEL);
5031da177e4SLinus Torvalds 			if (!opt_rio_lo_ptr)
5041da177e4SLinus Torvalds 				return -ENOMEM;
5051da177e4SLinus Torvalds 			opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
5061da177e4SLinus Torvalds 			opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
5071da177e4SLinus Torvalds 			opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
5081da177e4SLinus Torvalds 			opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
5091da177e4SLinus Torvalds 			opt_rio_lo_ptr->pack_count = 1;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 			list_add(&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
5121da177e4SLinus Torvalds 		} else {
5131da177e4SLinus Torvalds 			opt_rio_lo_ptr->first_slot_num = min(opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
5141da177e4SLinus Torvalds 			opt_rio_lo_ptr->middle_num = max(opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
5151da177e4SLinus Torvalds 			opt_rio_lo_ptr->pack_count = 2;
5161da177e4SLinus Torvalds 		}
5171da177e4SLinus Torvalds 	}
5181da177e4SLinus Torvalds 	return 0;
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds /* Since we don't know the max slot number per each chassis, hence go
5231da177e4SLinus Torvalds  * through the list of all chassis to find out the range
5241da177e4SLinus Torvalds  * Arguments: slot_num, 1st slot number of the chassis we think we are on,
5251da177e4SLinus Torvalds  * var (0 = chassis, 1 = expansion box)
5261da177e4SLinus Torvalds  */
first_slot_num(u8 slot_num,u8 first_slot,u8 var)5271da177e4SLinus Torvalds static int first_slot_num(u8 slot_num, u8 first_slot, u8 var)
5281da177e4SLinus Torvalds {
5291da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr = NULL;
5301da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr = NULL;
5311da177e4SLinus Torvalds 	int rc = 0;
5321da177e4SLinus Torvalds 
5331da177e4SLinus Torvalds 	if (!var) {
534a8d2dbd3Sakpm@linux-foundation.org 		list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
5351da177e4SLinus Torvalds 			if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) {
5361da177e4SLinus Torvalds 				rc = -ENODEV;
5371da177e4SLinus Torvalds 				break;
5381da177e4SLinus Torvalds 			}
5391da177e4SLinus Torvalds 		}
5401da177e4SLinus Torvalds 	} else {
541a8d2dbd3Sakpm@linux-foundation.org 		list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
5421da177e4SLinus Torvalds 			if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
5431da177e4SLinus Torvalds 				rc = -ENODEV;
5441da177e4SLinus Torvalds 				break;
5451da177e4SLinus Torvalds 			}
5461da177e4SLinus Torvalds 		}
5471da177e4SLinus Torvalds 	}
5481da177e4SLinus Torvalds 	return rc;
5491da177e4SLinus Torvalds }
5501da177e4SLinus Torvalds 
find_rxe_num(u8 slot_num)5511da177e4SLinus Torvalds static struct opt_rio_lo *find_rxe_num(u8 slot_num)
5521da177e4SLinus Torvalds {
5531da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr;
5541da177e4SLinus Torvalds 
555a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
5561da177e4SLinus Torvalds 		//check to see if this slot_num belongs to expansion box
5571da177e4SLinus Torvalds 		if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num(slot_num, opt_lo_ptr->first_slot_num, 1)))
5581da177e4SLinus Torvalds 			return opt_lo_ptr;
5591da177e4SLinus Torvalds 	}
5601da177e4SLinus Torvalds 	return NULL;
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds 
find_chassis_num(u8 slot_num)5631da177e4SLinus Torvalds static struct opt_rio *find_chassis_num(u8 slot_num)
5641da177e4SLinus Torvalds {
5651da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr;
5661da177e4SLinus Torvalds 
567a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
5681da177e4SLinus Torvalds 		//check to see if this slot_num belongs to chassis
5691da177e4SLinus Torvalds 		if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num(slot_num, opt_vg_ptr->first_slot_num, 0)))
5701da177e4SLinus Torvalds 			return opt_vg_ptr;
5711da177e4SLinus Torvalds 	}
5721da177e4SLinus Torvalds 	return NULL;
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds /* This routine will find out how many slots are in the chassis, so that
5761da177e4SLinus Torvalds  * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
5771da177e4SLinus Torvalds  */
calculate_first_slot(u8 slot_num)5781da177e4SLinus Torvalds static u8 calculate_first_slot(u8 slot_num)
5791da177e4SLinus Torvalds {
5801da177e4SLinus Torvalds 	u8 first_slot = 1;
5811da177e4SLinus Torvalds 	struct slot *slot_cur;
5821da177e4SLinus Torvalds 
583a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) {
5841da177e4SLinus Torvalds 		if (slot_cur->ctrl) {
5851da177e4SLinus Torvalds 			if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num))
5861da177e4SLinus Torvalds 				first_slot = slot_cur->ctrl->ending_slot_num;
5871da177e4SLinus Torvalds 		}
5881da177e4SLinus Torvalds 	}
5891da177e4SLinus Torvalds 	return first_slot + 1;
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds }
592a32615a1SAlex Chiang 
593a32615a1SAlex Chiang #define SLOT_NAME_SIZE 30
594a32615a1SAlex Chiang 
create_file_name(struct slot * slot_cur)5951da177e4SLinus Torvalds static char *create_file_name(struct slot *slot_cur)
5961da177e4SLinus Torvalds {
5971da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr = NULL;
5981da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr = NULL;
599a32615a1SAlex Chiang 	static char str[SLOT_NAME_SIZE];
6001da177e4SLinus Torvalds 	int which = 0; /* rxe = 1, chassis = 0 */
6011da177e4SLinus Torvalds 	u8 number = 1; /* either chassis or rxe # */
6021da177e4SLinus Torvalds 	u8 first_slot = 1;
6031da177e4SLinus Torvalds 	u8 slot_num;
6041da177e4SLinus Torvalds 	u8 flag = 0;
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds 	if (!slot_cur) {
6071da177e4SLinus Torvalds 		err("Structure passed is empty\n");
6081da177e4SLinus Torvalds 		return NULL;
6091da177e4SLinus Torvalds 	}
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds 	slot_num = slot_cur->number;
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 	memset(str, 0, sizeof(str));
6141da177e4SLinus Torvalds 
6151da177e4SLinus Torvalds 	if (rio_table_ptr) {
6161da177e4SLinus Torvalds 		if (rio_table_ptr->ver_num == 3) {
6171da177e4SLinus Torvalds 			opt_vg_ptr = find_chassis_num(slot_num);
6181da177e4SLinus Torvalds 			opt_lo_ptr = find_rxe_num(slot_num);
6191da177e4SLinus Torvalds 		}
6201da177e4SLinus Torvalds 	}
6211da177e4SLinus Torvalds 	if (opt_vg_ptr) {
6221da177e4SLinus Torvalds 		if (opt_lo_ptr) {
6231da177e4SLinus Torvalds 			if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
6241da177e4SLinus Torvalds 				number = opt_lo_ptr->chassis_num;
6251da177e4SLinus Torvalds 				first_slot = opt_lo_ptr->first_slot_num;
6261da177e4SLinus Torvalds 				which = 1; /* it is RXE */
6271da177e4SLinus Torvalds 			} else {
6281da177e4SLinus Torvalds 				first_slot = opt_vg_ptr->first_slot_num;
6291da177e4SLinus Torvalds 				number = opt_vg_ptr->chassis_num;
6301da177e4SLinus Torvalds 				which = 0;
6311da177e4SLinus Torvalds 			}
6321da177e4SLinus Torvalds 		} else {
6331da177e4SLinus Torvalds 			first_slot = opt_vg_ptr->first_slot_num;
6341da177e4SLinus Torvalds 			number = opt_vg_ptr->chassis_num;
6351da177e4SLinus Torvalds 			which = 0;
6361da177e4SLinus Torvalds 		}
6371da177e4SLinus Torvalds 		++flag;
6381da177e4SLinus Torvalds 	} else if (opt_lo_ptr) {
6391da177e4SLinus Torvalds 		number = opt_lo_ptr->chassis_num;
6401da177e4SLinus Torvalds 		first_slot = opt_lo_ptr->first_slot_num;
6411da177e4SLinus Torvalds 		which = 1;
6421da177e4SLinus Torvalds 		++flag;
6431da177e4SLinus Torvalds 	} else if (rio_table_ptr) {
6441da177e4SLinus Torvalds 		if (rio_table_ptr->ver_num == 3) {
6451da177e4SLinus Torvalds 			/* if both NULL and we DO have correct RIO table in BIOS */
6461da177e4SLinus Torvalds 			return NULL;
6471da177e4SLinus Torvalds 		}
6481da177e4SLinus Torvalds 	}
6491da177e4SLinus Torvalds 	if (!flag) {
6501da177e4SLinus Torvalds 		if (slot_cur->ctrl->ctlr_type == 4) {
6511da177e4SLinus Torvalds 			first_slot = calculate_first_slot(slot_num);
6521da177e4SLinus Torvalds 			which = 1;
6531da177e4SLinus Torvalds 		} else {
6541da177e4SLinus Torvalds 			which = 0;
6551da177e4SLinus Torvalds 		}
6561da177e4SLinus Torvalds 	}
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds 	sprintf(str, "%s%dslot%d",
6591da177e4SLinus Torvalds 		which == 0 ? "chassis" : "rxe",
6601da177e4SLinus Torvalds 		number, slot_num - first_slot + 1);
6611da177e4SLinus Torvalds 	return str;
6621da177e4SLinus Torvalds }
6631da177e4SLinus Torvalds 
fillslotinfo(struct hotplug_slot * hotplug_slot)6641da177e4SLinus Torvalds static int fillslotinfo(struct hotplug_slot *hotplug_slot)
6651da177e4SLinus Torvalds {
6661da177e4SLinus Torvalds 	struct slot *slot;
6671da177e4SLinus Torvalds 	int rc = 0;
6681da177e4SLinus Torvalds 
669125450f8SLukas Wunner 	slot = to_slot(hotplug_slot);
6701da177e4SLinus Torvalds 	rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL);
6711da177e4SLinus Torvalds 	return rc;
6721da177e4SLinus Torvalds }
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds static struct pci_driver ibmphp_driver;
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds /*
6771da177e4SLinus Torvalds  * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
6781da177e4SLinus Torvalds  * each hpc from physical address to a list of hot plug controllers based on
6791da177e4SLinus Torvalds  * hpc descriptors.
6801da177e4SLinus Torvalds  */
ebda_rsrc_controller(void)6811da177e4SLinus Torvalds static int __init ebda_rsrc_controller(void)
6821da177e4SLinus Torvalds {
6831da177e4SLinus Torvalds 	u16 addr, addr_slot, addr_bus;
6841da177e4SLinus Torvalds 	u8 ctlr_id, temp, bus_index;
6851da177e4SLinus Torvalds 	u16 ctlr, slot, bus;
6861da177e4SLinus Torvalds 	u16 slot_num, bus_num, index;
6871da177e4SLinus Torvalds 	struct controller *hpc_ptr;
6881da177e4SLinus Torvalds 	struct ebda_hpc_bus *bus_ptr;
6891da177e4SLinus Torvalds 	struct ebda_hpc_slot *slot_ptr;
6901da177e4SLinus Torvalds 	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
6911da177e4SLinus Torvalds 	int rc;
6921da177e4SLinus Torvalds 	struct slot *tmp_slot;
693a32615a1SAlex Chiang 	char name[SLOT_NAME_SIZE];
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	addr = hpc_list_ptr->phys_addr;
6961da177e4SLinus Torvalds 	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
6971da177e4SLinus Torvalds 		bus_index = 1;
6981da177e4SLinus Torvalds 		ctlr_id = readb(io_mem + addr);
6991da177e4SLinus Torvalds 		addr += 1;
7001da177e4SLinus Torvalds 		slot_num = readb(io_mem + addr);
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds 		addr += 1;
7031da177e4SLinus Torvalds 		addr_slot = addr;	/* offset of slot structure */
7041da177e4SLinus Torvalds 		addr += (slot_num * 4);
7051da177e4SLinus Torvalds 
7061da177e4SLinus Torvalds 		bus_num = readb(io_mem + addr);
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 		addr += 1;
7091da177e4SLinus Torvalds 		addr_bus = addr;	/* offset of bus */
7101da177e4SLinus Torvalds 		addr += (bus_num * 9);	/* offset of ctlr_type */
7111da177e4SLinus Torvalds 		temp = readb(io_mem + addr);
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 		addr += 1;
7141da177e4SLinus Torvalds 		/* init hpc structure */
7151da177e4SLinus Torvalds 		hpc_ptr = alloc_ebda_hpc(slot_num, bus_num);
7161da177e4SLinus Torvalds 		if (!hpc_ptr) {
717*faa2e05aSVishal Aslot 			return -ENOMEM;
7181da177e4SLinus Torvalds 		}
7191da177e4SLinus Torvalds 		hpc_ptr->ctlr_id = ctlr_id;
7201da177e4SLinus Torvalds 		hpc_ptr->ctlr_relative_id = ctlr;
7211da177e4SLinus Torvalds 		hpc_ptr->slot_count = slot_num;
7221da177e4SLinus Torvalds 		hpc_ptr->bus_count = bus_num;
723367fa982SMasanari Iida 		debug("now enter ctlr data structure ---\n");
7241da177e4SLinus Torvalds 		debug("ctlr id: %x\n", ctlr_id);
7251da177e4SLinus Torvalds 		debug("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id);
7261da177e4SLinus Torvalds 		debug("count of slots controlled by this ctlr: %x\n", slot_num);
7271da177e4SLinus Torvalds 		debug("count of buses controlled by this ctlr: %x\n", bus_num);
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds 		/* init slot structure, fetch slot, bus, cap... */
7301da177e4SLinus Torvalds 		slot_ptr = hpc_ptr->slots;
7311da177e4SLinus Torvalds 		for (slot = 0; slot < slot_num; slot++) {
7321da177e4SLinus Torvalds 			slot_ptr->slot_num = readb(io_mem + addr_slot);
7331da177e4SLinus Torvalds 			slot_ptr->slot_bus_num = readb(io_mem + addr_slot + slot_num);
7341da177e4SLinus Torvalds 			slot_ptr->ctl_index = readb(io_mem + addr_slot + 2*slot_num);
7351da177e4SLinus Torvalds 			slot_ptr->slot_cap = readb(io_mem + addr_slot + 3*slot_num);
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds 			// create bus_info lined list --- if only one slot per bus: slot_min = slot_max
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 			bus_info_ptr2 = ibmphp_find_same_bus_num(slot_ptr->slot_bus_num);
7401da177e4SLinus Torvalds 			if (!bus_info_ptr2) {
741f5afe806SEric Sesterhenn 				bus_info_ptr1 = kzalloc(sizeof(struct bus_info), GFP_KERNEL);
7421da177e4SLinus Torvalds 				if (!bus_info_ptr1) {
7431da177e4SLinus Torvalds 					rc = -ENOMEM;
744125450f8SLukas Wunner 					goto error_no_slot;
7451da177e4SLinus Torvalds 				}
7461da177e4SLinus Torvalds 				bus_info_ptr1->slot_min = slot_ptr->slot_num;
7471da177e4SLinus Torvalds 				bus_info_ptr1->slot_max = slot_ptr->slot_num;
7481da177e4SLinus Torvalds 				bus_info_ptr1->slot_count += 1;
7491da177e4SLinus Torvalds 				bus_info_ptr1->busno = slot_ptr->slot_bus_num;
7501da177e4SLinus Torvalds 				bus_info_ptr1->index = bus_index++;
7511da177e4SLinus Torvalds 				bus_info_ptr1->current_speed = 0xff;
7521da177e4SLinus Torvalds 				bus_info_ptr1->current_bus_mode = 0xff;
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds 				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 				list_add_tail(&bus_info_ptr1->bus_info_list, &bus_info_head);
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 			} else {
7591da177e4SLinus Torvalds 				bus_info_ptr2->slot_min = min(bus_info_ptr2->slot_min, slot_ptr->slot_num);
7601da177e4SLinus Torvalds 				bus_info_ptr2->slot_max = max(bus_info_ptr2->slot_max, slot_ptr->slot_num);
7611da177e4SLinus Torvalds 				bus_info_ptr2->slot_count += 1;
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds 			}
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds 			// end of creating the bus_info linked list
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 			slot_ptr++;
7681da177e4SLinus Torvalds 			addr_slot += 1;
7691da177e4SLinus Torvalds 		}
7701da177e4SLinus Torvalds 
7711da177e4SLinus Torvalds 		/* init bus structure */
7721da177e4SLinus Torvalds 		bus_ptr = hpc_ptr->buses;
7731da177e4SLinus Torvalds 		for (bus = 0; bus < bus_num; bus++) {
7741da177e4SLinus Torvalds 			bus_ptr->bus_num = readb(io_mem + addr_bus + bus);
7751da177e4SLinus Torvalds 			bus_ptr->slots_at_33_conv = readb(io_mem + addr_bus + bus_num + 8 * bus);
7761da177e4SLinus Torvalds 			bus_ptr->slots_at_66_conv = readb(io_mem + addr_bus + bus_num + 8 * bus + 1);
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 			bus_ptr->slots_at_66_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 2);
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 			bus_ptr->slots_at_100_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 3);
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 			bus_ptr->slots_at_133_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 4);
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds 			bus_info_ptr2 = ibmphp_find_same_bus_num(bus_ptr->bus_num);
7851da177e4SLinus Torvalds 			if (bus_info_ptr2) {
7861da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
7871da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
7881da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
7891da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
7901da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix;
7911da177e4SLinus Torvalds 			}
7921da177e4SLinus Torvalds 			bus_ptr++;
7931da177e4SLinus Torvalds 		}
7941da177e4SLinus Torvalds 
7951da177e4SLinus Torvalds 		hpc_ptr->ctlr_type = temp;
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds 		switch (hpc_ptr->ctlr_type) {
7981da177e4SLinus Torvalds 			case 1:
7991da177e4SLinus Torvalds 				hpc_ptr->u.pci_ctlr.bus = readb(io_mem + addr);
8001da177e4SLinus Torvalds 				hpc_ptr->u.pci_ctlr.dev_fun = readb(io_mem + addr + 1);
8011da177e4SLinus Torvalds 				hpc_ptr->irq = readb(io_mem + addr + 2);
8021da177e4SLinus Torvalds 				addr += 3;
8031da177e4SLinus Torvalds 				debug("ctrl bus = %x, ctlr devfun = %x, irq = %x\n",
8041da177e4SLinus Torvalds 					hpc_ptr->u.pci_ctlr.bus,
8051da177e4SLinus Torvalds 					hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
8061da177e4SLinus Torvalds 				break;
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 			case 0:
8091da177e4SLinus Torvalds 				hpc_ptr->u.isa_ctlr.io_start = readw(io_mem + addr);
8101da177e4SLinus Torvalds 				hpc_ptr->u.isa_ctlr.io_end = readw(io_mem + addr + 2);
8111da177e4SLinus Torvalds 				if (!request_region(hpc_ptr->u.isa_ctlr.io_start,
8121da177e4SLinus Torvalds 						     (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
8131da177e4SLinus Torvalds 						     "ibmphp")) {
8141da177e4SLinus Torvalds 					rc = -ENODEV;
815125450f8SLukas Wunner 					goto error_no_slot;
8161da177e4SLinus Torvalds 				}
8171da177e4SLinus Torvalds 				hpc_ptr->irq = readb(io_mem + addr + 4);
8181da177e4SLinus Torvalds 				addr += 5;
8191da177e4SLinus Torvalds 				break;
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 			case 2:
8221da177e4SLinus Torvalds 			case 4:
8231da177e4SLinus Torvalds 				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl(io_mem + addr);
8241da177e4SLinus Torvalds 				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb(io_mem + addr + 4);
8251da177e4SLinus Torvalds 				hpc_ptr->irq = readb(io_mem + addr + 5);
8261da177e4SLinus Torvalds 				addr += 6;
8271da177e4SLinus Torvalds 				break;
8281da177e4SLinus Torvalds 			default:
8291da177e4SLinus Torvalds 				rc = -ENODEV;
830125450f8SLukas Wunner 				goto error_no_slot;
8311da177e4SLinus Torvalds 		}
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 		//reorganize chassis' linked list
8341da177e4SLinus Torvalds 		combine_wpg_for_chassis();
8351da177e4SLinus Torvalds 		combine_wpg_for_expansion();
8361da177e4SLinus Torvalds 		hpc_ptr->revision = 0xff;
8371da177e4SLinus Torvalds 		hpc_ptr->options = 0xff;
8381da177e4SLinus Torvalds 		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
8391da177e4SLinus Torvalds 		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds 		// register slots with hpc core as well as create linked list of ibm slot
8421da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->slot_count; index++) {
843f5afe806SEric Sesterhenn 			tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL);
8441da177e4SLinus Torvalds 			if (!tmp_slot) {
8451da177e4SLinus Torvalds 				rc = -ENOMEM;
8461da177e4SLinus Torvalds 				goto error_no_slot;
8471da177e4SLinus Torvalds 			}
8481da177e4SLinus Torvalds 
849dc6712d1SKristen Accardi 			tmp_slot->flag = 1;
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 			tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
8521da177e4SLinus Torvalds 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
8531da177e4SLinus Torvalds 				tmp_slot->supported_speed =  3;
8541da177e4SLinus Torvalds 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
8551da177e4SLinus Torvalds 				tmp_slot->supported_speed =  2;
8561da177e4SLinus Torvalds 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
8571da177e4SLinus Torvalds 				tmp_slot->supported_speed =  1;
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
8601da177e4SLinus Torvalds 				tmp_slot->supported_bus_mode = 1;
8611da177e4SLinus Torvalds 			else
8621da177e4SLinus Torvalds 				tmp_slot->supported_bus_mode = 0;
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds 			tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
8661da177e4SLinus Torvalds 
8671da177e4SLinus Torvalds 			bus_info_ptr1 = ibmphp_find_same_bus_num(hpc_ptr->slots[index].slot_bus_num);
8681da177e4SLinus Torvalds 			if (!bus_info_ptr1) {
8691da177e4SLinus Torvalds 				rc = -ENODEV;
8701da177e4SLinus Torvalds 				goto error;
8711da177e4SLinus Torvalds 			}
8721da177e4SLinus Torvalds 			tmp_slot->bus_on = bus_info_ptr1;
8731da177e4SLinus Torvalds 			bus_info_ptr1 = NULL;
8741da177e4SLinus Torvalds 			tmp_slot->ctrl = hpc_ptr;
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds 			tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
8771da177e4SLinus Torvalds 			tmp_slot->number = hpc_ptr->slots[index].slot_num;
8781da177e4SLinus Torvalds 
879125450f8SLukas Wunner 			rc = fillslotinfo(&tmp_slot->hotplug_slot);
8801da177e4SLinus Torvalds 			if (rc)
8811da177e4SLinus Torvalds 				goto error;
8821da177e4SLinus Torvalds 
883125450f8SLukas Wunner 			rc = ibmphp_init_devno(&tmp_slot);
8841da177e4SLinus Torvalds 			if (rc)
8851da177e4SLinus Torvalds 				goto error;
886125450f8SLukas Wunner 			tmp_slot->hotplug_slot.ops = &ibmphp_hotplug_slot_ops;
8871da177e4SLinus Torvalds 
8881da177e4SLinus Torvalds 			// end of registering ibm slot with hotplug core
8891da177e4SLinus Torvalds 
890125450f8SLukas Wunner 			list_add(&tmp_slot->ibm_slot_list, &ibmphp_slot_head);
8911da177e4SLinus Torvalds 		}
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds 		print_bus_info();
8941da177e4SLinus Torvalds 		list_add(&hpc_ptr->ebda_hpc_list, &ebda_hpc_head);
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	}			/* each hpc  */
8971da177e4SLinus Torvalds 
898a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) {
899a32615a1SAlex Chiang 		snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot));
900125450f8SLukas Wunner 		pci_hp_register(&tmp_slot->hotplug_slot,
901a32615a1SAlex Chiang 			pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name);
9021da177e4SLinus Torvalds 	}
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds 	print_ebda_hpc();
9051da177e4SLinus Torvalds 	print_ibm_slot();
9061da177e4SLinus Torvalds 	return 0;
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds error:
909125450f8SLukas Wunner 	kfree(tmp_slot);
9101da177e4SLinus Torvalds error_no_slot:
9111da177e4SLinus Torvalds 	free_ebda_hpc(hpc_ptr);
9121da177e4SLinus Torvalds 	return rc;
9131da177e4SLinus Torvalds }
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds /*
9161da177e4SLinus Torvalds  * map info (bus, devfun, start addr, end addr..) of i/o, memory,
9171da177e4SLinus Torvalds  * pfm from the physical addr to a list of resource.
9181da177e4SLinus Torvalds  */
ebda_rsrc_rsrc(void)9191da177e4SLinus Torvalds static int __init ebda_rsrc_rsrc(void)
9201da177e4SLinus Torvalds {
9211da177e4SLinus Torvalds 	u16 addr;
9221da177e4SLinus Torvalds 	short rsrc;
9231da177e4SLinus Torvalds 	u8 type, rsrc_type;
9241da177e4SLinus Torvalds 	struct ebda_pci_rsrc *rsrc_ptr;
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 	addr = rsrc_list_ptr->phys_addr;
9271da177e4SLinus Torvalds 	debug("now entering rsrc land\n");
9281da177e4SLinus Torvalds 	debug("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr);
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) {
9311da177e4SLinus Torvalds 		type = readb(io_mem + addr);
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 		addr += 1;
9341da177e4SLinus Torvalds 		rsrc_type = type & EBDA_RSRC_TYPE_MASK;
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 		if (rsrc_type == EBDA_IO_RSRC_TYPE) {
9371da177e4SLinus Torvalds 			rsrc_ptr = alloc_ebda_pci_rsrc();
9381da177e4SLinus Torvalds 			if (!rsrc_ptr) {
9391da177e4SLinus Torvalds 				iounmap(io_mem);
9401da177e4SLinus Torvalds 				return -ENOMEM;
9411da177e4SLinus Torvalds 			}
9421da177e4SLinus Torvalds 			rsrc_ptr->rsrc_type = type;
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 			rsrc_ptr->bus_num = readb(io_mem + addr);
9451da177e4SLinus Torvalds 			rsrc_ptr->dev_fun = readb(io_mem + addr + 1);
9461da177e4SLinus Torvalds 			rsrc_ptr->start_addr = readw(io_mem + addr + 2);
9471da177e4SLinus Torvalds 			rsrc_ptr->end_addr = readw(io_mem + addr + 4);
9481da177e4SLinus Torvalds 			addr += 6;
9491da177e4SLinus Torvalds 
9501da177e4SLinus Torvalds 			debug("rsrc from io type ----\n");
9511da177e4SLinus Torvalds 			debug("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
9521da177e4SLinus Torvalds 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds 			list_add(&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
9551da177e4SLinus Torvalds 		}
9561da177e4SLinus Torvalds 
9571da177e4SLinus Torvalds 		if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) {
9581da177e4SLinus Torvalds 			rsrc_ptr = alloc_ebda_pci_rsrc();
9591da177e4SLinus Torvalds 			if (!rsrc_ptr) {
9601da177e4SLinus Torvalds 				iounmap(io_mem);
9611da177e4SLinus Torvalds 				return -ENOMEM;
9621da177e4SLinus Torvalds 			}
9631da177e4SLinus Torvalds 			rsrc_ptr->rsrc_type = type;
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 			rsrc_ptr->bus_num = readb(io_mem + addr);
9661da177e4SLinus Torvalds 			rsrc_ptr->dev_fun = readb(io_mem + addr + 1);
9671da177e4SLinus Torvalds 			rsrc_ptr->start_addr = readl(io_mem + addr + 2);
9681da177e4SLinus Torvalds 			rsrc_ptr->end_addr = readl(io_mem + addr + 6);
9691da177e4SLinus Torvalds 			addr += 10;
9701da177e4SLinus Torvalds 
9711da177e4SLinus Torvalds 			debug("rsrc from mem or pfm ---\n");
9721da177e4SLinus Torvalds 			debug("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
9731da177e4SLinus Torvalds 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 			list_add(&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
9761da177e4SLinus Torvalds 		}
9771da177e4SLinus Torvalds 	}
9781da177e4SLinus Torvalds 	kfree(rsrc_list_ptr);
9791da177e4SLinus Torvalds 	rsrc_list_ptr = NULL;
9801da177e4SLinus Torvalds 	print_ebda_pci_rsrc();
9811da177e4SLinus Torvalds 	return 0;
9821da177e4SLinus Torvalds }
9831da177e4SLinus Torvalds 
ibmphp_get_total_controllers(void)9841da177e4SLinus Torvalds u16 ibmphp_get_total_controllers(void)
9851da177e4SLinus Torvalds {
9861da177e4SLinus Torvalds 	return hpc_list_ptr->num_ctlrs;
9871da177e4SLinus Torvalds }
9881da177e4SLinus Torvalds 
ibmphp_get_slot_from_physical_num(u8 physical_num)9891da177e4SLinus Torvalds struct slot *ibmphp_get_slot_from_physical_num(u8 physical_num)
9901da177e4SLinus Torvalds {
9911da177e4SLinus Torvalds 	struct slot *slot;
9921da177e4SLinus Torvalds 
993a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(slot, &ibmphp_slot_head, ibm_slot_list) {
9941da177e4SLinus Torvalds 		if (slot->number == physical_num)
9951da177e4SLinus Torvalds 			return slot;
9961da177e4SLinus Torvalds 	}
9971da177e4SLinus Torvalds 	return NULL;
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds /* To find:
10011da177e4SLinus Torvalds  *	- the smallest slot number
10021da177e4SLinus Torvalds  *	- the largest slot number
10031da177e4SLinus Torvalds  *	- the total number of the slots based on each bus
10041da177e4SLinus Torvalds  *	  (if only one slot per bus slot_min = slot_max )
10051da177e4SLinus Torvalds  */
ibmphp_find_same_bus_num(u32 num)10061da177e4SLinus Torvalds struct bus_info *ibmphp_find_same_bus_num(u32 num)
10071da177e4SLinus Torvalds {
10081da177e4SLinus Torvalds 	struct bus_info *ptr;
10091da177e4SLinus Torvalds 
1010a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
10111da177e4SLinus Torvalds 		if (ptr->busno == num)
10121da177e4SLinus Torvalds 			 return ptr;
10131da177e4SLinus Torvalds 	}
10141da177e4SLinus Torvalds 	return NULL;
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds 
10171da177e4SLinus Torvalds /*  Finding relative bus number, in order to map corresponding
10181da177e4SLinus Torvalds  *  bus register
10191da177e4SLinus Torvalds  */
ibmphp_get_bus_index(u8 num)10201da177e4SLinus Torvalds int ibmphp_get_bus_index(u8 num)
10211da177e4SLinus Torvalds {
10221da177e4SLinus Torvalds 	struct bus_info *ptr;
10231da177e4SLinus Torvalds 
1024a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
10251da177e4SLinus Torvalds 		if (ptr->busno == num)
10261da177e4SLinus Torvalds 			return ptr->index;
10271da177e4SLinus Torvalds 	}
10281da177e4SLinus Torvalds 	return -ENODEV;
10291da177e4SLinus Torvalds }
10301da177e4SLinus Torvalds 
ibmphp_free_bus_info_queue(void)10311da177e4SLinus Torvalds void ibmphp_free_bus_info_queue(void)
10321da177e4SLinus Torvalds {
10332ac83cccSGeliang Tang 	struct bus_info *bus_info, *next;
10341da177e4SLinus Torvalds 
10352ac83cccSGeliang Tang 	list_for_each_entry_safe(bus_info, next, &bus_info_head,
10362ac83cccSGeliang Tang 				 bus_info_list) {
10371da177e4SLinus Torvalds 		kfree (bus_info);
10381da177e4SLinus Torvalds 	}
10391da177e4SLinus Torvalds }
10401da177e4SLinus Torvalds 
ibmphp_free_ebda_hpc_queue(void)10411da177e4SLinus Torvalds void ibmphp_free_ebda_hpc_queue(void)
10421da177e4SLinus Torvalds {
10432ac83cccSGeliang Tang 	struct controller *controller = NULL, *next;
10441da177e4SLinus Torvalds 	int pci_flag = 0;
10451da177e4SLinus Torvalds 
10462ac83cccSGeliang Tang 	list_for_each_entry_safe(controller, next, &ebda_hpc_head,
10472ac83cccSGeliang Tang 				 ebda_hpc_list) {
10481da177e4SLinus Torvalds 		if (controller->ctlr_type == 0)
10491da177e4SLinus Torvalds 			release_region(controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
10501da177e4SLinus Torvalds 		else if ((controller->ctlr_type == 1) && (!pci_flag)) {
10511da177e4SLinus Torvalds 			++pci_flag;
10521da177e4SLinus Torvalds 			pci_unregister_driver(&ibmphp_driver);
10531da177e4SLinus Torvalds 		}
10541da177e4SLinus Torvalds 		free_ebda_hpc(controller);
10551da177e4SLinus Torvalds 	}
10561da177e4SLinus Torvalds }
10571da177e4SLinus Torvalds 
ibmphp_free_ebda_pci_rsrc_queue(void)10581da177e4SLinus Torvalds void ibmphp_free_ebda_pci_rsrc_queue(void)
10591da177e4SLinus Torvalds {
10602ac83cccSGeliang Tang 	struct ebda_pci_rsrc *resource, *next;
10611da177e4SLinus Torvalds 
10622ac83cccSGeliang Tang 	list_for_each_entry_safe(resource, next, &ibmphp_ebda_pci_rsrc_head,
10632ac83cccSGeliang Tang 				 ebda_pci_rsrc_list) {
10641da177e4SLinus Torvalds 		kfree (resource);
10651da177e4SLinus Torvalds 		resource = NULL;
10661da177e4SLinus Torvalds 	}
10671da177e4SLinus Torvalds }
10681da177e4SLinus Torvalds 
10698394264dSArvind Yadav static const struct pci_device_id id_table[] = {
10701da177e4SLinus Torvalds 	{
10711da177e4SLinus Torvalds 		.vendor		= PCI_VENDOR_ID_IBM,
10721da177e4SLinus Torvalds 		.device		= HPC_DEVICE_ID,
10731da177e4SLinus Torvalds 		.subvendor	= PCI_VENDOR_ID_IBM,
10741da177e4SLinus Torvalds 		.subdevice	= HPC_SUBSYSTEM_ID,
10751da177e4SLinus Torvalds 		.class		= ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
10761da177e4SLinus Torvalds 	}, {}
10771da177e4SLinus Torvalds };
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, id_table);
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds static int ibmphp_probe(struct pci_dev *, const struct pci_device_id *);
10821da177e4SLinus Torvalds static struct pci_driver ibmphp_driver = {
10831da177e4SLinus Torvalds 	.name		= "ibmphp",
10841da177e4SLinus Torvalds 	.id_table	= id_table,
10851da177e4SLinus Torvalds 	.probe		= ibmphp_probe,
10861da177e4SLinus Torvalds };
10871da177e4SLinus Torvalds 
ibmphp_register_pci(void)10881da177e4SLinus Torvalds int ibmphp_register_pci(void)
10891da177e4SLinus Torvalds {
10901da177e4SLinus Torvalds 	struct controller *ctrl;
10911da177e4SLinus Torvalds 	int rc = 0;
10921da177e4SLinus Torvalds 
1093a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
10941da177e4SLinus Torvalds 		if (ctrl->ctlr_type == 1) {
10951da177e4SLinus Torvalds 			rc = pci_register_driver(&ibmphp_driver);
10961da177e4SLinus Torvalds 			break;
10971da177e4SLinus Torvalds 		}
10981da177e4SLinus Torvalds 	}
10991da177e4SLinus Torvalds 	return rc;
11001da177e4SLinus Torvalds }
ibmphp_probe(struct pci_dev * dev,const struct pci_device_id * ids)11011da177e4SLinus Torvalds static int ibmphp_probe(struct pci_dev *dev, const struct pci_device_id *ids)
11021da177e4SLinus Torvalds {
11031da177e4SLinus Torvalds 	struct controller *ctrl;
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 	debug("inside ibmphp_probe\n");
11061da177e4SLinus Torvalds 
1107a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
11081da177e4SLinus Torvalds 		if (ctrl->ctlr_type == 1) {
11091da177e4SLinus Torvalds 			if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
11101da177e4SLinus Torvalds 				ctrl->ctrl_dev = dev;
11111da177e4SLinus Torvalds 				debug("found device!!!\n");
11121da177e4SLinus Torvalds 				debug("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
11131da177e4SLinus Torvalds 				return 0;
11141da177e4SLinus Torvalds 			}
11151da177e4SLinus Torvalds 		}
11161da177e4SLinus Torvalds 	}
11171da177e4SLinus Torvalds 	return -ENODEV;
11181da177e4SLinus Torvalds }
1119