rpaphp_pci.c revision 89a071b80767c3a7ed56e13ae5e810f751b19eeb
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com> 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NON INFRINGEMENT. See the GNU General Public License for more 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * details. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send feedback to <lxie@us.ibm.com> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 264e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/string.h> 274e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pci-bridge.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/rtas.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/machdep.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 324e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include "../pci.h" /* for pci_add_new_bus */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "rpaphp.h" 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 350945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rosestatic struct pci_bus *find_bus_among_children(struct pci_bus *bus, 369c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct device_node *dn) 379c209c919df95f83aa042b3352c43841ad15a02bJohn Rose{ 389c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct pci_bus *child = NULL; 399c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct list_head *tmp; 409c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct device_node *busdn; 419c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 429c209c919df95f83aa042b3352c43841ad15a02bJohn Rose busdn = pci_bus_to_OF_node(bus); 439c209c919df95f83aa042b3352c43841ad15a02bJohn Rose if (busdn == dn) 449c209c919df95f83aa042b3352c43841ad15a02bJohn Rose return bus; 459c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 469c209c919df95f83aa042b3352c43841ad15a02bJohn Rose list_for_each(tmp, &bus->children) { 479c209c919df95f83aa042b3352c43841ad15a02bJohn Rose child = find_bus_among_children(pci_bus_b(tmp), dn); 489c209c919df95f83aa042b3352c43841ad15a02bJohn Rose if (child) 499c209c919df95f83aa042b3352c43841ad15a02bJohn Rose break; 509c209c919df95f83aa042b3352c43841ad15a02bJohn Rose } 519c209c919df95f83aa042b3352c43841ad15a02bJohn Rose return child; 529c209c919df95f83aa042b3352c43841ad15a02bJohn Rose} 539c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 5456d8456b06ad1316bff3c75caed5e06e786f20d8John Rosestruct pci_bus *rpaphp_find_pci_bus(struct device_node *dn) 559c209c919df95f83aa042b3352c43841ad15a02bJohn Rose{ 561635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras struct pci_dn *pdn = dn->data; 571635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras 581635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras if (!pdn || !pdn->phb || !pdn->phb->bus) 590945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose return NULL; 609c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 611635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras return find_bus_among_children(pdn->phb->bus, dn); 629c209c919df95f83aa042b3352c43841ad15a02bJohn Rose} 6356d8456b06ad1316bff3c75caed5e06e786f20d8John RoseEXPORT_SYMBOL_GPL(rpaphp_find_pci_bus); 649c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint rpaphp_claim_resource(struct pci_dev *dev, int resource) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource *res = &dev->resource[resource]; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource *root = pci_find_parent_resource(dev, res); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge"; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -EINVAL; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (root != NULL) { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = request_resource(root, res); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("PCI: %s region %d of %s %s [%lx:%lx]\n", 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds root ? "Address space collision on" : 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "No parent found for", 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource, dtype, pci_name(dev), res->start, res->end); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL_GPL(rpaphp_claim_resource); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rpaphp_get_sensor_state(struct slot *slot, int *state) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int setlevel; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc < 0) { 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc == -EFAULT || rc == -EEXIST) { 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: slot must be power up to get sensor-state\n", 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* some slots have to be powered up 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * before get-sensor will succeed. 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = rtas_set_power_level(slot->power_domain, POWER_ON, 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &setlevel); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc < 0) { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: power on slot[%s] failed rc=%d.\n", 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, slot->name, rc); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = rtas_get_sensor(DR_ENTITY_SENSE, 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->index, state); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (rc == -ENODEV) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info("%s: slot is unusable\n", __FUNCTION__); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s failed to get sensor state\n", __FUNCTION__); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get_pci_adapter_status - get the status of a slot 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0-- slot is empty 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1-- adapter is configured 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2-- adapter is not configured 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3-- not valid 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1290945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose struct pci_bus *bus; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int state, rc; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = NOT_VALID; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = rpaphp_get_sensor_state(slot, &state); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13756d8456b06ad1316bff3c75caed5e06e786f20d8John Rose if (state == EMPTY) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = EMPTY; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (state == PRESENT) { 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!is_init) { 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* at run-time slot->state can be changed by */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* config/unconfig adapter */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = slot->state; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1450945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose bus = rpaphp_find_pci_bus(slot->dn); 1460945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose if (bus && !list_empty(&bus->devices)) 1470945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose *value = CONFIGURED; 1480945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose else 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = NOT_CONFIGURED; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Must be called before pci_bus_add_devices */ 1575fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rosevoid rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(dev, &bus->devices, bus_list) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Skip already-present devices (which are on the 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * global device list.) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list_empty(&dev->global_list)) { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Need to setup IOMMU tables */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppc_md.iommu_dev_setup(dev); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(fix_bus) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcibios_fixup_device_resources(dev, bus); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_irq_line(dev); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < PCI_NUM_RESOURCES; i++) { 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource *r = &dev->resource[i]; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r->parent || !r->start || !r->flags) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rpaphp_claim_resource(dev, i); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1865fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rosestatic void rpaphp_eeh_add_bus_device(struct pci_bus *bus) 1875fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose{ 1885fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose struct pci_dev *dev; 1895fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose 1905fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose list_for_each_entry(dev, &bus->devices, bus_list) { 1915fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose eeh_add_device_late(dev); 1925fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 1935fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose struct pci_bus *subbus = dev->subordinate; 1945fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose if (subbus) 1955fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_eeh_add_bus_device (subbus); 1965fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose } 1975fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose } 1985fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose} 1995fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rpaphp_pci_config_bridge(struct pci_dev *dev) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 sec_busno; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_bus *child_bus; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *child_dev; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("Enter %s: BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev)); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get busno of downstream bus */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* add to children of PCI bridge dev->bus */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!child_bus) { 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s: could not add second bus\n", __FUNCTION__); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* do pci_scan_child_bus */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_scan_child_bus(child_bus); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(child_dev, &child_bus->devices, bus_list) { 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eeh_add_device_late(child_dev); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fixup new pci devices without touching bus struct */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rpaphp_fixup_new_pci_devices(child_bus, 0); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make the discovered devices available */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_bus_add_devices(child_bus); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2335fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rosevoid rpaphp_init_new_devs(struct pci_bus *bus) 2345fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose{ 2355fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_fixup_new_pci_devices(bus, 0); 2365fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_eeh_add_bus_device(bus); 2375fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose} 2385fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John RoseEXPORT_SYMBOL_GPL(rpaphp_init_new_devs); 2395fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose 240bde168412440084e649e7e04938bd1ab6e7bf978John Rose/***************************************************************************** 241bde168412440084e649e7e04938bd1ab6e7bf978John Rose rpaphp_pci_config_slot() will configure all devices under the 242bde168412440084e649e7e04938bd1ab6e7bf978John Rose given slot->dn and return the the first pci_dev. 243bde168412440084e649e7e04938bd1ab6e7bf978John Rose *****************************************************************************/ 244bde168412440084e649e7e04938bd1ab6e7bf978John Rosestatic struct pci_dev * 245940903c5a5a906c622a79b3101586deb1a1b3480John Roserpaphp_pci_config_slot(struct pci_bus *bus) 246bde168412440084e649e7e04938bd1ab6e7bf978John Rose{ 247940903c5a5a906c622a79b3101586deb1a1b3480John Rose struct device_node *dn = pci_bus_to_OF_node(bus); 248bde168412440084e649e7e04938bd1ab6e7bf978John Rose struct pci_dev *dev = NULL; 2499c209c919df95f83aa042b3352c43841ad15a02bJohn Rose int slotno; 250bde168412440084e649e7e04938bd1ab6e7bf978John Rose int num; 251bde168412440084e649e7e04938bd1ab6e7bf978John Rose 252bde168412440084e649e7e04938bd1ab6e7bf978John Rose dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); 253940903c5a5a906c622a79b3101586deb1a1b3480John Rose if (!dn || !dn->child) 2540945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose return NULL; 255bde168412440084e649e7e04938bd1ab6e7bf978John Rose 25689a071b80767c3a7ed56e13ae5e810f751b19eebAndrew Morton if (_machine == PLATFORM_PSERIES_LPAR) { 2575fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose of_scan_bus(dn, bus); 2585fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose if (list_empty(&bus->devices)) { 2595fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose err("%s: No new device found\n", __FUNCTION__); 2605fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose return NULL; 2615fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose } 2629c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 2635fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_init_new_devs(bus); 2640945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose pci_bus_add_devices(bus); 2655fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose dev = list_entry(&bus->devices, struct pci_dev, bus_list); 2665fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose } else { 2675fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); 2685fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose 2695fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose /* pci_scan_slot should find all children */ 2705fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); 2715fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose if (num) { 2725fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_fixup_new_pci_devices(bus, 1); 2735fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose pci_bus_add_devices(bus); 2745fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose } 2755fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose if (list_empty(&bus->devices)) { 2765fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose err("%s: No new device found\n", __FUNCTION__); 2775fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose return NULL; 2785fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose } 2795fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose list_for_each_entry(dev, &bus->devices, bus_list) { 2805fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 2815fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_pci_config_bridge(dev); 2825fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose 2835fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_eeh_add_bus_device(bus); 2845fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose } 285bde168412440084e649e7e04938bd1ab6e7bf978John Rose } 2860945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose 287bde168412440084e649e7e04938bd1ab6e7bf978John Rose return dev; 288bde168412440084e649e7e04938bd1ab6e7bf978John Rose} 289bde168412440084e649e7e04938bd1ab6e7bf978John Rose 2905fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rosevoid rpaphp_eeh_init_nodes(struct device_node *dn) 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct device_node *sib; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (sib = dn->child; sib; sib = sib->sibling) 2955fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_eeh_init_nodes(sib); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eeh_add_device_early(dn); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3005fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John RoseEXPORT_SYMBOL_GPL(rpaphp_eeh_init_nodes); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 302940903c5a5a906c622a79b3101586deb1a1b3480John Rosestatic void print_slot_pci_funcs(struct pci_bus *bus) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 304940903c5a5a906c622a79b3101586deb1a1b3480John Rose struct device_node *dn; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 307940903c5a5a906c622a79b3101586deb1a1b3480John Rose dn = pci_bus_to_OF_node(bus); 308940903c5a5a906c622a79b3101586deb1a1b3480John Rose if (!dn) 309940903c5a5a906c622a79b3101586deb1a1b3480John Rose return; 310940903c5a5a906c622a79b3101586deb1a1b3480John Rose 311940903c5a5a906c622a79b3101586deb1a1b3480John Rose dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name); 312940903c5a5a906c622a79b3101586deb1a1b3480John Rose list_for_each_entry (dev, &bus->devices, bus_list) 3135eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose dbg("\t%s\n", pci_name(dev)); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 317940903c5a5a906c622a79b3101586deb1a1b3480John Roseint rpaphp_config_pci_adapter(struct pci_bus *bus) 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 319940903c5a5a906c622a79b3101586deb1a1b3480John Rose struct device_node *dn = pci_bus_to_OF_node(bus); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -ENODEV; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 323940903c5a5a906c622a79b3101586deb1a1b3480John Rose dbg("Entry %s: slot[%s]\n", __FUNCTION__, dn->full_name); 324940903c5a5a906c622a79b3101586deb1a1b3480John Rose if (!dn) 325940903c5a5a906c622a79b3101586deb1a1b3480John Rose goto exit; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3275fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose rpaphp_eeh_init_nodes(dn); 328940903c5a5a906c622a79b3101586deb1a1b3480John Rose dev = rpaphp_pci_config_slot(bus); 3299c209c919df95f83aa042b3352c43841ad15a02bJohn Rose if (!dev) { 3309c209c919df95f83aa042b3352c43841ad15a02bJohn Rose err("%s: can't find any devices.\n", __FUNCTION__); 3319c209c919df95f83aa042b3352c43841ad15a02bJohn Rose goto exit; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 333940903c5a5a906c622a79b3101586deb1a1b3480John Rose print_slot_pci_funcs(bus); 3349c209c919df95f83aa042b3352c43841ad15a02bJohn Rose rc = 0; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("Exit %s: rc=%d\n", __FUNCTION__, rc); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 339940903c5a5a906c622a79b3101586deb1a1b3480John RoseEXPORT_SYMBOL_GPL(rpaphp_config_pci_adapter); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eeh_remove_device(dev); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_bus *bus = dev->subordinate; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *ln; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bus) 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *pdev = pci_dev_b(ln); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pdev) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rpaphp_eeh_remove_bus_device(pdev); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 359934199e95d6ac28f42686fe3009877eff33e06c3Linas Vepstasint rpaphp_unconfig_pci_adapter(struct pci_bus *bus) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3619c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct pci_dev *dev, *tmp; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 363934199e95d6ac28f42686fe3009877eff33e06c3Linas Vepstas list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rpaphp_eeh_remove_bus_device(dev); 3659c209c919df95f83aa042b3352c43841ad15a02bJohn Rose pci_remove_bus_device(dev); 3669c209c919df95f83aa042b3352c43841ad15a02bJohn Rose } 367934199e95d6ac28f42686fe3009877eff33e06c3Linas Vepstas return 0; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3695fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John RoseEXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int setup_pci_hotplug_slot_info(struct slot *slot) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s Initilize the PCI slot's hotplug->info structure ...\n", 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rpaphp_get_power_status(slot, &slot->hotplug_slot->info->power_status); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rpaphp_get_pci_adapter_status(slot, 1, 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &slot->hotplug_slot->info-> 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter_status); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->hotplug_slot->info->adapter_status == NOT_VALID) { 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s: NOT_VALID: skip dn->full_name=%s\n", 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, slot->dn->full_name); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3879c209c919df95f83aa042b3352c43841ad15a02bJohn Rosestatic void set_slot_name(struct slot *slot) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3899c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct pci_bus *bus = slot->bus; 3909c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct pci_dev *bridge; 3919c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 3929c209c919df95f83aa042b3352c43841ad15a02bJohn Rose bridge = bus->self; 3939c209c919df95f83aa042b3352c43841ad15a02bJohn Rose if (bridge) 3949c209c919df95f83aa042b3352c43841ad15a02bJohn Rose strcpy(slot->name, pci_name(bridge)); 3959c209c919df95f83aa042b3352c43841ad15a02bJohn Rose else 3969c209c919df95f83aa042b3352c43841ad15a02bJohn Rose sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus), 3979c209c919df95f83aa042b3352c43841ad15a02bJohn Rose bus->number); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int setup_pci_slot(struct slot *slot) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4029c209c919df95f83aa042b3352c43841ad15a02bJohn Rose struct device_node *dn = slot->dn; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_bus *bus; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4059c209c919df95f83aa042b3352c43841ad15a02bJohn Rose BUG_ON(!dn); 4069c209c919df95f83aa042b3352c43841ad15a02bJohn Rose bus = rpaphp_find_pci_bus(dn); 4079c209c919df95f83aa042b3352c43841ad15a02bJohn Rose if (!bus) { 4089c209c919df95f83aa042b3352c43841ad15a02bJohn Rose err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); 4099c209c919df95f83aa042b3352c43841ad15a02bJohn Rose goto exit_rc; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4129c209c919df95f83aa042b3352c43841ad15a02bJohn Rose slot->bus = bus; 4139c209c919df95f83aa042b3352c43841ad15a02bJohn Rose slot->pci_devs = &bus->devices; 4149c209c919df95f83aa042b3352c43841ad15a02bJohn Rose set_slot_name(slot); 4159c209c919df95f83aa042b3352c43841ad15a02bJohn Rose 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* find slot's pci_dev if it's not empty */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->hotplug_slot->info->adapter_status == EMPTY) { 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->state = EMPTY; /* slot is empty */ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* slot is occupied */ 4219c209c919df95f83aa042b3352c43841ad15a02bJohn Rose if (!dn->child) { 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* non-empty slot has to have child */ 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s: slot[%s]'s device_node doesn't have child for adapter\n", 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, slot->name); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_rc; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) { 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s CONFIGURING pci adapter in slot[%s]\n", 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, slot->name); 431940903c5a5a906c622a79b3101586deb1a1b3480John Rose if (rpaphp_config_pci_adapter(slot->bus)) { 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s: CONFIG pci adapter failed\n", __FUNCTION__); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_rc; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) { 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s: slot[%s]'s adapter_status is NOT_VALID.\n", 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, slot->name); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_rc; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 441940903c5a5a906c622a79b3101586deb1a1b3480John Rose print_slot_pci_funcs(slot->bus); 4425eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose if (!list_empty(slot->pci_devs)) { 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->state = CONFIGURED; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DLPAR add as opposed to 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * boot time */ 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->state = NOT_CONFIGURED; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_rc: 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dealloc_slot_struct(slot); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint register_pci_slot(struct slot *slot) 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EINVAL; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup_pci_hotplug_slot_info(slot)) 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_rc; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (setup_pci_slot(slot)) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit_rc; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = register_slot(slot); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_rc: 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint rpaphp_enable_pci_slot(struct slot *slot) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = 0, state; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = rpaphp_get_sensor_state(slot, &state); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: sensor state[%d]\n", __FUNCTION__, state); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if slot is not empty, enable the adapter */ 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state == PRESENT) { 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name); 480940903c5a5a906c622a79b3101586deb1a1b3480John Rose retval = rpaphp_config_pci_adapter(slot->bus); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retval) { 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->state = CONFIGURED; 4835fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose info("%s: devices in slot[%s] configured\n", 4845fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose __FUNCTION__, slot->name); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->state = NOT_CONFIGURED; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s: no pci_dev struct for adapter in slot[%s]\n", 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, slot->name); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (state == EMPTY) { 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->state = EMPTY; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s: slot[%s] is in invalid state\n", __FUNCTION__, 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->name); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot->state = NOT_VALID; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EINVAL; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 503