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