11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * IBM Hot Plug Controller Driver
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Written By: Tong Yu, IBM Corporation
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
71da177e4SLinus Torvalds  * Copyright (C) 2001-2003 IBM Corp.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * All rights reserved.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
121da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
131da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or (at
141da177e4SLinus Torvalds  * your option) any later version.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful, but
171da177e4SLinus Torvalds  * WITHOUT ANY WARRANTY; without even the implied warranty of
181da177e4SLinus Torvalds  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
191da177e4SLinus Torvalds  * NON INFRINGEMENT.  See the GNU General Public License for more
201da177e4SLinus Torvalds  * details.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
231da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
241da177e4SLinus Torvalds  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
251da177e4SLinus Torvalds  *
261da177e4SLinus Torvalds  * Send feedback to <gregkh@us.ibm.com>
271da177e4SLinus Torvalds  *
281da177e4SLinus Torvalds  */
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/module.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/mm.h>
331da177e4SLinus Torvalds #include <linux/slab.h>
341da177e4SLinus Torvalds #include <linux/pci.h>
351da177e4SLinus Torvalds #include <linux/list.h>
361da177e4SLinus Torvalds #include <linux/init.h>
371da177e4SLinus Torvalds #include "ibmphp.h"
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds /*
401da177e4SLinus Torvalds  * POST builds data blocks(in this data block definition, a char-1
411da177e4SLinus Torvalds  * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended
421da177e4SLinus Torvalds  * BIOS Data Area which describe the configuration of the hot-plug
431da177e4SLinus Torvalds  * controllers and resources used by the PCI Hot-Plug devices.
441da177e4SLinus Torvalds  *
451da177e4SLinus Torvalds  * This file walks EBDA, maps data block from physical addr,
461da177e4SLinus Torvalds  * reconstruct linked lists about all system resource(MEM, PFM, IO)
471da177e4SLinus Torvalds  * already assigned by POST, as well as linked lists about hot plug
481da177e4SLinus Torvalds  * controllers (ctlr#, slot#, bus&slot features...)
491da177e4SLinus Torvalds  */
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds /* Global lists */
521da177e4SLinus Torvalds LIST_HEAD (ibmphp_ebda_pci_rsrc_head);
531da177e4SLinus Torvalds LIST_HEAD (ibmphp_slot_head);
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds /* Local variables */
561da177e4SLinus Torvalds static struct ebda_hpc_list *hpc_list_ptr;
571da177e4SLinus Torvalds static struct ebda_rsrc_list *rsrc_list_ptr;
581da177e4SLinus Torvalds static struct rio_table_hdr *rio_table_ptr = NULL;
591da177e4SLinus Torvalds static LIST_HEAD (ebda_hpc_head);
601da177e4SLinus Torvalds static LIST_HEAD (bus_info_head);
611da177e4SLinus Torvalds static LIST_HEAD (rio_vg_head);
621da177e4SLinus Torvalds static LIST_HEAD (rio_lo_head);
631da177e4SLinus Torvalds static LIST_HEAD (opt_vg_head);
641da177e4SLinus Torvalds static LIST_HEAD (opt_lo_head);
651da177e4SLinus Torvalds static void __iomem *io_mem;
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds /* Local functions */
681da177e4SLinus Torvalds static int ebda_rsrc_controller (void);
691da177e4SLinus Torvalds static int ebda_rsrc_rsrc (void);
701da177e4SLinus Torvalds static int ebda_rio_table (void);
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
731da177e4SLinus Torvalds {
74f5afe806SEric Sesterhenn 	return kzalloc(sizeof(struct ebda_hpc_list), GFP_KERNEL);
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count)
781da177e4SLinus Torvalds {
791da177e4SLinus Torvalds 	struct controller *controller;
801da177e4SLinus Torvalds 	struct ebda_hpc_slot *slots;
811da177e4SLinus Torvalds 	struct ebda_hpc_bus *buses;
821da177e4SLinus Torvalds 
83f5afe806SEric Sesterhenn 	controller = kzalloc(sizeof(struct controller), GFP_KERNEL);
841da177e4SLinus Torvalds 	if (!controller)
851da177e4SLinus Torvalds 		goto error;
861da177e4SLinus Torvalds 
87f5afe806SEric Sesterhenn 	slots = kcalloc(slot_count, sizeof(struct ebda_hpc_slot), GFP_KERNEL);
881da177e4SLinus Torvalds 	if (!slots)
891da177e4SLinus Torvalds 		goto error_contr;
901da177e4SLinus Torvalds 	controller->slots = slots;
911da177e4SLinus Torvalds 
92f5afe806SEric Sesterhenn 	buses = kcalloc(bus_count, sizeof(struct ebda_hpc_bus), GFP_KERNEL);
931da177e4SLinus Torvalds 	if (!buses)
941da177e4SLinus Torvalds 		goto error_slots;
951da177e4SLinus Torvalds 	controller->buses = buses;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	return controller;
981da177e4SLinus Torvalds error_slots:
991da177e4SLinus Torvalds 	kfree(controller->slots);
1001da177e4SLinus Torvalds error_contr:
1011da177e4SLinus Torvalds 	kfree(controller);
1021da177e4SLinus Torvalds error:
1031da177e4SLinus Torvalds 	return NULL;
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds static void free_ebda_hpc (struct controller *controller)
1071da177e4SLinus Torvalds {
1081da177e4SLinus Torvalds 	kfree (controller->slots);
1091da177e4SLinus Torvalds 	kfree (controller->buses);
1101da177e4SLinus Torvalds 	kfree (controller);
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void)
1141da177e4SLinus Torvalds {
115f5afe806SEric Sesterhenn 	return kzalloc(sizeof(struct ebda_rsrc_list), GFP_KERNEL);
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void)
1191da177e4SLinus Torvalds {
120f5afe806SEric Sesterhenn 	return kzalloc(sizeof(struct ebda_pci_rsrc), GFP_KERNEL);
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds static void __init print_bus_info (void)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	struct bus_info *ptr;
1261da177e4SLinus Torvalds 
127a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
12866bef8c0SHarvey Harrison 		debug ("%s - slot_min = %x\n", __func__, ptr->slot_min);
12966bef8c0SHarvey Harrison 		debug ("%s - slot_max = %x\n", __func__, ptr->slot_max);
13066bef8c0SHarvey Harrison 		debug ("%s - slot_count = %x\n", __func__, ptr->slot_count);
13166bef8c0SHarvey Harrison 		debug ("%s - bus# = %x\n", __func__, ptr->busno);
13266bef8c0SHarvey Harrison 		debug ("%s - current_speed = %x\n", __func__, ptr->current_speed);
13366bef8c0SHarvey Harrison 		debug ("%s - controller_id = %x\n", __func__, ptr->controller_id);
1341da177e4SLinus Torvalds 
13566bef8c0SHarvey Harrison 		debug ("%s - slots_at_33_conv = %x\n", __func__, ptr->slots_at_33_conv);
13666bef8c0SHarvey Harrison 		debug ("%s - slots_at_66_conv = %x\n", __func__, ptr->slots_at_66_conv);
13766bef8c0SHarvey Harrison 		debug ("%s - slots_at_66_pcix = %x\n", __func__, ptr->slots_at_66_pcix);
13866bef8c0SHarvey Harrison 		debug ("%s - slots_at_100_pcix = %x\n", __func__, ptr->slots_at_100_pcix);
13966bef8c0SHarvey Harrison 		debug ("%s - slots_at_133_pcix = %x\n", __func__, ptr->slots_at_133_pcix);
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	}
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds static void print_lo_info (void)
1451da177e4SLinus Torvalds {
1461da177e4SLinus Torvalds 	struct rio_detail *ptr;
1471da177e4SLinus Torvalds 	debug ("print_lo_info ----\n");
148a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &rio_lo_head, rio_detail_list) {
14966bef8c0SHarvey Harrison 		debug ("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
15066bef8c0SHarvey Harrison 		debug ("%s - rio_type = %x\n", __func__, ptr->rio_type);
15166bef8c0SHarvey Harrison 		debug ("%s - owner_id = %x\n", __func__, ptr->owner_id);
15266bef8c0SHarvey Harrison 		debug ("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
15366bef8c0SHarvey Harrison 		debug ("%s - wpindex = %x\n", __func__, ptr->wpindex);
15466bef8c0SHarvey Harrison 		debug ("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	}
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds static void print_vg_info (void)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds 	struct rio_detail *ptr;
16266bef8c0SHarvey Harrison 	debug ("%s ---\n", __func__);
163a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &rio_vg_head, rio_detail_list) {
16466bef8c0SHarvey Harrison 		debug ("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
16566bef8c0SHarvey Harrison 		debug ("%s - rio_type = %x\n", __func__, ptr->rio_type);
16666bef8c0SHarvey Harrison 		debug ("%s - owner_id = %x\n", __func__, ptr->owner_id);
16766bef8c0SHarvey Harrison 		debug ("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
16866bef8c0SHarvey Harrison 		debug ("%s - wpindex = %x\n", __func__, ptr->wpindex);
16966bef8c0SHarvey Harrison 		debug ("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	}
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds static void __init print_ebda_pci_rsrc (void)
1751da177e4SLinus Torvalds {
1761da177e4SLinus Torvalds 	struct ebda_pci_rsrc *ptr;
1771da177e4SLinus Torvalds 
178a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &ibmphp_ebda_pci_rsrc_head, ebda_pci_rsrc_list) {
1791da177e4SLinus Torvalds 		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
18066bef8c0SHarvey Harrison 			__func__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr);
1811da177e4SLinus Torvalds 	}
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds static void __init print_ibm_slot (void)
1851da177e4SLinus Torvalds {
1861da177e4SLinus Torvalds 	struct slot *ptr;
1871da177e4SLinus Torvalds 
188a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &ibmphp_slot_head, ibm_slot_list) {
18966bef8c0SHarvey Harrison 		debug ("%s - slot_number: %x\n", __func__, ptr->number);
1901da177e4SLinus Torvalds 	}
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds static void __init print_opt_vg (void)
1941da177e4SLinus Torvalds {
1951da177e4SLinus Torvalds 	struct opt_rio *ptr;
19666bef8c0SHarvey Harrison 	debug ("%s ---\n", __func__);
197a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
19866bef8c0SHarvey Harrison 		debug ("%s - rio_type %x\n", __func__, ptr->rio_type);
19966bef8c0SHarvey Harrison 		debug ("%s - chassis_num: %x\n", __func__, ptr->chassis_num);
20066bef8c0SHarvey Harrison 		debug ("%s - first_slot_num: %x\n", __func__, ptr->first_slot_num);
20166bef8c0SHarvey Harrison 		debug ("%s - middle_num: %x\n", __func__, ptr->middle_num);
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds static void __init print_ebda_hpc (void)
2061da177e4SLinus Torvalds {
2071da177e4SLinus Torvalds 	struct controller *hpc_ptr;
2081da177e4SLinus Torvalds 	u16 index;
2091da177e4SLinus Torvalds 
210a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(hpc_ptr, &ebda_hpc_head, ebda_hpc_list) {
2111da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->slot_count; index++) {
21266bef8c0SHarvey Harrison 			debug ("%s - physical slot#: %x\n", __func__, hpc_ptr->slots[index].slot_num);
21366bef8c0SHarvey Harrison 			debug ("%s - pci bus# of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_bus_num);
21466bef8c0SHarvey Harrison 			debug ("%s - index into ctlr addr: %x\n", __func__, hpc_ptr->slots[index].ctl_index);
21566bef8c0SHarvey Harrison 			debug ("%s - cap of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_cap);
2161da177e4SLinus Torvalds 		}
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->bus_count; index++) {
21966bef8c0SHarvey Harrison 			debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __func__, hpc_ptr->buses[index].bus_num);
2201da177e4SLinus Torvalds 		}
2211da177e4SLinus Torvalds 
22266bef8c0SHarvey Harrison 		debug ("%s - type of hpc: %x\n", __func__, hpc_ptr->ctlr_type);
2231da177e4SLinus Torvalds 		switch (hpc_ptr->ctlr_type) {
2241da177e4SLinus Torvalds 		case 1:
22566bef8c0SHarvey Harrison 			debug ("%s - bus: %x\n", __func__, hpc_ptr->u.pci_ctlr.bus);
22666bef8c0SHarvey Harrison 			debug ("%s - dev_fun: %x\n", __func__, hpc_ptr->u.pci_ctlr.dev_fun);
22766bef8c0SHarvey Harrison 			debug ("%s - irq: %x\n", __func__, hpc_ptr->irq);
2281da177e4SLinus Torvalds 			break;
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 		case 0:
23166bef8c0SHarvey Harrison 			debug ("%s - io_start: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_start);
23266bef8c0SHarvey Harrison 			debug ("%s - io_end: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_end);
23366bef8c0SHarvey Harrison 			debug ("%s - irq: %x\n", __func__, hpc_ptr->irq);
2341da177e4SLinus Torvalds 			break;
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 		case 2:
2371da177e4SLinus Torvalds 		case 4:
23866bef8c0SHarvey Harrison 			debug ("%s - wpegbbar: %lx\n", __func__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
23966bef8c0SHarvey Harrison 			debug ("%s - i2c_addr: %x\n", __func__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
24066bef8c0SHarvey Harrison 			debug ("%s - irq: %x\n", __func__, hpc_ptr->irq);
2411da177e4SLinus Torvalds 			break;
2421da177e4SLinus Torvalds 		}
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds int __init ibmphp_access_ebda (void)
2471da177e4SLinus Torvalds {
248b0fc889cSChandru 	u8 format, num_ctlrs, rio_complete, hs_complete, ebda_sz;
2491da177e4SLinus Torvalds 	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
2501da177e4SLinus Torvalds 	int rc = 0;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	rio_complete = 0;
2541da177e4SLinus Torvalds 	hs_complete = 0;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	io_mem = ioremap ((0x40 << 4) + 0x0e, 2);
2571da177e4SLinus Torvalds 	if (!io_mem )
2581da177e4SLinus Torvalds 		return -ENOMEM;
2591da177e4SLinus Torvalds 	ebda_seg = readw (io_mem);
2601da177e4SLinus Torvalds 	iounmap (io_mem);
2611da177e4SLinus Torvalds 	debug ("returned ebda segment: %x\n", ebda_seg);
2621da177e4SLinus Torvalds 
263b0fc889cSChandru 	io_mem = ioremap(ebda_seg<<4, 1);
264ba02b242SAndrew Morton 	if (!io_mem)
265ba02b242SAndrew Morton 		return -ENOMEM;
266b0fc889cSChandru 	ebda_sz = readb(io_mem);
267b0fc889cSChandru 	iounmap(io_mem);
268b0fc889cSChandru 	debug("ebda size: %d(KiB)\n", ebda_sz);
269b0fc889cSChandru 	if (ebda_sz == 0)
270b0fc889cSChandru 		return -ENOMEM;
271b0fc889cSChandru 
272b0fc889cSChandru 	io_mem = ioremap(ebda_seg<<4, (ebda_sz * 1024));
2731da177e4SLinus Torvalds 	if (!io_mem )
2741da177e4SLinus Torvalds 		return -ENOMEM;
2751da177e4SLinus Torvalds 	next_offset = 0x180;
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	for (;;) {
2781da177e4SLinus Torvalds 		offset = next_offset;
279ac3abf2cSSteven Rostedt 
280ac3abf2cSSteven Rostedt 		/* Make sure what we read is still in the mapped section */
281ac3abf2cSSteven Rostedt 		if (WARN(offset > (ebda_sz * 1024 - 4),
282ac3abf2cSSteven Rostedt 			 "ibmphp_ebda: next read is beyond ebda_sz\n"))
283ac3abf2cSSteven Rostedt 			break;
284ac3abf2cSSteven Rostedt 
2851da177e4SLinus Torvalds 		next_offset = readw (io_mem + offset);	/* offset of next blk */
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 		offset += 2;
2881da177e4SLinus Torvalds 		if (next_offset == 0)	/* 0 indicate it's last blk */
2891da177e4SLinus Torvalds 			break;
2901da177e4SLinus Torvalds 		blk_id = readw (io_mem + offset);	/* this blk id */
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 		offset += 2;
2931da177e4SLinus Torvalds 		/* check if it is hot swap block or rio block */
2941da177e4SLinus Torvalds 		if (blk_id != 0x4853 && blk_id != 0x4752)
2951da177e4SLinus Torvalds 			continue;
2961da177e4SLinus Torvalds 		/* found hs table */
2971da177e4SLinus Torvalds 		if (blk_id == 0x4853) {
2981da177e4SLinus Torvalds 			debug ("now enter hot swap block---\n");
2991da177e4SLinus Torvalds 			debug ("hot blk id: %x\n", blk_id);
3001da177e4SLinus Torvalds 			format = readb (io_mem + offset);
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 			offset += 1;
3031da177e4SLinus Torvalds 			if (format != 4)
3041da177e4SLinus Torvalds 				goto error_nodev;
3051da177e4SLinus Torvalds 			debug ("hot blk format: %x\n", format);
3061da177e4SLinus Torvalds 			/* hot swap sub blk */
3071da177e4SLinus Torvalds 			base = offset;
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 			sub_addr = base;
3101da177e4SLinus Torvalds 			re = readw (io_mem + sub_addr);	/* next sub blk */
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 			sub_addr += 2;
3131da177e4SLinus Torvalds 			rc_id = readw (io_mem + sub_addr); 	/* sub blk id */
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 			sub_addr += 2;
3161da177e4SLinus Torvalds 			if (rc_id != 0x5243)
3171da177e4SLinus Torvalds 				goto error_nodev;
3181da177e4SLinus Torvalds 			/* rc sub blk signature  */
3191da177e4SLinus Torvalds 			num_ctlrs = readb (io_mem + sub_addr);
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 			sub_addr += 1;
3221da177e4SLinus Torvalds 			hpc_list_ptr = alloc_ebda_hpc_list ();
3231da177e4SLinus Torvalds 			if (!hpc_list_ptr) {
3241da177e4SLinus Torvalds 				rc = -ENOMEM;
3251da177e4SLinus Torvalds 				goto out;
3261da177e4SLinus Torvalds 			}
3271da177e4SLinus Torvalds 			hpc_list_ptr->format = format;
3281da177e4SLinus Torvalds 			hpc_list_ptr->num_ctlrs = num_ctlrs;
3291da177e4SLinus Torvalds 			hpc_list_ptr->phys_addr = sub_addr;	/*  offset of RSRC_CONTROLLER blk */
3301da177e4SLinus Torvalds 			debug ("info about hpc descriptor---\n");
3311da177e4SLinus Torvalds 			debug ("hot blk format: %x\n", format);
3321da177e4SLinus Torvalds 			debug ("num of controller: %x\n", num_ctlrs);
3331da177e4SLinus Torvalds 			debug ("offset of hpc data structure enteries: %x\n ", sub_addr);
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 			sub_addr = base + re;	/* re sub blk */
3361da177e4SLinus Torvalds 			/* FIXME: rc is never used/checked */
3371da177e4SLinus Torvalds 			rc = readw (io_mem + sub_addr);	/* next sub blk */
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 			sub_addr += 2;
3401da177e4SLinus Torvalds 			re_id = readw (io_mem + sub_addr);	/* sub blk id */
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 			sub_addr += 2;
3431da177e4SLinus Torvalds 			if (re_id != 0x5245)
3441da177e4SLinus Torvalds 				goto error_nodev;
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 			/* signature of re */
3471da177e4SLinus Torvalds 			num_entries = readw (io_mem + sub_addr);
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 			sub_addr += 2;	/* offset of RSRC_ENTRIES blk */
3501da177e4SLinus Torvalds 			rsrc_list_ptr = alloc_ebda_rsrc_list ();
3511da177e4SLinus Torvalds 			if (!rsrc_list_ptr ) {
3521da177e4SLinus Torvalds 				rc = -ENOMEM;
3531da177e4SLinus Torvalds 				goto out;
3541da177e4SLinus Torvalds 			}
3551da177e4SLinus Torvalds 			rsrc_list_ptr->format = format;
3561da177e4SLinus Torvalds 			rsrc_list_ptr->num_entries = num_entries;
3571da177e4SLinus Torvalds 			rsrc_list_ptr->phys_addr = sub_addr;
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 			debug ("info about rsrc descriptor---\n");
3601da177e4SLinus Torvalds 			debug ("format: %x\n", format);
3611da177e4SLinus Torvalds 			debug ("num of rsrc: %x\n", num_entries);
3621da177e4SLinus Torvalds 			debug ("offset of rsrc data structure enteries: %x\n ", sub_addr);
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 			hs_complete = 1;
3651da177e4SLinus Torvalds 		} else {
3661da177e4SLinus Torvalds 		/* found rio table, blk_id == 0x4752 */
3671da177e4SLinus Torvalds 			debug ("now enter io table ---\n");
3681da177e4SLinus Torvalds 			debug ("rio blk id: %x\n", blk_id);
3691da177e4SLinus Torvalds 
370f5afe806SEric Sesterhenn 			rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL);
3718f0cdddcSJulia Lawall 			if (!rio_table_ptr) {
3728f0cdddcSJulia Lawall 				rc = -ENOMEM;
3738f0cdddcSJulia Lawall 				goto out;
3748f0cdddcSJulia Lawall 			}
3751da177e4SLinus Torvalds 			rio_table_ptr->ver_num = readb (io_mem + offset);
3761da177e4SLinus Torvalds 			rio_table_ptr->scal_count = readb (io_mem + offset + 1);
3771da177e4SLinus Torvalds 			rio_table_ptr->riodev_count = readb (io_mem + offset + 2);
3781da177e4SLinus Torvalds 			rio_table_ptr->offset = offset +3 ;
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 			debug("info about rio table hdr ---\n");
3811da177e4SLinus Torvalds 			debug("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ",
3821da177e4SLinus Torvalds 				rio_table_ptr->ver_num, rio_table_ptr->scal_count,
3831da177e4SLinus Torvalds 				rio_table_ptr->riodev_count, rio_table_ptr->offset);
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 			rio_complete = 1;
3861da177e4SLinus Torvalds 		}
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	if (!hs_complete && !rio_complete)
3901da177e4SLinus Torvalds 		goto error_nodev;
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	if (rio_table_ptr) {
3931da177e4SLinus Torvalds 		if (rio_complete && rio_table_ptr->ver_num == 3) {
3941da177e4SLinus Torvalds 			rc = ebda_rio_table ();
3951da177e4SLinus Torvalds 			if (rc)
3961da177e4SLinus Torvalds 				goto out;
3971da177e4SLinus Torvalds 		}
3981da177e4SLinus Torvalds 	}
3991da177e4SLinus Torvalds 	rc = ebda_rsrc_controller ();
4001da177e4SLinus Torvalds 	if (rc)
4011da177e4SLinus Torvalds 		goto out;
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds 	rc = ebda_rsrc_rsrc ();
4041da177e4SLinus Torvalds 	goto out;
4051da177e4SLinus Torvalds error_nodev:
4061da177e4SLinus Torvalds 	rc = -ENODEV;
4071da177e4SLinus Torvalds out:
4081da177e4SLinus Torvalds 	iounmap (io_mem);
4091da177e4SLinus Torvalds 	return rc;
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds /*
4131da177e4SLinus Torvalds  * map info of scalability details and rio details from physical address
4141da177e4SLinus Torvalds  */
4151da177e4SLinus Torvalds static int __init ebda_rio_table (void)
4161da177e4SLinus Torvalds {
4171da177e4SLinus Torvalds 	u16 offset;
4181da177e4SLinus Torvalds 	u8 i;
4191da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr;
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 	offset = rio_table_ptr->offset;
4221da177e4SLinus Torvalds 	offset += 12 * rio_table_ptr->scal_count;
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	// we do concern about rio details
4251da177e4SLinus Torvalds 	for (i = 0; i < rio_table_ptr->riodev_count; i++) {
426f5afe806SEric Sesterhenn 		rio_detail_ptr = kzalloc(sizeof(struct rio_detail), GFP_KERNEL);
4271da177e4SLinus Torvalds 		if (!rio_detail_ptr)
4281da177e4SLinus Torvalds 			return -ENOMEM;
4291da177e4SLinus Torvalds 		rio_detail_ptr->rio_node_id = readb (io_mem + offset);
4301da177e4SLinus Torvalds 		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
4311da177e4SLinus Torvalds 		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
4321da177e4SLinus Torvalds 		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
4331da177e4SLinus Torvalds 		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
4341da177e4SLinus Torvalds 		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
4351da177e4SLinus Torvalds 		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
4361da177e4SLinus Torvalds 		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
4371da177e4SLinus Torvalds 		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
4381da177e4SLinus Torvalds 		rio_detail_ptr->status = readb (io_mem + offset + 12);
4391da177e4SLinus Torvalds 		rio_detail_ptr->wpindex = readb (io_mem + offset + 13);
4401da177e4SLinus Torvalds 		rio_detail_ptr->chassis_num = readb (io_mem + offset + 14);
4411da177e4SLinus 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);
4421da177e4SLinus Torvalds 		//create linked list of chassis
4431da177e4SLinus Torvalds 		if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5)
4441da177e4SLinus Torvalds 			list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head);
4451da177e4SLinus Torvalds 		//create linked list of expansion box
4461da177e4SLinus Torvalds 		else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7)
4471da177e4SLinus Torvalds 			list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head);
4481da177e4SLinus Torvalds 		else
4491da177e4SLinus Torvalds 			// not in my concern
4501da177e4SLinus Torvalds 			kfree (rio_detail_ptr);
4511da177e4SLinus Torvalds 		offset += 15;
4521da177e4SLinus Torvalds 	}
4531da177e4SLinus Torvalds 	print_lo_info ();
4541da177e4SLinus Torvalds 	print_vg_info ();
4551da177e4SLinus Torvalds 	return 0;
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds /*
4591da177e4SLinus Torvalds  * reorganizing linked list of chassis
4601da177e4SLinus Torvalds  */
4611da177e4SLinus Torvalds static struct opt_rio *search_opt_vg (u8 chassis_num)
4621da177e4SLinus Torvalds {
4631da177e4SLinus Torvalds 	struct opt_rio *ptr;
464a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
4651da177e4SLinus Torvalds 		if (ptr->chassis_num == chassis_num)
4661da177e4SLinus Torvalds 			return ptr;
4671da177e4SLinus Torvalds 	}
4681da177e4SLinus Torvalds 	return NULL;
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds static int __init combine_wpg_for_chassis (void)
4721da177e4SLinus Torvalds {
4731da177e4SLinus Torvalds 	struct opt_rio *opt_rio_ptr = NULL;
4741da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr = NULL;
4751da177e4SLinus Torvalds 
476a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(rio_detail_ptr, &rio_vg_head, rio_detail_list) {
4771da177e4SLinus Torvalds 		opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num);
4781da177e4SLinus Torvalds 		if (!opt_rio_ptr) {
479f5afe806SEric Sesterhenn 			opt_rio_ptr = kzalloc(sizeof(struct opt_rio), GFP_KERNEL);
4801da177e4SLinus Torvalds 			if (!opt_rio_ptr)
4811da177e4SLinus Torvalds 				return -ENOMEM;
4821da177e4SLinus Torvalds 			opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
4831da177e4SLinus Torvalds 			opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
4841da177e4SLinus Torvalds 			opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
4851da177e4SLinus Torvalds 			opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
4861da177e4SLinus Torvalds 			list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head);
4871da177e4SLinus Torvalds 		} else {
4881da177e4SLinus Torvalds 			opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
4891da177e4SLinus Torvalds 			opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
4901da177e4SLinus Torvalds 		}
4911da177e4SLinus Torvalds 	}
4921da177e4SLinus Torvalds 	print_opt_vg ();
4931da177e4SLinus Torvalds 	return 0;
4941da177e4SLinus Torvalds }
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds /*
497a8d2dbd3Sakpm@linux-foundation.org  * reorganizing linked list of expansion box
4981da177e4SLinus Torvalds  */
4991da177e4SLinus Torvalds static struct opt_rio_lo *search_opt_lo (u8 chassis_num)
5001da177e4SLinus Torvalds {
5011da177e4SLinus Torvalds 	struct opt_rio_lo *ptr;
502a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &opt_lo_head, opt_rio_lo_list) {
5031da177e4SLinus Torvalds 		if (ptr->chassis_num == chassis_num)
5041da177e4SLinus Torvalds 			return ptr;
5051da177e4SLinus Torvalds 	}
5061da177e4SLinus Torvalds 	return NULL;
5071da177e4SLinus Torvalds }
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds static int combine_wpg_for_expansion (void)
5101da177e4SLinus Torvalds {
5111da177e4SLinus Torvalds 	struct opt_rio_lo *opt_rio_lo_ptr = NULL;
5121da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr = NULL;
5131da177e4SLinus Torvalds 
514a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(rio_detail_ptr, &rio_lo_head, rio_detail_list) {
5151da177e4SLinus Torvalds 		opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num);
5161da177e4SLinus Torvalds 		if (!opt_rio_lo_ptr) {
517f5afe806SEric Sesterhenn 			opt_rio_lo_ptr = kzalloc(sizeof(struct opt_rio_lo), GFP_KERNEL);
5181da177e4SLinus Torvalds 			if (!opt_rio_lo_ptr)
5191da177e4SLinus Torvalds 				return -ENOMEM;
5201da177e4SLinus Torvalds 			opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
5211da177e4SLinus Torvalds 			opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
5221da177e4SLinus Torvalds 			opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
5231da177e4SLinus Torvalds 			opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
5241da177e4SLinus Torvalds 			opt_rio_lo_ptr->pack_count = 1;
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 			list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
5271da177e4SLinus Torvalds 		} else {
5281da177e4SLinus Torvalds 			opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
5291da177e4SLinus Torvalds 			opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
5301da177e4SLinus Torvalds 			opt_rio_lo_ptr->pack_count = 2;
5311da177e4SLinus Torvalds 		}
5321da177e4SLinus Torvalds 	}
5331da177e4SLinus Torvalds 	return 0;
5341da177e4SLinus Torvalds }
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds /* Since we don't know the max slot number per each chassis, hence go
5381da177e4SLinus Torvalds  * through the list of all chassis to find out the range
5391da177e4SLinus Torvalds  * Arguments: slot_num, 1st slot number of the chassis we think we are on,
5401da177e4SLinus Torvalds  * var (0 = chassis, 1 = expansion box)
5411da177e4SLinus Torvalds  */
5421da177e4SLinus Torvalds static int first_slot_num (u8 slot_num, u8 first_slot, u8 var)
5431da177e4SLinus Torvalds {
5441da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr = NULL;
5451da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr = NULL;
5461da177e4SLinus Torvalds 	int rc = 0;
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	if (!var) {
549a8d2dbd3Sakpm@linux-foundation.org 		list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
5501da177e4SLinus Torvalds 			if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) {
5511da177e4SLinus Torvalds 				rc = -ENODEV;
5521da177e4SLinus Torvalds 				break;
5531da177e4SLinus Torvalds 			}
5541da177e4SLinus Torvalds 		}
5551da177e4SLinus Torvalds 	} else {
556a8d2dbd3Sakpm@linux-foundation.org 		list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
5571da177e4SLinus Torvalds 			if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
5581da177e4SLinus Torvalds 				rc = -ENODEV;
5591da177e4SLinus Torvalds 				break;
5601da177e4SLinus Torvalds 			}
5611da177e4SLinus Torvalds 		}
5621da177e4SLinus Torvalds 	}
5631da177e4SLinus Torvalds 	return rc;
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds static struct opt_rio_lo * find_rxe_num (u8 slot_num)
5671da177e4SLinus Torvalds {
5681da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr;
5691da177e4SLinus Torvalds 
570a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
5711da177e4SLinus Torvalds 		//check to see if this slot_num belongs to expansion box
5721da177e4SLinus Torvalds 		if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1)))
5731da177e4SLinus Torvalds 			return opt_lo_ptr;
5741da177e4SLinus Torvalds 	}
5751da177e4SLinus Torvalds 	return NULL;
5761da177e4SLinus Torvalds }
5771da177e4SLinus Torvalds 
5781da177e4SLinus Torvalds static struct opt_rio * find_chassis_num (u8 slot_num)
5791da177e4SLinus Torvalds {
5801da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr;
5811da177e4SLinus Torvalds 
582a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
5831da177e4SLinus Torvalds 		//check to see if this slot_num belongs to chassis
5841da177e4SLinus Torvalds 		if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0)))
5851da177e4SLinus Torvalds 			return opt_vg_ptr;
5861da177e4SLinus Torvalds 	}
5871da177e4SLinus Torvalds 	return NULL;
5881da177e4SLinus Torvalds }
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds /* This routine will find out how many slots are in the chassis, so that
5911da177e4SLinus Torvalds  * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
5921da177e4SLinus Torvalds  */
5931da177e4SLinus Torvalds static u8 calculate_first_slot (u8 slot_num)
5941da177e4SLinus Torvalds {
5951da177e4SLinus Torvalds 	u8 first_slot = 1;
5961da177e4SLinus Torvalds 	struct slot * slot_cur;
5971da177e4SLinus Torvalds 
598a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) {
5991da177e4SLinus Torvalds 		if (slot_cur->ctrl) {
6001da177e4SLinus Torvalds 			if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num))
6011da177e4SLinus Torvalds 				first_slot = slot_cur->ctrl->ending_slot_num;
6021da177e4SLinus Torvalds 		}
6031da177e4SLinus Torvalds 	}
6041da177e4SLinus Torvalds 	return first_slot + 1;
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds }
607a32615a1SAlex Chiang 
608a32615a1SAlex Chiang #define SLOT_NAME_SIZE 30
609a32615a1SAlex Chiang 
6101da177e4SLinus Torvalds static char *create_file_name (struct slot * slot_cur)
6111da177e4SLinus Torvalds {
6121da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr = NULL;
6131da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr = NULL;
614a32615a1SAlex Chiang 	static char str[SLOT_NAME_SIZE];
6151da177e4SLinus Torvalds 	int which = 0; /* rxe = 1, chassis = 0 */
6161da177e4SLinus Torvalds 	u8 number = 1; /* either chassis or rxe # */
6171da177e4SLinus Torvalds 	u8 first_slot = 1;
6181da177e4SLinus Torvalds 	u8 slot_num;
6191da177e4SLinus Torvalds 	u8 flag = 0;
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds 	if (!slot_cur) {
6221da177e4SLinus Torvalds 		err ("Structure passed is empty\n");
6231da177e4SLinus Torvalds 		return NULL;
6241da177e4SLinus Torvalds 	}
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	slot_num = slot_cur->number;
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds 	memset (str, 0, sizeof(str));
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 	if (rio_table_ptr) {
6311da177e4SLinus Torvalds 		if (rio_table_ptr->ver_num == 3) {
6321da177e4SLinus Torvalds 			opt_vg_ptr = find_chassis_num (slot_num);
6331da177e4SLinus Torvalds 			opt_lo_ptr = find_rxe_num (slot_num);
6341da177e4SLinus Torvalds 		}
6351da177e4SLinus Torvalds 	}
6361da177e4SLinus Torvalds 	if (opt_vg_ptr) {
6371da177e4SLinus Torvalds 		if (opt_lo_ptr) {
6381da177e4SLinus Torvalds 			if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
6391da177e4SLinus Torvalds 				number = opt_lo_ptr->chassis_num;
6401da177e4SLinus Torvalds 				first_slot = opt_lo_ptr->first_slot_num;
6411da177e4SLinus Torvalds 				which = 1; /* it is RXE */
6421da177e4SLinus Torvalds 			} else {
6431da177e4SLinus Torvalds 				first_slot = opt_vg_ptr->first_slot_num;
6441da177e4SLinus Torvalds 				number = opt_vg_ptr->chassis_num;
6451da177e4SLinus Torvalds 				which = 0;
6461da177e4SLinus Torvalds 			}
6471da177e4SLinus Torvalds 		} else {
6481da177e4SLinus Torvalds 			first_slot = opt_vg_ptr->first_slot_num;
6491da177e4SLinus Torvalds 			number = opt_vg_ptr->chassis_num;
6501da177e4SLinus Torvalds 			which = 0;
6511da177e4SLinus Torvalds 		}
6521da177e4SLinus Torvalds 		++flag;
6531da177e4SLinus Torvalds 	} else if (opt_lo_ptr) {
6541da177e4SLinus Torvalds 		number = opt_lo_ptr->chassis_num;
6551da177e4SLinus Torvalds 		first_slot = opt_lo_ptr->first_slot_num;
6561da177e4SLinus Torvalds 		which = 1;
6571da177e4SLinus Torvalds 		++flag;
6581da177e4SLinus Torvalds 	} else if (rio_table_ptr) {
6591da177e4SLinus Torvalds 		if (rio_table_ptr->ver_num == 3) {
6601da177e4SLinus Torvalds 			/* if both NULL and we DO have correct RIO table in BIOS */
6611da177e4SLinus Torvalds 			return NULL;
6621da177e4SLinus Torvalds 		}
6631da177e4SLinus Torvalds 	}
6641da177e4SLinus Torvalds 	if (!flag) {
6651da177e4SLinus Torvalds 		if (slot_cur->ctrl->ctlr_type == 4) {
6661da177e4SLinus Torvalds 			first_slot = calculate_first_slot (slot_num);
6671da177e4SLinus Torvalds 			which = 1;
6681da177e4SLinus Torvalds 		} else {
6691da177e4SLinus Torvalds 			which = 0;
6701da177e4SLinus Torvalds 		}
6711da177e4SLinus Torvalds 	}
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds 	sprintf(str, "%s%dslot%d",
6741da177e4SLinus Torvalds 		which == 0 ? "chassis" : "rxe",
6751da177e4SLinus Torvalds 		number, slot_num - first_slot + 1);
6761da177e4SLinus Torvalds 	return str;
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds static int fillslotinfo(struct hotplug_slot *hotplug_slot)
6801da177e4SLinus Torvalds {
6811da177e4SLinus Torvalds 	struct slot *slot;
6821da177e4SLinus Torvalds 	int rc = 0;
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds 	if (!hotplug_slot || !hotplug_slot->private)
6851da177e4SLinus Torvalds 		return -EINVAL;
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 	slot = hotplug_slot->private;
6881da177e4SLinus Torvalds 	rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL);
6891da177e4SLinus Torvalds 	if (rc)
6901da177e4SLinus Torvalds 		return rc;
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 	// power - enabled:1  not:0
6931da177e4SLinus Torvalds 	hotplug_slot->info->power_status = SLOT_POWER(slot->status);
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	// attention - off:0, on:1, blinking:2
6961da177e4SLinus Torvalds 	hotplug_slot->info->attention_status = SLOT_ATTN(slot->status, slot->ext_status);
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	// latch - open:1 closed:0
6991da177e4SLinus Torvalds 	hotplug_slot->info->latch_status = SLOT_LATCH(slot->status);
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	// pci board - present:1 not:0
7021da177e4SLinus Torvalds 	if (SLOT_PRESENT (slot->status))
7031da177e4SLinus Torvalds 		hotplug_slot->info->adapter_status = 1;
7041da177e4SLinus Torvalds 	else
7051da177e4SLinus Torvalds 		hotplug_slot->info->adapter_status = 0;
7061da177e4SLinus Torvalds /*
7071da177e4SLinus Torvalds 	if (slot->bus_on->supported_bus_mode
7081da177e4SLinus Torvalds 		&& (slot->bus_on->supported_speed == BUS_SPEED_66))
7091da177e4SLinus Torvalds 		hotplug_slot->info->max_bus_speed_status = BUS_SPEED_66PCIX;
7101da177e4SLinus Torvalds 	else
7111da177e4SLinus Torvalds 		hotplug_slot->info->max_bus_speed_status = slot->bus_on->supported_speed;
7121da177e4SLinus Torvalds */
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	return rc;
7151da177e4SLinus Torvalds }
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds static void release_slot(struct hotplug_slot *hotplug_slot)
7181da177e4SLinus Torvalds {
7191da177e4SLinus Torvalds 	struct slot *slot;
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds 	if (!hotplug_slot || !hotplug_slot->private)
7221da177e4SLinus Torvalds 		return;
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	slot = hotplug_slot->private;
7251da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->info);
7261da177e4SLinus Torvalds 	kfree(slot->hotplug_slot);
7271da177e4SLinus Torvalds 	slot->ctrl = NULL;
7281da177e4SLinus Torvalds 	slot->bus_on = NULL;
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds 	/* we don't want to actually remove the resources, since free_resources will do just that */
7311da177e4SLinus Torvalds 	ibmphp_unconfigure_card(&slot, -1);
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 	kfree (slot);
7341da177e4SLinus Torvalds }
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds static struct pci_driver ibmphp_driver;
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds /*
7391da177e4SLinus Torvalds  * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
7401da177e4SLinus Torvalds  * each hpc from physical address to a list of hot plug controllers based on
7411da177e4SLinus Torvalds  * hpc descriptors.
7421da177e4SLinus Torvalds  */
7431da177e4SLinus Torvalds static int __init ebda_rsrc_controller (void)
7441da177e4SLinus Torvalds {
7451da177e4SLinus Torvalds 	u16 addr, addr_slot, addr_bus;
7461da177e4SLinus Torvalds 	u8 ctlr_id, temp, bus_index;
7471da177e4SLinus Torvalds 	u16 ctlr, slot, bus;
7481da177e4SLinus Torvalds 	u16 slot_num, bus_num, index;
7491da177e4SLinus Torvalds 	struct hotplug_slot *hp_slot_ptr;
7501da177e4SLinus Torvalds 	struct controller *hpc_ptr;
7511da177e4SLinus Torvalds 	struct ebda_hpc_bus *bus_ptr;
7521da177e4SLinus Torvalds 	struct ebda_hpc_slot *slot_ptr;
7531da177e4SLinus Torvalds 	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
7541da177e4SLinus Torvalds 	int rc;
7551da177e4SLinus Torvalds 	struct slot *tmp_slot;
756a32615a1SAlex Chiang 	char name[SLOT_NAME_SIZE];
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 	addr = hpc_list_ptr->phys_addr;
7591da177e4SLinus Torvalds 	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
7601da177e4SLinus Torvalds 		bus_index = 1;
7611da177e4SLinus Torvalds 		ctlr_id = readb (io_mem + addr);
7621da177e4SLinus Torvalds 		addr += 1;
7631da177e4SLinus Torvalds 		slot_num = readb (io_mem + addr);
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds 		addr += 1;
7661da177e4SLinus Torvalds 		addr_slot = addr;	/* offset of slot structure */
7671da177e4SLinus Torvalds 		addr += (slot_num * 4);
7681da177e4SLinus Torvalds 
7691da177e4SLinus Torvalds 		bus_num = readb (io_mem + addr);
7701da177e4SLinus Torvalds 
7711da177e4SLinus Torvalds 		addr += 1;
7721da177e4SLinus Torvalds 		addr_bus = addr;	/* offset of bus */
7731da177e4SLinus Torvalds 		addr += (bus_num * 9);	/* offset of ctlr_type */
7741da177e4SLinus Torvalds 		temp = readb (io_mem + addr);
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 		addr += 1;
7771da177e4SLinus Torvalds 		/* init hpc structure */
7781da177e4SLinus Torvalds 		hpc_ptr = alloc_ebda_hpc (slot_num, bus_num);
7791da177e4SLinus Torvalds 		if (!hpc_ptr ) {
7801da177e4SLinus Torvalds 			rc = -ENOMEM;
7811da177e4SLinus Torvalds 			goto error_no_hpc;
7821da177e4SLinus Torvalds 		}
7831da177e4SLinus Torvalds 		hpc_ptr->ctlr_id = ctlr_id;
7841da177e4SLinus Torvalds 		hpc_ptr->ctlr_relative_id = ctlr;
7851da177e4SLinus Torvalds 		hpc_ptr->slot_count = slot_num;
7861da177e4SLinus Torvalds 		hpc_ptr->bus_count = bus_num;
7871da177e4SLinus Torvalds 		debug ("now enter ctlr data struture ---\n");
7881da177e4SLinus Torvalds 		debug ("ctlr id: %x\n", ctlr_id);
7891da177e4SLinus Torvalds 		debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id);
7901da177e4SLinus Torvalds 		debug ("count of slots controlled by this ctlr: %x\n", slot_num);
7911da177e4SLinus Torvalds 		debug ("count of buses controlled by this ctlr: %x\n", bus_num);
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 		/* init slot structure, fetch slot, bus, cap... */
7941da177e4SLinus Torvalds 		slot_ptr = hpc_ptr->slots;
7951da177e4SLinus Torvalds 		for (slot = 0; slot < slot_num; slot++) {
7961da177e4SLinus Torvalds 			slot_ptr->slot_num = readb (io_mem + addr_slot);
7971da177e4SLinus Torvalds 			slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num);
7981da177e4SLinus Torvalds 			slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num);
7991da177e4SLinus Torvalds 			slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num);
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 			// create bus_info lined list --- if only one slot per bus: slot_min = slot_max
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds 			bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num);
8041da177e4SLinus Torvalds 			if (!bus_info_ptr2) {
805f5afe806SEric Sesterhenn 				bus_info_ptr1 = kzalloc(sizeof(struct bus_info), GFP_KERNEL);
8061da177e4SLinus Torvalds 				if (!bus_info_ptr1) {
8071da177e4SLinus Torvalds 					rc = -ENOMEM;
8081da177e4SLinus Torvalds 					goto error_no_hp_slot;
8091da177e4SLinus Torvalds 				}
8101da177e4SLinus Torvalds 				bus_info_ptr1->slot_min = slot_ptr->slot_num;
8111da177e4SLinus Torvalds 				bus_info_ptr1->slot_max = slot_ptr->slot_num;
8121da177e4SLinus Torvalds 				bus_info_ptr1->slot_count += 1;
8131da177e4SLinus Torvalds 				bus_info_ptr1->busno = slot_ptr->slot_bus_num;
8141da177e4SLinus Torvalds 				bus_info_ptr1->index = bus_index++;
8151da177e4SLinus Torvalds 				bus_info_ptr1->current_speed = 0xff;
8161da177e4SLinus Torvalds 				bus_info_ptr1->current_bus_mode = 0xff;
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
8191da177e4SLinus Torvalds 
8201da177e4SLinus Torvalds 				list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head);
8211da177e4SLinus Torvalds 
8221da177e4SLinus Torvalds 			} else {
8231da177e4SLinus Torvalds 				bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num);
8241da177e4SLinus Torvalds 				bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num);
8251da177e4SLinus Torvalds 				bus_info_ptr2->slot_count += 1;
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 			}
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds 			// end of creating the bus_info linked list
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds 			slot_ptr++;
8321da177e4SLinus Torvalds 			addr_slot += 1;
8331da177e4SLinus Torvalds 		}
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 		/* init bus structure */
8361da177e4SLinus Torvalds 		bus_ptr = hpc_ptr->buses;
8371da177e4SLinus Torvalds 		for (bus = 0; bus < bus_num; bus++) {
8381da177e4SLinus Torvalds 			bus_ptr->bus_num = readb (io_mem + addr_bus + bus);
8391da177e4SLinus Torvalds 			bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus);
8401da177e4SLinus Torvalds 			bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 			bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2);
8431da177e4SLinus Torvalds 
8441da177e4SLinus Torvalds 			bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3);
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds 			bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4);
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 			bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num);
8491da177e4SLinus Torvalds 			if (bus_info_ptr2) {
8501da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
8511da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
8521da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
8531da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
8541da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix;
8551da177e4SLinus Torvalds 			}
8561da177e4SLinus Torvalds 			bus_ptr++;
8571da177e4SLinus Torvalds 		}
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds 		hpc_ptr->ctlr_type = temp;
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 		switch (hpc_ptr->ctlr_type) {
8621da177e4SLinus Torvalds 			case 1:
8631da177e4SLinus Torvalds 				hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr);
8641da177e4SLinus Torvalds 				hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
8651da177e4SLinus Torvalds 				hpc_ptr->irq = readb (io_mem + addr + 2);
8661da177e4SLinus Torvalds 				addr += 3;
8671da177e4SLinus Torvalds 				debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n",
8681da177e4SLinus Torvalds 					hpc_ptr->u.pci_ctlr.bus,
8691da177e4SLinus Torvalds 					hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
8701da177e4SLinus Torvalds 				break;
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 			case 0:
8731da177e4SLinus Torvalds 				hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
8741da177e4SLinus Torvalds 				hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
8751da177e4SLinus Torvalds 				if (!request_region (hpc_ptr->u.isa_ctlr.io_start,
8761da177e4SLinus Torvalds 						     (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
8771da177e4SLinus Torvalds 						     "ibmphp")) {
8781da177e4SLinus Torvalds 					rc = -ENODEV;
8791da177e4SLinus Torvalds 					goto error_no_hp_slot;
8801da177e4SLinus Torvalds 				}
8811da177e4SLinus Torvalds 				hpc_ptr->irq = readb (io_mem + addr + 4);
8821da177e4SLinus Torvalds 				addr += 5;
8831da177e4SLinus Torvalds 				break;
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds 			case 2:
8861da177e4SLinus Torvalds 			case 4:
8871da177e4SLinus Torvalds 				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
8881da177e4SLinus Torvalds 				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
8891da177e4SLinus Torvalds 				hpc_ptr->irq = readb (io_mem + addr + 5);
8901da177e4SLinus Torvalds 				addr += 6;
8911da177e4SLinus Torvalds 				break;
8921da177e4SLinus Torvalds 			default:
8931da177e4SLinus Torvalds 				rc = -ENODEV;
8941da177e4SLinus Torvalds 				goto error_no_hp_slot;
8951da177e4SLinus Torvalds 		}
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 		//reorganize chassis' linked list
8981da177e4SLinus Torvalds 		combine_wpg_for_chassis ();
8991da177e4SLinus Torvalds 		combine_wpg_for_expansion ();
9001da177e4SLinus Torvalds 		hpc_ptr->revision = 0xff;
9011da177e4SLinus Torvalds 		hpc_ptr->options = 0xff;
9021da177e4SLinus Torvalds 		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
9031da177e4SLinus Torvalds 		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds 		// register slots with hpc core as well as create linked list of ibm slot
9061da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->slot_count; index++) {
9071da177e4SLinus Torvalds 
908f5afe806SEric Sesterhenn 			hp_slot_ptr = kzalloc(sizeof(*hp_slot_ptr), GFP_KERNEL);
9091da177e4SLinus Torvalds 			if (!hp_slot_ptr) {
9101da177e4SLinus Torvalds 				rc = -ENOMEM;
9111da177e4SLinus Torvalds 				goto error_no_hp_slot;
9121da177e4SLinus Torvalds 			}
9131da177e4SLinus Torvalds 
914f5afe806SEric Sesterhenn 			hp_slot_ptr->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
9151da177e4SLinus Torvalds 			if (!hp_slot_ptr->info) {
9161da177e4SLinus Torvalds 				rc = -ENOMEM;
9171da177e4SLinus Torvalds 				goto error_no_hp_info;
9181da177e4SLinus Torvalds 			}
9191da177e4SLinus Torvalds 
920f5afe806SEric Sesterhenn 			tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL);
9211da177e4SLinus Torvalds 			if (!tmp_slot) {
9221da177e4SLinus Torvalds 				rc = -ENOMEM;
9231da177e4SLinus Torvalds 				goto error_no_slot;
9241da177e4SLinus Torvalds 			}
9251da177e4SLinus Torvalds 
926dc6712d1SKristen Accardi 			tmp_slot->flag = 1;
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds 			tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
9291da177e4SLinus Torvalds 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
9301da177e4SLinus Torvalds 				tmp_slot->supported_speed =  3;
9311da177e4SLinus Torvalds 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
9321da177e4SLinus Torvalds 				tmp_slot->supported_speed =  2;
9331da177e4SLinus Torvalds 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
9341da177e4SLinus Torvalds 				tmp_slot->supported_speed =  1;
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
9371da177e4SLinus Torvalds 				tmp_slot->supported_bus_mode = 1;
9381da177e4SLinus Torvalds 			else
9391da177e4SLinus Torvalds 				tmp_slot->supported_bus_mode = 0;
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 
9421da177e4SLinus Torvalds 			tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
9451da177e4SLinus Torvalds 			if (!bus_info_ptr1) {
946b91aac29SJesper Juhl 				kfree(tmp_slot);
9471da177e4SLinus Torvalds 				rc = -ENODEV;
9481da177e4SLinus Torvalds 				goto error;
9491da177e4SLinus Torvalds 			}
9501da177e4SLinus Torvalds 			tmp_slot->bus_on = bus_info_ptr1;
9511da177e4SLinus Torvalds 			bus_info_ptr1 = NULL;
9521da177e4SLinus Torvalds 			tmp_slot->ctrl = hpc_ptr;
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds 			tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
9551da177e4SLinus Torvalds 			tmp_slot->number = hpc_ptr->slots[index].slot_num;
9561da177e4SLinus Torvalds 			tmp_slot->hotplug_slot = hp_slot_ptr;
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 			hp_slot_ptr->private = tmp_slot;
9591da177e4SLinus Torvalds 			hp_slot_ptr->release = release_slot;
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 			rc = fillslotinfo(hp_slot_ptr);
9621da177e4SLinus Torvalds 			if (rc)
9631da177e4SLinus Torvalds 				goto error;
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 			rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private);
9661da177e4SLinus Torvalds 			if (rc)
9671da177e4SLinus Torvalds 				goto error;
9681da177e4SLinus Torvalds 			hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds 			// end of registering ibm slot with hotplug core
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 			list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head);
9731da177e4SLinus Torvalds 		}
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 		print_bus_info ();
9761da177e4SLinus Torvalds 		list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head );
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds 	}			/* each hpc  */
9791da177e4SLinus Torvalds 
980a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) {
981a32615a1SAlex Chiang 		snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot));
982f46753c5SAlex Chiang 		pci_hp_register(tmp_slot->hotplug_slot,
983a32615a1SAlex Chiang 			pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name);
9841da177e4SLinus Torvalds 	}
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 	print_ebda_hpc ();
9871da177e4SLinus Torvalds 	print_ibm_slot ();
9881da177e4SLinus Torvalds 	return 0;
9891da177e4SLinus Torvalds 
9901da177e4SLinus Torvalds error:
9911da177e4SLinus Torvalds 	kfree (hp_slot_ptr->private);
9921da177e4SLinus Torvalds error_no_slot:
9931da177e4SLinus Torvalds 	kfree (hp_slot_ptr->info);
9941da177e4SLinus Torvalds error_no_hp_info:
9951da177e4SLinus Torvalds 	kfree (hp_slot_ptr);
9961da177e4SLinus Torvalds error_no_hp_slot:
9971da177e4SLinus Torvalds 	free_ebda_hpc (hpc_ptr);
9981da177e4SLinus Torvalds error_no_hpc:
9991da177e4SLinus Torvalds 	iounmap (io_mem);
10001da177e4SLinus Torvalds 	return rc;
10011da177e4SLinus Torvalds }
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds /*
10041da177e4SLinus Torvalds  * map info (bus, devfun, start addr, end addr..) of i/o, memory,
10051da177e4SLinus Torvalds  * pfm from the physical addr to a list of resource.
10061da177e4SLinus Torvalds  */
10071da177e4SLinus Torvalds static int __init ebda_rsrc_rsrc (void)
10081da177e4SLinus Torvalds {
10091da177e4SLinus Torvalds 	u16 addr;
10101da177e4SLinus Torvalds 	short rsrc;
10111da177e4SLinus Torvalds 	u8 type, rsrc_type;
10121da177e4SLinus Torvalds 	struct ebda_pci_rsrc *rsrc_ptr;
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	addr = rsrc_list_ptr->phys_addr;
10151da177e4SLinus Torvalds 	debug ("now entering rsrc land\n");
10161da177e4SLinus Torvalds 	debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr);
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 	for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) {
10191da177e4SLinus Torvalds 		type = readb (io_mem + addr);
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds 		addr += 1;
10221da177e4SLinus Torvalds 		rsrc_type = type & EBDA_RSRC_TYPE_MASK;
10231da177e4SLinus Torvalds 
10241da177e4SLinus Torvalds 		if (rsrc_type == EBDA_IO_RSRC_TYPE) {
10251da177e4SLinus Torvalds 			rsrc_ptr = alloc_ebda_pci_rsrc ();
10261da177e4SLinus Torvalds 			if (!rsrc_ptr) {
10271da177e4SLinus Torvalds 				iounmap (io_mem);
10281da177e4SLinus Torvalds 				return -ENOMEM;
10291da177e4SLinus Torvalds 			}
10301da177e4SLinus Torvalds 			rsrc_ptr->rsrc_type = type;
10311da177e4SLinus Torvalds 
10321da177e4SLinus Torvalds 			rsrc_ptr->bus_num = readb (io_mem + addr);
10331da177e4SLinus Torvalds 			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
10341da177e4SLinus Torvalds 			rsrc_ptr->start_addr = readw (io_mem + addr + 2);
10351da177e4SLinus Torvalds 			rsrc_ptr->end_addr = readw (io_mem + addr + 4);
10361da177e4SLinus Torvalds 			addr += 6;
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds 			debug ("rsrc from io type ----\n");
10391da177e4SLinus Torvalds 			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
10401da177e4SLinus Torvalds 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
10431da177e4SLinus Torvalds 		}
10441da177e4SLinus Torvalds 
10451da177e4SLinus Torvalds 		if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) {
10461da177e4SLinus Torvalds 			rsrc_ptr = alloc_ebda_pci_rsrc ();
10471da177e4SLinus Torvalds 			if (!rsrc_ptr ) {
10481da177e4SLinus Torvalds 				iounmap (io_mem);
10491da177e4SLinus Torvalds 				return -ENOMEM;
10501da177e4SLinus Torvalds 			}
10511da177e4SLinus Torvalds 			rsrc_ptr->rsrc_type = type;
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds 			rsrc_ptr->bus_num = readb (io_mem + addr);
10541da177e4SLinus Torvalds 			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
10551da177e4SLinus Torvalds 			rsrc_ptr->start_addr = readl (io_mem + addr + 2);
10561da177e4SLinus Torvalds 			rsrc_ptr->end_addr = readl (io_mem + addr + 6);
10571da177e4SLinus Torvalds 			addr += 10;
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 			debug ("rsrc from mem or pfm ---\n");
10601da177e4SLinus Torvalds 			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
10611da177e4SLinus Torvalds 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
10641da177e4SLinus Torvalds 		}
10651da177e4SLinus Torvalds 	}
10661da177e4SLinus Torvalds 	kfree (rsrc_list_ptr);
10671da177e4SLinus Torvalds 	rsrc_list_ptr = NULL;
10681da177e4SLinus Torvalds 	print_ebda_pci_rsrc ();
10691da177e4SLinus Torvalds 	return 0;
10701da177e4SLinus Torvalds }
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds u16 ibmphp_get_total_controllers (void)
10731da177e4SLinus Torvalds {
10741da177e4SLinus Torvalds 	return hpc_list_ptr->num_ctlrs;
10751da177e4SLinus Torvalds }
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num)
10781da177e4SLinus Torvalds {
10791da177e4SLinus Torvalds 	struct slot *slot;
10801da177e4SLinus Torvalds 
1081a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(slot, &ibmphp_slot_head, ibm_slot_list) {
10821da177e4SLinus Torvalds 		if (slot->number == physical_num)
10831da177e4SLinus Torvalds 			return slot;
10841da177e4SLinus Torvalds 	}
10851da177e4SLinus Torvalds 	return NULL;
10861da177e4SLinus Torvalds }
10871da177e4SLinus Torvalds 
10881da177e4SLinus Torvalds /* To find:
10891da177e4SLinus Torvalds  *	- the smallest slot number
10901da177e4SLinus Torvalds  *	- the largest slot number
10911da177e4SLinus Torvalds  *	- the total number of the slots based on each bus
10921da177e4SLinus Torvalds  *	  (if only one slot per bus slot_min = slot_max )
10931da177e4SLinus Torvalds  */
10941da177e4SLinus Torvalds struct bus_info *ibmphp_find_same_bus_num (u32 num)
10951da177e4SLinus Torvalds {
10961da177e4SLinus Torvalds 	struct bus_info *ptr;
10971da177e4SLinus Torvalds 
1098a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
10991da177e4SLinus Torvalds 		if (ptr->busno == num)
11001da177e4SLinus Torvalds 			 return ptr;
11011da177e4SLinus Torvalds 	}
11021da177e4SLinus Torvalds 	return NULL;
11031da177e4SLinus Torvalds }
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds /*  Finding relative bus number, in order to map corresponding
11061da177e4SLinus Torvalds  *  bus register
11071da177e4SLinus Torvalds  */
11081da177e4SLinus Torvalds int ibmphp_get_bus_index (u8 num)
11091da177e4SLinus Torvalds {
11101da177e4SLinus Torvalds 	struct bus_info *ptr;
11111da177e4SLinus Torvalds 
1112a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
11131da177e4SLinus Torvalds 		if (ptr->busno == num)
11141da177e4SLinus Torvalds 			return ptr->index;
11151da177e4SLinus Torvalds 	}
11161da177e4SLinus Torvalds 	return -ENODEV;
11171da177e4SLinus Torvalds }
11181da177e4SLinus Torvalds 
11191da177e4SLinus Torvalds void ibmphp_free_bus_info_queue (void)
11201da177e4SLinus Torvalds {
11211da177e4SLinus Torvalds 	struct bus_info *bus_info;
11221da177e4SLinus Torvalds 	struct list_head *list;
11231da177e4SLinus Torvalds 	struct list_head *next;
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 	list_for_each_safe (list, next, &bus_info_head ) {
11261da177e4SLinus Torvalds 		bus_info = list_entry (list, struct bus_info, bus_info_list);
11271da177e4SLinus Torvalds 		kfree (bus_info);
11281da177e4SLinus Torvalds 	}
11291da177e4SLinus Torvalds }
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds void ibmphp_free_ebda_hpc_queue (void)
11321da177e4SLinus Torvalds {
11331da177e4SLinus Torvalds 	struct controller *controller = NULL;
11341da177e4SLinus Torvalds 	struct list_head *list;
11351da177e4SLinus Torvalds 	struct list_head *next;
11361da177e4SLinus Torvalds 	int pci_flag = 0;
11371da177e4SLinus Torvalds 
11381da177e4SLinus Torvalds 	list_for_each_safe (list, next, &ebda_hpc_head) {
11391da177e4SLinus Torvalds 		controller = list_entry (list, struct controller, ebda_hpc_list);
11401da177e4SLinus Torvalds 		if (controller->ctlr_type == 0)
11411da177e4SLinus Torvalds 			release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
11421da177e4SLinus Torvalds 		else if ((controller->ctlr_type == 1) && (!pci_flag)) {
11431da177e4SLinus Torvalds 			++pci_flag;
11441da177e4SLinus Torvalds 			pci_unregister_driver (&ibmphp_driver);
11451da177e4SLinus Torvalds 		}
11461da177e4SLinus Torvalds 		free_ebda_hpc (controller);
11471da177e4SLinus Torvalds 	}
11481da177e4SLinus Torvalds }
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds void ibmphp_free_ebda_pci_rsrc_queue (void)
11511da177e4SLinus Torvalds {
11521da177e4SLinus Torvalds 	struct ebda_pci_rsrc *resource;
11531da177e4SLinus Torvalds 	struct list_head *list;
11541da177e4SLinus Torvalds 	struct list_head *next;
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds 	list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) {
11571da177e4SLinus Torvalds 		resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
11581da177e4SLinus Torvalds 		kfree (resource);
11591da177e4SLinus Torvalds 		resource = NULL;
11601da177e4SLinus Torvalds 	}
11611da177e4SLinus Torvalds }
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds static struct pci_device_id id_table[] = {
11641da177e4SLinus Torvalds 	{
11651da177e4SLinus Torvalds 		.vendor		= PCI_VENDOR_ID_IBM,
11661da177e4SLinus Torvalds 		.device		= HPC_DEVICE_ID,
11671da177e4SLinus Torvalds 		.subvendor	= PCI_VENDOR_ID_IBM,
11681da177e4SLinus Torvalds 		.subdevice	= HPC_SUBSYSTEM_ID,
11691da177e4SLinus Torvalds 		.class		= ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
11701da177e4SLinus Torvalds 	}, {}
11711da177e4SLinus Torvalds };
11721da177e4SLinus Torvalds 
11731da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, id_table);
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *);
11761da177e4SLinus Torvalds static struct pci_driver ibmphp_driver = {
11771da177e4SLinus Torvalds 	.name		= "ibmphp",
11781da177e4SLinus Torvalds 	.id_table	= id_table,
11791da177e4SLinus Torvalds 	.probe		= ibmphp_probe,
11801da177e4SLinus Torvalds };
11811da177e4SLinus Torvalds 
11821da177e4SLinus Torvalds int ibmphp_register_pci (void)
11831da177e4SLinus Torvalds {
11841da177e4SLinus Torvalds 	struct controller *ctrl;
11851da177e4SLinus Torvalds 	int rc = 0;
11861da177e4SLinus Torvalds 
1187a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
11881da177e4SLinus Torvalds 		if (ctrl->ctlr_type == 1) {
11891da177e4SLinus Torvalds 			rc = pci_register_driver(&ibmphp_driver);
11901da177e4SLinus Torvalds 			break;
11911da177e4SLinus Torvalds 		}
11921da177e4SLinus Torvalds 	}
11931da177e4SLinus Torvalds 	return rc;
11941da177e4SLinus Torvalds }
11951da177e4SLinus Torvalds static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids)
11961da177e4SLinus Torvalds {
11971da177e4SLinus Torvalds 	struct controller *ctrl;
11981da177e4SLinus Torvalds 
11991da177e4SLinus Torvalds 	debug ("inside ibmphp_probe\n");
12001da177e4SLinus Torvalds 
1201a8d2dbd3Sakpm@linux-foundation.org 	list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
12021da177e4SLinus Torvalds 		if (ctrl->ctlr_type == 1) {
12031da177e4SLinus Torvalds 			if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
12041da177e4SLinus Torvalds 				ctrl->ctrl_dev = dev;
12051da177e4SLinus Torvalds 				debug ("found device!!!\n");
12061da177e4SLinus Torvalds 				debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
12071da177e4SLinus Torvalds 				return 0;
12081da177e4SLinus Torvalds 			}
12091da177e4SLinus Torvalds 		}
12101da177e4SLinus Torvalds 	}
12111da177e4SLinus Torvalds 	return -ENODEV;
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds 
1214