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 	struct list_head *ptr1;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	list_for_each (ptr1, &bus_info_head) {
1291da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct bus_info, bus_info_list);
1301da177e4SLinus Torvalds 		debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min);
1311da177e4SLinus Torvalds 		debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max);
1321da177e4SLinus Torvalds 		debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count);
1331da177e4SLinus Torvalds 		debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno);
1341da177e4SLinus Torvalds 		debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed);
1351da177e4SLinus Torvalds 		debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id);
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 		debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv);
1381da177e4SLinus Torvalds 		debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv);
1391da177e4SLinus Torvalds 		debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix);
1401da177e4SLinus Torvalds 		debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix);
1411da177e4SLinus Torvalds 		debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix);
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	}
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds static void print_lo_info (void)
1471da177e4SLinus Torvalds {
1481da177e4SLinus Torvalds 	struct rio_detail *ptr;
1491da177e4SLinus Torvalds 	struct list_head *ptr1;
1501da177e4SLinus Torvalds 	debug ("print_lo_info ----\n");
1511da177e4SLinus Torvalds 	list_for_each (ptr1, &rio_lo_head) {
1521da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
1531da177e4SLinus Torvalds 		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
1541da177e4SLinus Torvalds 		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
1551da177e4SLinus Torvalds 		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
1561da177e4SLinus Torvalds 		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
1571da177e4SLinus Torvalds 		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
1581da177e4SLinus Torvalds 		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	}
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds static void print_vg_info (void)
1641da177e4SLinus Torvalds {
1651da177e4SLinus Torvalds 	struct rio_detail *ptr;
1661da177e4SLinus Torvalds 	struct list_head *ptr1;
1671da177e4SLinus Torvalds 	debug ("%s ---\n", __FUNCTION__);
1681da177e4SLinus Torvalds 	list_for_each (ptr1, &rio_vg_head) {
1691da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
1701da177e4SLinus Torvalds 		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
1711da177e4SLinus Torvalds 		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
1721da177e4SLinus Torvalds 		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
1731da177e4SLinus Torvalds 		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
1741da177e4SLinus Torvalds 		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
1751da177e4SLinus Torvalds 		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	}
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds static void __init print_ebda_pci_rsrc (void)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	struct ebda_pci_rsrc *ptr;
1831da177e4SLinus Torvalds 	struct list_head *ptr1;
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) {
1861da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
1871da177e4SLinus Torvalds 		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
1881da177e4SLinus Torvalds 			__FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr);
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds }
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds static void __init print_ibm_slot (void)
1931da177e4SLinus Torvalds {
1941da177e4SLinus Torvalds 	struct slot *ptr;
1951da177e4SLinus Torvalds 	struct list_head *ptr1;
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	list_for_each (ptr1, &ibmphp_slot_head) {
1981da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct slot, ibm_slot_list);
1991da177e4SLinus Torvalds 		debug ("%s - slot_number: %x\n", __FUNCTION__, ptr->number);
2001da177e4SLinus Torvalds 	}
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds static void __init print_opt_vg (void)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds 	struct opt_rio *ptr;
2061da177e4SLinus Torvalds 	struct list_head *ptr1;
2071da177e4SLinus Torvalds 	debug ("%s ---\n", __FUNCTION__);
2081da177e4SLinus Torvalds 	list_for_each (ptr1, &opt_vg_head) {
2091da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
2101da177e4SLinus Torvalds 		debug ("%s - rio_type %x\n", __FUNCTION__, ptr->rio_type);
2111da177e4SLinus Torvalds 		debug ("%s - chassis_num: %x\n", __FUNCTION__, ptr->chassis_num);
2121da177e4SLinus Torvalds 		debug ("%s - first_slot_num: %x\n", __FUNCTION__, ptr->first_slot_num);
2131da177e4SLinus Torvalds 		debug ("%s - middle_num: %x\n", __FUNCTION__, ptr->middle_num);
2141da177e4SLinus Torvalds 	}
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds static void __init print_ebda_hpc (void)
2181da177e4SLinus Torvalds {
2191da177e4SLinus Torvalds 	struct controller *hpc_ptr;
2201da177e4SLinus Torvalds 	struct list_head *ptr1;
2211da177e4SLinus Torvalds 	u16 index;
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	list_for_each (ptr1, &ebda_hpc_head) {
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 		hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list);
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->slot_count; index++) {
2281da177e4SLinus Torvalds 			debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num);
2291da177e4SLinus Torvalds 			debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num);
2301da177e4SLinus Torvalds 			debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index);
2311da177e4SLinus Torvalds 			debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap);
2321da177e4SLinus Torvalds 		}
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->bus_count; index++) {
2351da177e4SLinus Torvalds 			debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num);
2361da177e4SLinus Torvalds 		}
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 		debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type);
2391da177e4SLinus Torvalds 		switch (hpc_ptr->ctlr_type) {
2401da177e4SLinus Torvalds 		case 1:
2411da177e4SLinus Torvalds 			debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus);
2421da177e4SLinus Torvalds 			debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun);
2431da177e4SLinus Torvalds 			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
2441da177e4SLinus Torvalds 			break;
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 		case 0:
2471da177e4SLinus Torvalds 			debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start);
2481da177e4SLinus Torvalds 			debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end);
2491da177e4SLinus Torvalds 			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
2501da177e4SLinus Torvalds 			break;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 		case 2:
2531da177e4SLinus Torvalds 		case 4:
2541da177e4SLinus Torvalds 			debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
2551da177e4SLinus Torvalds 			debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
2561da177e4SLinus Torvalds 			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
2571da177e4SLinus Torvalds 			break;
2581da177e4SLinus Torvalds 		}
2591da177e4SLinus Torvalds 	}
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds int __init ibmphp_access_ebda (void)
2631da177e4SLinus Torvalds {
2641da177e4SLinus Torvalds 	u8 format, num_ctlrs, rio_complete, hs_complete;
2651da177e4SLinus Torvalds 	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
2661da177e4SLinus Torvalds 	int rc = 0;
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	rio_complete = 0;
2701da177e4SLinus Torvalds 	hs_complete = 0;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	io_mem = ioremap ((0x40 << 4) + 0x0e, 2);
2731da177e4SLinus Torvalds 	if (!io_mem )
2741da177e4SLinus Torvalds 		return -ENOMEM;
2751da177e4SLinus Torvalds 	ebda_seg = readw (io_mem);
2761da177e4SLinus Torvalds 	iounmap (io_mem);
2771da177e4SLinus Torvalds 	debug ("returned ebda segment: %x\n", ebda_seg);
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	io_mem = ioremap (ebda_seg<<4, 65000);
2801da177e4SLinus Torvalds 	if (!io_mem )
2811da177e4SLinus Torvalds 		return -ENOMEM;
2821da177e4SLinus Torvalds 	next_offset = 0x180;
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	for (;;) {
2851da177e4SLinus Torvalds 		offset = next_offset;
2861da177e4SLinus Torvalds 		next_offset = readw (io_mem + offset);	/* offset of next blk */
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 		offset += 2;
2891da177e4SLinus Torvalds 		if (next_offset == 0)	/* 0 indicate it's last blk */
2901da177e4SLinus Torvalds 			break;
2911da177e4SLinus Torvalds 		blk_id = readw (io_mem + offset);	/* this blk id */
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 		offset += 2;
2941da177e4SLinus Torvalds 		/* check if it is hot swap block or rio block */
2951da177e4SLinus Torvalds 		if (blk_id != 0x4853 && blk_id != 0x4752)
2961da177e4SLinus Torvalds 			continue;
2971da177e4SLinus Torvalds 		/* found hs table */
2981da177e4SLinus Torvalds 		if (blk_id == 0x4853) {
2991da177e4SLinus Torvalds 			debug ("now enter hot swap block---\n");
3001da177e4SLinus Torvalds 			debug ("hot blk id: %x\n", blk_id);
3011da177e4SLinus Torvalds 			format = readb (io_mem + offset);
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 			offset += 1;
3041da177e4SLinus Torvalds 			if (format != 4)
3051da177e4SLinus Torvalds 				goto error_nodev;
3061da177e4SLinus Torvalds 			debug ("hot blk format: %x\n", format);
3071da177e4SLinus Torvalds 			/* hot swap sub blk */
3081da177e4SLinus Torvalds 			base = offset;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 			sub_addr = base;
3111da177e4SLinus Torvalds 			re = readw (io_mem + sub_addr);	/* next sub blk */
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 			sub_addr += 2;
3141da177e4SLinus Torvalds 			rc_id = readw (io_mem + sub_addr); 	/* sub blk id */
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds 			sub_addr += 2;
3171da177e4SLinus Torvalds 			if (rc_id != 0x5243)
3181da177e4SLinus Torvalds 				goto error_nodev;
3191da177e4SLinus Torvalds 			/* rc sub blk signature  */
3201da177e4SLinus Torvalds 			num_ctlrs = readb (io_mem + sub_addr);
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 			sub_addr += 1;
3231da177e4SLinus Torvalds 			hpc_list_ptr = alloc_ebda_hpc_list ();
3241da177e4SLinus Torvalds 			if (!hpc_list_ptr) {
3251da177e4SLinus Torvalds 				rc = -ENOMEM;
3261da177e4SLinus Torvalds 				goto out;
3271da177e4SLinus Torvalds 			}
3281da177e4SLinus Torvalds 			hpc_list_ptr->format = format;
3291da177e4SLinus Torvalds 			hpc_list_ptr->num_ctlrs = num_ctlrs;
3301da177e4SLinus Torvalds 			hpc_list_ptr->phys_addr = sub_addr;	/*  offset of RSRC_CONTROLLER blk */
3311da177e4SLinus Torvalds 			debug ("info about hpc descriptor---\n");
3321da177e4SLinus Torvalds 			debug ("hot blk format: %x\n", format);
3331da177e4SLinus Torvalds 			debug ("num of controller: %x\n", num_ctlrs);
3341da177e4SLinus Torvalds 			debug ("offset of hpc data structure enteries: %x\n ", sub_addr);
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 			sub_addr = base + re;	/* re sub blk */
3371da177e4SLinus Torvalds 			/* FIXME: rc is never used/checked */
3381da177e4SLinus Torvalds 			rc = readw (io_mem + sub_addr);	/* next sub blk */
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 			sub_addr += 2;
3411da177e4SLinus Torvalds 			re_id = readw (io_mem + sub_addr);	/* sub blk id */
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 			sub_addr += 2;
3441da177e4SLinus Torvalds 			if (re_id != 0x5245)
3451da177e4SLinus Torvalds 				goto error_nodev;
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 			/* signature of re */
3481da177e4SLinus Torvalds 			num_entries = readw (io_mem + sub_addr);
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 			sub_addr += 2;	/* offset of RSRC_ENTRIES blk */
3511da177e4SLinus Torvalds 			rsrc_list_ptr = alloc_ebda_rsrc_list ();
3521da177e4SLinus Torvalds 			if (!rsrc_list_ptr ) {
3531da177e4SLinus Torvalds 				rc = -ENOMEM;
3541da177e4SLinus Torvalds 				goto out;
3551da177e4SLinus Torvalds 			}
3561da177e4SLinus Torvalds 			rsrc_list_ptr->format = format;
3571da177e4SLinus Torvalds 			rsrc_list_ptr->num_entries = num_entries;
3581da177e4SLinus Torvalds 			rsrc_list_ptr->phys_addr = sub_addr;
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 			debug ("info about rsrc descriptor---\n");
3611da177e4SLinus Torvalds 			debug ("format: %x\n", format);
3621da177e4SLinus Torvalds 			debug ("num of rsrc: %x\n", num_entries);
3631da177e4SLinus Torvalds 			debug ("offset of rsrc data structure enteries: %x\n ", sub_addr);
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 			hs_complete = 1;
3661da177e4SLinus Torvalds 		} else {
3671da177e4SLinus Torvalds 		/* found rio table, blk_id == 0x4752 */
3681da177e4SLinus Torvalds 			debug ("now enter io table ---\n");
3691da177e4SLinus Torvalds 			debug ("rio blk id: %x\n", blk_id);
3701da177e4SLinus Torvalds 
371f5afe806SEric Sesterhenn 			rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL);
3721da177e4SLinus Torvalds 			if (!rio_table_ptr)
3731da177e4SLinus Torvalds 				return -ENOMEM;
3741da177e4SLinus Torvalds 			rio_table_ptr->ver_num = readb (io_mem + offset);
3751da177e4SLinus Torvalds 			rio_table_ptr->scal_count = readb (io_mem + offset + 1);
3761da177e4SLinus Torvalds 			rio_table_ptr->riodev_count = readb (io_mem + offset + 2);
3771da177e4SLinus Torvalds 			rio_table_ptr->offset = offset +3 ;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 			debug("info about rio table hdr ---\n");
3801da177e4SLinus Torvalds 			debug("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ",
3811da177e4SLinus Torvalds 				rio_table_ptr->ver_num, rio_table_ptr->scal_count,
3821da177e4SLinus Torvalds 				rio_table_ptr->riodev_count, rio_table_ptr->offset);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 			rio_complete = 1;
3851da177e4SLinus Torvalds 		}
3861da177e4SLinus Torvalds 	}
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	if (!hs_complete && !rio_complete)
3891da177e4SLinus Torvalds 		goto error_nodev;
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	if (rio_table_ptr) {
3921da177e4SLinus Torvalds 		if (rio_complete && rio_table_ptr->ver_num == 3) {
3931da177e4SLinus Torvalds 			rc = ebda_rio_table ();
3941da177e4SLinus Torvalds 			if (rc)
3951da177e4SLinus Torvalds 				goto out;
3961da177e4SLinus Torvalds 		}
3971da177e4SLinus Torvalds 	}
3981da177e4SLinus Torvalds 	rc = ebda_rsrc_controller ();
3991da177e4SLinus Torvalds 	if (rc)
4001da177e4SLinus Torvalds 		goto out;
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 	rc = ebda_rsrc_rsrc ();
4031da177e4SLinus Torvalds 	goto out;
4041da177e4SLinus Torvalds error_nodev:
4051da177e4SLinus Torvalds 	rc = -ENODEV;
4061da177e4SLinus Torvalds out:
4071da177e4SLinus Torvalds 	iounmap (io_mem);
4081da177e4SLinus Torvalds 	return rc;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds /*
4121da177e4SLinus Torvalds  * map info of scalability details and rio details from physical address
4131da177e4SLinus Torvalds  */
4141da177e4SLinus Torvalds static int __init ebda_rio_table (void)
4151da177e4SLinus Torvalds {
4161da177e4SLinus Torvalds 	u16 offset;
4171da177e4SLinus Torvalds 	u8 i;
4181da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr;
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	offset = rio_table_ptr->offset;
4211da177e4SLinus Torvalds 	offset += 12 * rio_table_ptr->scal_count;
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 	// we do concern about rio details
4241da177e4SLinus Torvalds 	for (i = 0; i < rio_table_ptr->riodev_count; i++) {
425f5afe806SEric Sesterhenn 		rio_detail_ptr = kzalloc(sizeof(struct rio_detail), GFP_KERNEL);
4261da177e4SLinus Torvalds 		if (!rio_detail_ptr)
4271da177e4SLinus Torvalds 			return -ENOMEM;
4281da177e4SLinus Torvalds 		rio_detail_ptr->rio_node_id = readb (io_mem + offset);
4291da177e4SLinus Torvalds 		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
4301da177e4SLinus Torvalds 		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
4311da177e4SLinus Torvalds 		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
4321da177e4SLinus Torvalds 		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
4331da177e4SLinus Torvalds 		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
4341da177e4SLinus Torvalds 		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
4351da177e4SLinus Torvalds 		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
4361da177e4SLinus Torvalds 		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
4371da177e4SLinus Torvalds 		rio_detail_ptr->status = readb (io_mem + offset + 12);
4381da177e4SLinus Torvalds 		rio_detail_ptr->wpindex = readb (io_mem + offset + 13);
4391da177e4SLinus Torvalds 		rio_detail_ptr->chassis_num = readb (io_mem + offset + 14);
4401da177e4SLinus 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);
4411da177e4SLinus Torvalds 		//create linked list of chassis
4421da177e4SLinus Torvalds 		if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5)
4431da177e4SLinus Torvalds 			list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head);
4441da177e4SLinus Torvalds 		//create linked list of expansion box
4451da177e4SLinus Torvalds 		else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7)
4461da177e4SLinus Torvalds 			list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head);
4471da177e4SLinus Torvalds 		else
4481da177e4SLinus Torvalds 			// not in my concern
4491da177e4SLinus Torvalds 			kfree (rio_detail_ptr);
4501da177e4SLinus Torvalds 		offset += 15;
4511da177e4SLinus Torvalds 	}
4521da177e4SLinus Torvalds 	print_lo_info ();
4531da177e4SLinus Torvalds 	print_vg_info ();
4541da177e4SLinus Torvalds 	return 0;
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds /*
4581da177e4SLinus Torvalds  * reorganizing linked list of chassis
4591da177e4SLinus Torvalds  */
4601da177e4SLinus Torvalds static struct opt_rio *search_opt_vg (u8 chassis_num)
4611da177e4SLinus Torvalds {
4621da177e4SLinus Torvalds 	struct opt_rio *ptr;
4631da177e4SLinus Torvalds 	struct list_head *ptr1;
4641da177e4SLinus Torvalds 	list_for_each (ptr1, &opt_vg_head) {
4651da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
4661da177e4SLinus Torvalds 		if (ptr->chassis_num == chassis_num)
4671da177e4SLinus Torvalds 			return ptr;
4681da177e4SLinus Torvalds 	}
4691da177e4SLinus Torvalds 	return NULL;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds static int __init combine_wpg_for_chassis (void)
4731da177e4SLinus Torvalds {
4741da177e4SLinus Torvalds 	struct opt_rio *opt_rio_ptr = NULL;
4751da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr = NULL;
4761da177e4SLinus Torvalds 	struct list_head *list_head_ptr = NULL;
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds 	list_for_each (list_head_ptr, &rio_vg_head) {
4791da177e4SLinus Torvalds 		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
4801da177e4SLinus Torvalds 		opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num);
4811da177e4SLinus Torvalds 		if (!opt_rio_ptr) {
482f5afe806SEric Sesterhenn 			opt_rio_ptr = kzalloc(sizeof(struct opt_rio), GFP_KERNEL);
4831da177e4SLinus Torvalds 			if (!opt_rio_ptr)
4841da177e4SLinus Torvalds 				return -ENOMEM;
4851da177e4SLinus Torvalds 			opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
4861da177e4SLinus Torvalds 			opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
4871da177e4SLinus Torvalds 			opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
4881da177e4SLinus Torvalds 			opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
4891da177e4SLinus Torvalds 			list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head);
4901da177e4SLinus Torvalds 		} else {
4911da177e4SLinus Torvalds 			opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
4921da177e4SLinus Torvalds 			opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
4931da177e4SLinus Torvalds 		}
4941da177e4SLinus Torvalds 	}
4951da177e4SLinus Torvalds 	print_opt_vg ();
4961da177e4SLinus Torvalds 	return 0;
4971da177e4SLinus Torvalds }
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds /*
5001da177e4SLinus Torvalds  * reorgnizing linked list of expansion box
5011da177e4SLinus Torvalds  */
5021da177e4SLinus Torvalds static struct opt_rio_lo *search_opt_lo (u8 chassis_num)
5031da177e4SLinus Torvalds {
5041da177e4SLinus Torvalds 	struct opt_rio_lo *ptr;
5051da177e4SLinus Torvalds 	struct list_head *ptr1;
5061da177e4SLinus Torvalds 	list_for_each (ptr1, &opt_lo_head) {
5071da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list);
5081da177e4SLinus Torvalds 		if (ptr->chassis_num == chassis_num)
5091da177e4SLinus Torvalds 			return ptr;
5101da177e4SLinus Torvalds 	}
5111da177e4SLinus Torvalds 	return NULL;
5121da177e4SLinus Torvalds }
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds static int combine_wpg_for_expansion (void)
5151da177e4SLinus Torvalds {
5161da177e4SLinus Torvalds 	struct opt_rio_lo *opt_rio_lo_ptr = NULL;
5171da177e4SLinus Torvalds 	struct rio_detail *rio_detail_ptr = NULL;
5181da177e4SLinus Torvalds 	struct list_head *list_head_ptr = NULL;
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 	list_for_each (list_head_ptr, &rio_lo_head) {
5211da177e4SLinus Torvalds 		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
5221da177e4SLinus Torvalds 		opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num);
5231da177e4SLinus Torvalds 		if (!opt_rio_lo_ptr) {
524f5afe806SEric Sesterhenn 			opt_rio_lo_ptr = kzalloc(sizeof(struct opt_rio_lo), GFP_KERNEL);
5251da177e4SLinus Torvalds 			if (!opt_rio_lo_ptr)
5261da177e4SLinus Torvalds 				return -ENOMEM;
5271da177e4SLinus Torvalds 			opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
5281da177e4SLinus Torvalds 			opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
5291da177e4SLinus Torvalds 			opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
5301da177e4SLinus Torvalds 			opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
5311da177e4SLinus Torvalds 			opt_rio_lo_ptr->pack_count = 1;
5321da177e4SLinus Torvalds 
5331da177e4SLinus Torvalds 			list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
5341da177e4SLinus Torvalds 		} else {
5351da177e4SLinus Torvalds 			opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
5361da177e4SLinus Torvalds 			opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
5371da177e4SLinus Torvalds 			opt_rio_lo_ptr->pack_count = 2;
5381da177e4SLinus Torvalds 		}
5391da177e4SLinus Torvalds 	}
5401da177e4SLinus Torvalds 	return 0;
5411da177e4SLinus Torvalds }
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds /* Since we don't know the max slot number per each chassis, hence go
5451da177e4SLinus Torvalds  * through the list of all chassis to find out the range
5461da177e4SLinus Torvalds  * Arguments: slot_num, 1st slot number of the chassis we think we are on,
5471da177e4SLinus Torvalds  * var (0 = chassis, 1 = expansion box)
5481da177e4SLinus Torvalds  */
5491da177e4SLinus Torvalds static int first_slot_num (u8 slot_num, u8 first_slot, u8 var)
5501da177e4SLinus Torvalds {
5511da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr = NULL;
5521da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr = NULL;
5531da177e4SLinus Torvalds 	struct list_head *ptr = NULL;
5541da177e4SLinus Torvalds 	int rc = 0;
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds 	if (!var) {
5571da177e4SLinus Torvalds 		list_for_each (ptr, &opt_vg_head) {
5581da177e4SLinus Torvalds 			opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
5591da177e4SLinus Torvalds 			if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) {
5601da177e4SLinus Torvalds 				rc = -ENODEV;
5611da177e4SLinus Torvalds 				break;
5621da177e4SLinus Torvalds 			}
5631da177e4SLinus Torvalds 		}
5641da177e4SLinus Torvalds 	} else {
5651da177e4SLinus Torvalds 		list_for_each (ptr, &opt_lo_head) {
5661da177e4SLinus Torvalds 			opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
5671da177e4SLinus Torvalds 			if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
5681da177e4SLinus Torvalds 				rc = -ENODEV;
5691da177e4SLinus Torvalds 				break;
5701da177e4SLinus Torvalds 			}
5711da177e4SLinus Torvalds 		}
5721da177e4SLinus Torvalds 	}
5731da177e4SLinus Torvalds 	return rc;
5741da177e4SLinus Torvalds }
5751da177e4SLinus Torvalds 
5761da177e4SLinus Torvalds static struct opt_rio_lo * find_rxe_num (u8 slot_num)
5771da177e4SLinus Torvalds {
5781da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr;
5791da177e4SLinus Torvalds 	struct list_head *ptr;
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds 	list_for_each (ptr, &opt_lo_head) {
5821da177e4SLinus Torvalds 		opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
5831da177e4SLinus Torvalds 		//check to see if this slot_num belongs to expansion box
5841da177e4SLinus Torvalds 		if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1)))
5851da177e4SLinus Torvalds 			return opt_lo_ptr;
5861da177e4SLinus Torvalds 	}
5871da177e4SLinus Torvalds 	return NULL;
5881da177e4SLinus Torvalds }
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds static struct opt_rio * find_chassis_num (u8 slot_num)
5911da177e4SLinus Torvalds {
5921da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr;
5931da177e4SLinus Torvalds 	struct list_head *ptr;
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds 	list_for_each (ptr, &opt_vg_head) {
5961da177e4SLinus Torvalds 		opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
5971da177e4SLinus Torvalds 		//check to see if this slot_num belongs to chassis
5981da177e4SLinus Torvalds 		if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0)))
5991da177e4SLinus Torvalds 			return opt_vg_ptr;
6001da177e4SLinus Torvalds 	}
6011da177e4SLinus Torvalds 	return NULL;
6021da177e4SLinus Torvalds }
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds /* This routine will find out how many slots are in the chassis, so that
6051da177e4SLinus Torvalds  * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
6061da177e4SLinus Torvalds  */
6071da177e4SLinus Torvalds static u8 calculate_first_slot (u8 slot_num)
6081da177e4SLinus Torvalds {
6091da177e4SLinus Torvalds 	u8 first_slot = 1;
6101da177e4SLinus Torvalds 	struct list_head * list;
6111da177e4SLinus Torvalds 	struct slot * slot_cur;
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 	list_for_each (list, &ibmphp_slot_head) {
6141da177e4SLinus Torvalds 		slot_cur = list_entry (list, struct slot, ibm_slot_list);
6151da177e4SLinus Torvalds 		if (slot_cur->ctrl) {
6161da177e4SLinus Torvalds 			if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num))
6171da177e4SLinus Torvalds 				first_slot = slot_cur->ctrl->ending_slot_num;
6181da177e4SLinus Torvalds 		}
6191da177e4SLinus Torvalds 	}
6201da177e4SLinus Torvalds 	return first_slot + 1;
6211da177e4SLinus Torvalds 
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds static char *create_file_name (struct slot * slot_cur)
6241da177e4SLinus Torvalds {
6251da177e4SLinus Torvalds 	struct opt_rio *opt_vg_ptr = NULL;
6261da177e4SLinus Torvalds 	struct opt_rio_lo *opt_lo_ptr = NULL;
6271da177e4SLinus Torvalds 	static char str[30];
6281da177e4SLinus Torvalds 	int which = 0; /* rxe = 1, chassis = 0 */
6291da177e4SLinus Torvalds 	u8 number = 1; /* either chassis or rxe # */
6301da177e4SLinus Torvalds 	u8 first_slot = 1;
6311da177e4SLinus Torvalds 	u8 slot_num;
6321da177e4SLinus Torvalds 	u8 flag = 0;
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds 	if (!slot_cur) {
6351da177e4SLinus Torvalds 		err ("Structure passed is empty\n");
6361da177e4SLinus Torvalds 		return NULL;
6371da177e4SLinus Torvalds 	}
6381da177e4SLinus Torvalds 
6391da177e4SLinus Torvalds 	slot_num = slot_cur->number;
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 	memset (str, 0, sizeof(str));
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 	if (rio_table_ptr) {
6441da177e4SLinus Torvalds 		if (rio_table_ptr->ver_num == 3) {
6451da177e4SLinus Torvalds 			opt_vg_ptr = find_chassis_num (slot_num);
6461da177e4SLinus Torvalds 			opt_lo_ptr = find_rxe_num (slot_num);
6471da177e4SLinus Torvalds 		}
6481da177e4SLinus Torvalds 	}
6491da177e4SLinus Torvalds 	if (opt_vg_ptr) {
6501da177e4SLinus Torvalds 		if (opt_lo_ptr) {
6511da177e4SLinus Torvalds 			if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
6521da177e4SLinus Torvalds 				number = opt_lo_ptr->chassis_num;
6531da177e4SLinus Torvalds 				first_slot = opt_lo_ptr->first_slot_num;
6541da177e4SLinus Torvalds 				which = 1; /* it is RXE */
6551da177e4SLinus Torvalds 			} else {
6561da177e4SLinus Torvalds 				first_slot = opt_vg_ptr->first_slot_num;
6571da177e4SLinus Torvalds 				number = opt_vg_ptr->chassis_num;
6581da177e4SLinus Torvalds 				which = 0;
6591da177e4SLinus Torvalds 			}
6601da177e4SLinus Torvalds 		} else {
6611da177e4SLinus Torvalds 			first_slot = opt_vg_ptr->first_slot_num;
6621da177e4SLinus Torvalds 			number = opt_vg_ptr->chassis_num;
6631da177e4SLinus Torvalds 			which = 0;
6641da177e4SLinus Torvalds 		}
6651da177e4SLinus Torvalds 		++flag;
6661da177e4SLinus Torvalds 	} else if (opt_lo_ptr) {
6671da177e4SLinus Torvalds 		number = opt_lo_ptr->chassis_num;
6681da177e4SLinus Torvalds 		first_slot = opt_lo_ptr->first_slot_num;
6691da177e4SLinus Torvalds 		which = 1;
6701da177e4SLinus Torvalds 		++flag;
6711da177e4SLinus Torvalds 	} else if (rio_table_ptr) {
6721da177e4SLinus Torvalds 		if (rio_table_ptr->ver_num == 3) {
6731da177e4SLinus Torvalds 			/* if both NULL and we DO have correct RIO table in BIOS */
6741da177e4SLinus Torvalds 			return NULL;
6751da177e4SLinus Torvalds 		}
6761da177e4SLinus Torvalds 	}
6771da177e4SLinus Torvalds 	if (!flag) {
6781da177e4SLinus Torvalds 		if (slot_cur->ctrl->ctlr_type == 4) {
6791da177e4SLinus Torvalds 			first_slot = calculate_first_slot (slot_num);
6801da177e4SLinus Torvalds 			which = 1;
6811da177e4SLinus Torvalds 		} else {
6821da177e4SLinus Torvalds 			which = 0;
6831da177e4SLinus Torvalds 		}
6841da177e4SLinus Torvalds 	}
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	sprintf(str, "%s%dslot%d",
6871da177e4SLinus Torvalds 		which == 0 ? "chassis" : "rxe",
6881da177e4SLinus Torvalds 		number, slot_num - first_slot + 1);
6891da177e4SLinus Torvalds 	return str;
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds static int fillslotinfo(struct hotplug_slot *hotplug_slot)
6931da177e4SLinus Torvalds {
6941da177e4SLinus Torvalds 	struct slot *slot;
6951da177e4SLinus Torvalds 	int rc = 0;
6961da177e4SLinus Torvalds 
6971da177e4SLinus Torvalds 	if (!hotplug_slot || !hotplug_slot->private)
6981da177e4SLinus Torvalds 		return -EINVAL;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	slot = hotplug_slot->private;
7011da177e4SLinus Torvalds 	rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL);
7021da177e4SLinus Torvalds 	if (rc)
7031da177e4SLinus Torvalds 		return rc;
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 	// power - enabled:1  not:0
7061da177e4SLinus Torvalds 	hotplug_slot->info->power_status = SLOT_POWER(slot->status);
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 	// attention - off:0, on:1, blinking:2
7091da177e4SLinus Torvalds 	hotplug_slot->info->attention_status = SLOT_ATTN(slot->status, slot->ext_status);
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	// latch - open:1 closed:0
7121da177e4SLinus Torvalds 	hotplug_slot->info->latch_status = SLOT_LATCH(slot->status);
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	// pci board - present:1 not:0
7151da177e4SLinus Torvalds 	if (SLOT_PRESENT (slot->status))
7161da177e4SLinus Torvalds 		hotplug_slot->info->adapter_status = 1;
7171da177e4SLinus Torvalds 	else
7181da177e4SLinus Torvalds 		hotplug_slot->info->adapter_status = 0;
7191da177e4SLinus Torvalds /*
7201da177e4SLinus Torvalds 	if (slot->bus_on->supported_bus_mode
7211da177e4SLinus Torvalds 		&& (slot->bus_on->supported_speed == BUS_SPEED_66))
7221da177e4SLinus Torvalds 		hotplug_slot->info->max_bus_speed_status = BUS_SPEED_66PCIX;
7231da177e4SLinus Torvalds 	else
7241da177e4SLinus Torvalds 		hotplug_slot->info->max_bus_speed_status = slot->bus_on->supported_speed;
7251da177e4SLinus Torvalds */
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	return rc;
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds static void release_slot(struct hotplug_slot *hotplug_slot)
7311da177e4SLinus Torvalds {
7321da177e4SLinus Torvalds 	struct slot *slot;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	if (!hotplug_slot || !hotplug_slot->private)
7351da177e4SLinus Torvalds 		return;
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds 	slot = hotplug_slot->private;
7381da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->info);
7391da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->name);
7401da177e4SLinus Torvalds 	kfree(slot->hotplug_slot);
7411da177e4SLinus Torvalds 	slot->ctrl = NULL;
7421da177e4SLinus Torvalds 	slot->bus_on = NULL;
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds 	/* we don't want to actually remove the resources, since free_resources will do just that */
7451da177e4SLinus Torvalds 	ibmphp_unconfigure_card(&slot, -1);
7461da177e4SLinus Torvalds 
7471da177e4SLinus Torvalds 	kfree (slot);
7481da177e4SLinus Torvalds }
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds static struct pci_driver ibmphp_driver;
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds /*
7531da177e4SLinus Torvalds  * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
7541da177e4SLinus Torvalds  * each hpc from physical address to a list of hot plug controllers based on
7551da177e4SLinus Torvalds  * hpc descriptors.
7561da177e4SLinus Torvalds  */
7571da177e4SLinus Torvalds static int __init ebda_rsrc_controller (void)
7581da177e4SLinus Torvalds {
7591da177e4SLinus Torvalds 	u16 addr, addr_slot, addr_bus;
7601da177e4SLinus Torvalds 	u8 ctlr_id, temp, bus_index;
7611da177e4SLinus Torvalds 	u16 ctlr, slot, bus;
7621da177e4SLinus Torvalds 	u16 slot_num, bus_num, index;
7631da177e4SLinus Torvalds 	struct hotplug_slot *hp_slot_ptr;
7641da177e4SLinus Torvalds 	struct controller *hpc_ptr;
7651da177e4SLinus Torvalds 	struct ebda_hpc_bus *bus_ptr;
7661da177e4SLinus Torvalds 	struct ebda_hpc_slot *slot_ptr;
7671da177e4SLinus Torvalds 	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
7681da177e4SLinus Torvalds 	int rc;
7691da177e4SLinus Torvalds 	struct slot *tmp_slot;
7701da177e4SLinus Torvalds 	struct list_head *list;
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 	addr = hpc_list_ptr->phys_addr;
7731da177e4SLinus Torvalds 	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
7741da177e4SLinus Torvalds 		bus_index = 1;
7751da177e4SLinus Torvalds 		ctlr_id = readb (io_mem + addr);
7761da177e4SLinus Torvalds 		addr += 1;
7771da177e4SLinus Torvalds 		slot_num = readb (io_mem + addr);
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds 		addr += 1;
7801da177e4SLinus Torvalds 		addr_slot = addr;	/* offset of slot structure */
7811da177e4SLinus Torvalds 		addr += (slot_num * 4);
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds 		bus_num = readb (io_mem + addr);
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds 		addr += 1;
7861da177e4SLinus Torvalds 		addr_bus = addr;	/* offset of bus */
7871da177e4SLinus Torvalds 		addr += (bus_num * 9);	/* offset of ctlr_type */
7881da177e4SLinus Torvalds 		temp = readb (io_mem + addr);
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 		addr += 1;
7911da177e4SLinus Torvalds 		/* init hpc structure */
7921da177e4SLinus Torvalds 		hpc_ptr = alloc_ebda_hpc (slot_num, bus_num);
7931da177e4SLinus Torvalds 		if (!hpc_ptr ) {
7941da177e4SLinus Torvalds 			rc = -ENOMEM;
7951da177e4SLinus Torvalds 			goto error_no_hpc;
7961da177e4SLinus Torvalds 		}
7971da177e4SLinus Torvalds 		hpc_ptr->ctlr_id = ctlr_id;
7981da177e4SLinus Torvalds 		hpc_ptr->ctlr_relative_id = ctlr;
7991da177e4SLinus Torvalds 		hpc_ptr->slot_count = slot_num;
8001da177e4SLinus Torvalds 		hpc_ptr->bus_count = bus_num;
8011da177e4SLinus Torvalds 		debug ("now enter ctlr data struture ---\n");
8021da177e4SLinus Torvalds 		debug ("ctlr id: %x\n", ctlr_id);
8031da177e4SLinus Torvalds 		debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id);
8041da177e4SLinus Torvalds 		debug ("count of slots controlled by this ctlr: %x\n", slot_num);
8051da177e4SLinus Torvalds 		debug ("count of buses controlled by this ctlr: %x\n", bus_num);
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds 		/* init slot structure, fetch slot, bus, cap... */
8081da177e4SLinus Torvalds 		slot_ptr = hpc_ptr->slots;
8091da177e4SLinus Torvalds 		for (slot = 0; slot < slot_num; slot++) {
8101da177e4SLinus Torvalds 			slot_ptr->slot_num = readb (io_mem + addr_slot);
8111da177e4SLinus Torvalds 			slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num);
8121da177e4SLinus Torvalds 			slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num);
8131da177e4SLinus Torvalds 			slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num);
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 			// create bus_info lined list --- if only one slot per bus: slot_min = slot_max
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 			bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num);
8181da177e4SLinus Torvalds 			if (!bus_info_ptr2) {
819f5afe806SEric Sesterhenn 				bus_info_ptr1 = kzalloc(sizeof(struct bus_info), GFP_KERNEL);
8201da177e4SLinus Torvalds 				if (!bus_info_ptr1) {
8211da177e4SLinus Torvalds 					rc = -ENOMEM;
8221da177e4SLinus Torvalds 					goto error_no_hp_slot;
8231da177e4SLinus Torvalds 				}
8241da177e4SLinus Torvalds 				bus_info_ptr1->slot_min = slot_ptr->slot_num;
8251da177e4SLinus Torvalds 				bus_info_ptr1->slot_max = slot_ptr->slot_num;
8261da177e4SLinus Torvalds 				bus_info_ptr1->slot_count += 1;
8271da177e4SLinus Torvalds 				bus_info_ptr1->busno = slot_ptr->slot_bus_num;
8281da177e4SLinus Torvalds 				bus_info_ptr1->index = bus_index++;
8291da177e4SLinus Torvalds 				bus_info_ptr1->current_speed = 0xff;
8301da177e4SLinus Torvalds 				bus_info_ptr1->current_bus_mode = 0xff;
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds 				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 				list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head);
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds 			} else {
8371da177e4SLinus Torvalds 				bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num);
8381da177e4SLinus Torvalds 				bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num);
8391da177e4SLinus Torvalds 				bus_info_ptr2->slot_count += 1;
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds 			}
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 			// end of creating the bus_info linked list
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 			slot_ptr++;
8461da177e4SLinus Torvalds 			addr_slot += 1;
8471da177e4SLinus Torvalds 		}
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds 		/* init bus structure */
8501da177e4SLinus Torvalds 		bus_ptr = hpc_ptr->buses;
8511da177e4SLinus Torvalds 		for (bus = 0; bus < bus_num; bus++) {
8521da177e4SLinus Torvalds 			bus_ptr->bus_num = readb (io_mem + addr_bus + bus);
8531da177e4SLinus Torvalds 			bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus);
8541da177e4SLinus Torvalds 			bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1);
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 			bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2);
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds 			bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3);
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds 			bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4);
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds 			bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num);
8631da177e4SLinus Torvalds 			if (bus_info_ptr2) {
8641da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
8651da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
8661da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
8671da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
8681da177e4SLinus Torvalds 				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix;
8691da177e4SLinus Torvalds 			}
8701da177e4SLinus Torvalds 			bus_ptr++;
8711da177e4SLinus Torvalds 		}
8721da177e4SLinus Torvalds 
8731da177e4SLinus Torvalds 		hpc_ptr->ctlr_type = temp;
8741da177e4SLinus Torvalds 
8751da177e4SLinus Torvalds 		switch (hpc_ptr->ctlr_type) {
8761da177e4SLinus Torvalds 			case 1:
8771da177e4SLinus Torvalds 				hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr);
8781da177e4SLinus Torvalds 				hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
8791da177e4SLinus Torvalds 				hpc_ptr->irq = readb (io_mem + addr + 2);
8801da177e4SLinus Torvalds 				addr += 3;
8811da177e4SLinus Torvalds 				debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n",
8821da177e4SLinus Torvalds 					hpc_ptr->u.pci_ctlr.bus,
8831da177e4SLinus Torvalds 					hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
8841da177e4SLinus Torvalds 				break;
8851da177e4SLinus Torvalds 
8861da177e4SLinus Torvalds 			case 0:
8871da177e4SLinus Torvalds 				hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
8881da177e4SLinus Torvalds 				hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
8891da177e4SLinus Torvalds 				if (!request_region (hpc_ptr->u.isa_ctlr.io_start,
8901da177e4SLinus Torvalds 						     (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
8911da177e4SLinus Torvalds 						     "ibmphp")) {
8921da177e4SLinus Torvalds 					rc = -ENODEV;
8931da177e4SLinus Torvalds 					goto error_no_hp_slot;
8941da177e4SLinus Torvalds 				}
8951da177e4SLinus Torvalds 				hpc_ptr->irq = readb (io_mem + addr + 4);
8961da177e4SLinus Torvalds 				addr += 5;
8971da177e4SLinus Torvalds 				break;
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 			case 2:
9001da177e4SLinus Torvalds 			case 4:
9011da177e4SLinus Torvalds 				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
9021da177e4SLinus Torvalds 				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
9031da177e4SLinus Torvalds 				hpc_ptr->irq = readb (io_mem + addr + 5);
9041da177e4SLinus Torvalds 				addr += 6;
9051da177e4SLinus Torvalds 				break;
9061da177e4SLinus Torvalds 			default:
9071da177e4SLinus Torvalds 				rc = -ENODEV;
9081da177e4SLinus Torvalds 				goto error_no_hp_slot;
9091da177e4SLinus Torvalds 		}
9101da177e4SLinus Torvalds 
9111da177e4SLinus Torvalds 		//reorganize chassis' linked list
9121da177e4SLinus Torvalds 		combine_wpg_for_chassis ();
9131da177e4SLinus Torvalds 		combine_wpg_for_expansion ();
9141da177e4SLinus Torvalds 		hpc_ptr->revision = 0xff;
9151da177e4SLinus Torvalds 		hpc_ptr->options = 0xff;
9161da177e4SLinus Torvalds 		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
9171da177e4SLinus Torvalds 		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
9181da177e4SLinus Torvalds 
9191da177e4SLinus Torvalds 		// register slots with hpc core as well as create linked list of ibm slot
9201da177e4SLinus Torvalds 		for (index = 0; index < hpc_ptr->slot_count; index++) {
9211da177e4SLinus Torvalds 
922f5afe806SEric Sesterhenn 			hp_slot_ptr = kzalloc(sizeof(*hp_slot_ptr), GFP_KERNEL);
9231da177e4SLinus Torvalds 			if (!hp_slot_ptr) {
9241da177e4SLinus Torvalds 				rc = -ENOMEM;
9251da177e4SLinus Torvalds 				goto error_no_hp_slot;
9261da177e4SLinus Torvalds 			}
9271da177e4SLinus Torvalds 
928f5afe806SEric Sesterhenn 			hp_slot_ptr->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
9291da177e4SLinus Torvalds 			if (!hp_slot_ptr->info) {
9301da177e4SLinus Torvalds 				rc = -ENOMEM;
9311da177e4SLinus Torvalds 				goto error_no_hp_info;
9321da177e4SLinus Torvalds 			}
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds 			hp_slot_ptr->name = kmalloc(30, GFP_KERNEL);
9351da177e4SLinus Torvalds 			if (!hp_slot_ptr->name) {
9361da177e4SLinus Torvalds 				rc = -ENOMEM;
9371da177e4SLinus Torvalds 				goto error_no_hp_name;
9381da177e4SLinus Torvalds 			}
9391da177e4SLinus Torvalds 
940f5afe806SEric Sesterhenn 			tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL);
9411da177e4SLinus Torvalds 			if (!tmp_slot) {
9421da177e4SLinus Torvalds 				rc = -ENOMEM;
9431da177e4SLinus Torvalds 				goto error_no_slot;
9441da177e4SLinus Torvalds 			}
9451da177e4SLinus Torvalds 
946dc6712d1SKristen Accardi 			tmp_slot->flag = 1;
9471da177e4SLinus Torvalds 
9481da177e4SLinus Torvalds 			tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
9491da177e4SLinus Torvalds 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
9501da177e4SLinus Torvalds 				tmp_slot->supported_speed =  3;
9511da177e4SLinus Torvalds 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
9521da177e4SLinus Torvalds 				tmp_slot->supported_speed =  2;
9531da177e4SLinus Torvalds 			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
9541da177e4SLinus Torvalds 				tmp_slot->supported_speed =  1;
9551da177e4SLinus Torvalds 
9561da177e4SLinus Torvalds 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
9571da177e4SLinus Torvalds 				tmp_slot->supported_bus_mode = 1;
9581da177e4SLinus Torvalds 			else
9591da177e4SLinus Torvalds 				tmp_slot->supported_bus_mode = 0;
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 
9621da177e4SLinus Torvalds 			tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds 			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
9651da177e4SLinus Torvalds 			if (!bus_info_ptr1) {
966b91aac29SJesper Juhl 				kfree(tmp_slot);
9671da177e4SLinus Torvalds 				rc = -ENODEV;
9681da177e4SLinus Torvalds 				goto error;
9691da177e4SLinus Torvalds 			}
9701da177e4SLinus Torvalds 			tmp_slot->bus_on = bus_info_ptr1;
9711da177e4SLinus Torvalds 			bus_info_ptr1 = NULL;
9721da177e4SLinus Torvalds 			tmp_slot->ctrl = hpc_ptr;
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds 			tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
9751da177e4SLinus Torvalds 			tmp_slot->number = hpc_ptr->slots[index].slot_num;
9761da177e4SLinus Torvalds 			tmp_slot->hotplug_slot = hp_slot_ptr;
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds 			hp_slot_ptr->private = tmp_slot;
9791da177e4SLinus Torvalds 			hp_slot_ptr->release = release_slot;
9801da177e4SLinus Torvalds 
9811da177e4SLinus Torvalds 			rc = fillslotinfo(hp_slot_ptr);
9821da177e4SLinus Torvalds 			if (rc)
9831da177e4SLinus Torvalds 				goto error;
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds 			rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private);
9861da177e4SLinus Torvalds 			if (rc)
9871da177e4SLinus Torvalds 				goto error;
9881da177e4SLinus Torvalds 			hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
9891da177e4SLinus Torvalds 
9901da177e4SLinus Torvalds 			// end of registering ibm slot with hotplug core
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 			list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head);
9931da177e4SLinus Torvalds 		}
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 		print_bus_info ();
9961da177e4SLinus Torvalds 		list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head );
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds 	}			/* each hpc  */
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 	list_for_each (list, &ibmphp_slot_head) {
10011da177e4SLinus Torvalds 		tmp_slot = list_entry (list, struct slot, ibm_slot_list);
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 		snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
10041da177e4SLinus Torvalds 		pci_hp_register (tmp_slot->hotplug_slot);
10051da177e4SLinus Torvalds 	}
10061da177e4SLinus Torvalds 
10071da177e4SLinus Torvalds 	print_ebda_hpc ();
10081da177e4SLinus Torvalds 	print_ibm_slot ();
10091da177e4SLinus Torvalds 	return 0;
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds error:
10121da177e4SLinus Torvalds 	kfree (hp_slot_ptr->private);
10131da177e4SLinus Torvalds error_no_slot:
10141da177e4SLinus Torvalds 	kfree (hp_slot_ptr->name);
10151da177e4SLinus Torvalds error_no_hp_name:
10161da177e4SLinus Torvalds 	kfree (hp_slot_ptr->info);
10171da177e4SLinus Torvalds error_no_hp_info:
10181da177e4SLinus Torvalds 	kfree (hp_slot_ptr);
10191da177e4SLinus Torvalds error_no_hp_slot:
10201da177e4SLinus Torvalds 	free_ebda_hpc (hpc_ptr);
10211da177e4SLinus Torvalds error_no_hpc:
10221da177e4SLinus Torvalds 	iounmap (io_mem);
10231da177e4SLinus Torvalds 	return rc;
10241da177e4SLinus Torvalds }
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds /*
10271da177e4SLinus Torvalds  * map info (bus, devfun, start addr, end addr..) of i/o, memory,
10281da177e4SLinus Torvalds  * pfm from the physical addr to a list of resource.
10291da177e4SLinus Torvalds  */
10301da177e4SLinus Torvalds static int __init ebda_rsrc_rsrc (void)
10311da177e4SLinus Torvalds {
10321da177e4SLinus Torvalds 	u16 addr;
10331da177e4SLinus Torvalds 	short rsrc;
10341da177e4SLinus Torvalds 	u8 type, rsrc_type;
10351da177e4SLinus Torvalds 	struct ebda_pci_rsrc *rsrc_ptr;
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 	addr = rsrc_list_ptr->phys_addr;
10381da177e4SLinus Torvalds 	debug ("now entering rsrc land\n");
10391da177e4SLinus Torvalds 	debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr);
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds 	for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) {
10421da177e4SLinus Torvalds 		type = readb (io_mem + addr);
10431da177e4SLinus Torvalds 
10441da177e4SLinus Torvalds 		addr += 1;
10451da177e4SLinus Torvalds 		rsrc_type = type & EBDA_RSRC_TYPE_MASK;
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds 		if (rsrc_type == EBDA_IO_RSRC_TYPE) {
10481da177e4SLinus Torvalds 			rsrc_ptr = alloc_ebda_pci_rsrc ();
10491da177e4SLinus Torvalds 			if (!rsrc_ptr) {
10501da177e4SLinus Torvalds 				iounmap (io_mem);
10511da177e4SLinus Torvalds 				return -ENOMEM;
10521da177e4SLinus Torvalds 			}
10531da177e4SLinus Torvalds 			rsrc_ptr->rsrc_type = type;
10541da177e4SLinus Torvalds 
10551da177e4SLinus Torvalds 			rsrc_ptr->bus_num = readb (io_mem + addr);
10561da177e4SLinus Torvalds 			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
10571da177e4SLinus Torvalds 			rsrc_ptr->start_addr = readw (io_mem + addr + 2);
10581da177e4SLinus Torvalds 			rsrc_ptr->end_addr = readw (io_mem + addr + 4);
10591da177e4SLinus Torvalds 			addr += 6;
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds 			debug ("rsrc from io type ----\n");
10621da177e4SLinus Torvalds 			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
10631da177e4SLinus Torvalds 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
10641da177e4SLinus Torvalds 
10651da177e4SLinus Torvalds 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
10661da177e4SLinus Torvalds 		}
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds 		if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) {
10691da177e4SLinus Torvalds 			rsrc_ptr = alloc_ebda_pci_rsrc ();
10701da177e4SLinus Torvalds 			if (!rsrc_ptr ) {
10711da177e4SLinus Torvalds 				iounmap (io_mem);
10721da177e4SLinus Torvalds 				return -ENOMEM;
10731da177e4SLinus Torvalds 			}
10741da177e4SLinus Torvalds 			rsrc_ptr->rsrc_type = type;
10751da177e4SLinus Torvalds 
10761da177e4SLinus Torvalds 			rsrc_ptr->bus_num = readb (io_mem + addr);
10771da177e4SLinus Torvalds 			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
10781da177e4SLinus Torvalds 			rsrc_ptr->start_addr = readl (io_mem + addr + 2);
10791da177e4SLinus Torvalds 			rsrc_ptr->end_addr = readl (io_mem + addr + 6);
10801da177e4SLinus Torvalds 			addr += 10;
10811da177e4SLinus Torvalds 
10821da177e4SLinus Torvalds 			debug ("rsrc from mem or pfm ---\n");
10831da177e4SLinus Torvalds 			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
10841da177e4SLinus Torvalds 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
10851da177e4SLinus Torvalds 
10861da177e4SLinus Torvalds 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
10871da177e4SLinus Torvalds 		}
10881da177e4SLinus Torvalds 	}
10891da177e4SLinus Torvalds 	kfree (rsrc_list_ptr);
10901da177e4SLinus Torvalds 	rsrc_list_ptr = NULL;
10911da177e4SLinus Torvalds 	print_ebda_pci_rsrc ();
10921da177e4SLinus Torvalds 	return 0;
10931da177e4SLinus Torvalds }
10941da177e4SLinus Torvalds 
10951da177e4SLinus Torvalds u16 ibmphp_get_total_controllers (void)
10961da177e4SLinus Torvalds {
10971da177e4SLinus Torvalds 	return hpc_list_ptr->num_ctlrs;
10981da177e4SLinus Torvalds }
10991da177e4SLinus Torvalds 
11001da177e4SLinus Torvalds struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num)
11011da177e4SLinus Torvalds {
11021da177e4SLinus Torvalds 	struct slot *slot;
11031da177e4SLinus Torvalds 	struct list_head *list;
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 	list_for_each (list, &ibmphp_slot_head) {
11061da177e4SLinus Torvalds 		slot = list_entry (list, struct slot, ibm_slot_list);
11071da177e4SLinus Torvalds 		if (slot->number == physical_num)
11081da177e4SLinus Torvalds 			return slot;
11091da177e4SLinus Torvalds 	}
11101da177e4SLinus Torvalds 	return NULL;
11111da177e4SLinus Torvalds }
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds /* To find:
11141da177e4SLinus Torvalds  *	- the smallest slot number
11151da177e4SLinus Torvalds  *	- the largest slot number
11161da177e4SLinus Torvalds  *	- the total number of the slots based on each bus
11171da177e4SLinus Torvalds  *	  (if only one slot per bus slot_min = slot_max )
11181da177e4SLinus Torvalds  */
11191da177e4SLinus Torvalds struct bus_info *ibmphp_find_same_bus_num (u32 num)
11201da177e4SLinus Torvalds {
11211da177e4SLinus Torvalds 	struct bus_info *ptr;
11221da177e4SLinus Torvalds 	struct list_head  *ptr1;
11231da177e4SLinus Torvalds 
11241da177e4SLinus Torvalds 	list_for_each (ptr1, &bus_info_head) {
11251da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct bus_info, bus_info_list);
11261da177e4SLinus Torvalds 		if (ptr->busno == num)
11271da177e4SLinus Torvalds 			 return ptr;
11281da177e4SLinus Torvalds 	}
11291da177e4SLinus Torvalds 	return NULL;
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds /*  Finding relative bus number, in order to map corresponding
11331da177e4SLinus Torvalds  *  bus register
11341da177e4SLinus Torvalds  */
11351da177e4SLinus Torvalds int ibmphp_get_bus_index (u8 num)
11361da177e4SLinus Torvalds {
11371da177e4SLinus Torvalds 	struct bus_info *ptr;
11381da177e4SLinus Torvalds 	struct list_head  *ptr1;
11391da177e4SLinus Torvalds 
11401da177e4SLinus Torvalds 	list_for_each (ptr1, &bus_info_head) {
11411da177e4SLinus Torvalds 		ptr = list_entry (ptr1, struct bus_info, bus_info_list);
11421da177e4SLinus Torvalds 		if (ptr->busno == num)
11431da177e4SLinus Torvalds 			return ptr->index;
11441da177e4SLinus Torvalds 	}
11451da177e4SLinus Torvalds 	return -ENODEV;
11461da177e4SLinus Torvalds }
11471da177e4SLinus Torvalds 
11481da177e4SLinus Torvalds void ibmphp_free_bus_info_queue (void)
11491da177e4SLinus Torvalds {
11501da177e4SLinus Torvalds 	struct bus_info *bus_info;
11511da177e4SLinus Torvalds 	struct list_head *list;
11521da177e4SLinus Torvalds 	struct list_head *next;
11531da177e4SLinus Torvalds 
11541da177e4SLinus Torvalds 	list_for_each_safe (list, next, &bus_info_head ) {
11551da177e4SLinus Torvalds 		bus_info = list_entry (list, struct bus_info, bus_info_list);
11561da177e4SLinus Torvalds 		kfree (bus_info);
11571da177e4SLinus Torvalds 	}
11581da177e4SLinus Torvalds }
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds void ibmphp_free_ebda_hpc_queue (void)
11611da177e4SLinus Torvalds {
11621da177e4SLinus Torvalds 	struct controller *controller = NULL;
11631da177e4SLinus Torvalds 	struct list_head *list;
11641da177e4SLinus Torvalds 	struct list_head *next;
11651da177e4SLinus Torvalds 	int pci_flag = 0;
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 	list_for_each_safe (list, next, &ebda_hpc_head) {
11681da177e4SLinus Torvalds 		controller = list_entry (list, struct controller, ebda_hpc_list);
11691da177e4SLinus Torvalds 		if (controller->ctlr_type == 0)
11701da177e4SLinus Torvalds 			release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
11711da177e4SLinus Torvalds 		else if ((controller->ctlr_type == 1) && (!pci_flag)) {
11721da177e4SLinus Torvalds 			++pci_flag;
11731da177e4SLinus Torvalds 			pci_unregister_driver (&ibmphp_driver);
11741da177e4SLinus Torvalds 		}
11751da177e4SLinus Torvalds 		free_ebda_hpc (controller);
11761da177e4SLinus Torvalds 	}
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds void ibmphp_free_ebda_pci_rsrc_queue (void)
11801da177e4SLinus Torvalds {
11811da177e4SLinus Torvalds 	struct ebda_pci_rsrc *resource;
11821da177e4SLinus Torvalds 	struct list_head *list;
11831da177e4SLinus Torvalds 	struct list_head *next;
11841da177e4SLinus Torvalds 
11851da177e4SLinus Torvalds 	list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) {
11861da177e4SLinus Torvalds 		resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
11871da177e4SLinus Torvalds 		kfree (resource);
11881da177e4SLinus Torvalds 		resource = NULL;
11891da177e4SLinus Torvalds 	}
11901da177e4SLinus Torvalds }
11911da177e4SLinus Torvalds 
11921da177e4SLinus Torvalds static struct pci_device_id id_table[] = {
11931da177e4SLinus Torvalds 	{
11941da177e4SLinus Torvalds 		.vendor		= PCI_VENDOR_ID_IBM,
11951da177e4SLinus Torvalds 		.device		= HPC_DEVICE_ID,
11961da177e4SLinus Torvalds 		.subvendor	= PCI_VENDOR_ID_IBM,
11971da177e4SLinus Torvalds 		.subdevice	= HPC_SUBSYSTEM_ID,
11981da177e4SLinus Torvalds 		.class		= ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
11991da177e4SLinus Torvalds 	}, {}
12001da177e4SLinus Torvalds };
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, id_table);
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *);
12051da177e4SLinus Torvalds static struct pci_driver ibmphp_driver = {
12061da177e4SLinus Torvalds 	.name		= "ibmphp",
12071da177e4SLinus Torvalds 	.id_table	= id_table,
12081da177e4SLinus Torvalds 	.probe		= ibmphp_probe,
12091da177e4SLinus Torvalds };
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds int ibmphp_register_pci (void)
12121da177e4SLinus Torvalds {
12131da177e4SLinus Torvalds 	struct controller *ctrl;
12141da177e4SLinus Torvalds 	struct list_head *tmp;
12151da177e4SLinus Torvalds 	int rc = 0;
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	list_for_each (tmp, &ebda_hpc_head) {
12181da177e4SLinus Torvalds 		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
12191da177e4SLinus Torvalds 		if (ctrl->ctlr_type == 1) {
12201da177e4SLinus Torvalds 			rc = pci_register_driver(&ibmphp_driver);
12211da177e4SLinus Torvalds 			break;
12221da177e4SLinus Torvalds 		}
12231da177e4SLinus Torvalds 	}
12241da177e4SLinus Torvalds 	return rc;
12251da177e4SLinus Torvalds }
12261da177e4SLinus Torvalds static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids)
12271da177e4SLinus Torvalds {
12281da177e4SLinus Torvalds 	struct controller *ctrl;
12291da177e4SLinus Torvalds 	struct list_head *tmp;
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds 	debug ("inside ibmphp_probe\n");
12321da177e4SLinus Torvalds 
12331da177e4SLinus Torvalds 	list_for_each (tmp, &ebda_hpc_head) {
12341da177e4SLinus Torvalds 		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
12351da177e4SLinus Torvalds 		if (ctrl->ctlr_type == 1) {
12361da177e4SLinus Torvalds 			if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
12371da177e4SLinus Torvalds 				ctrl->ctrl_dev = dev;
12381da177e4SLinus Torvalds 				debug ("found device!!!\n");
12391da177e4SLinus Torvalds 				debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
12401da177e4SLinus Torvalds 				return 0;
12411da177e4SLinus Torvalds 			}
12421da177e4SLinus Torvalds 		}
12431da177e4SLinus Torvalds 	}
12441da177e4SLinus Torvalds 	return -ENODEV;
12451da177e4SLinus Torvalds }
12461da177e4SLinus Torvalds 
1247