11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interface for Dynamic Logical Partitioning of I/O Slots on
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RPA-compliant PPC64 platform.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * John Rose <johnrose@austin.ibm.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linda Xie <lxie@us.ibm.com>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * October 2003
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 IBM.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This program is free software; you can redistribute it and/or
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      modify it under the terms of the GNU General Public License
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      as published by the Free Software Foundation; either version
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      2 of the License, or (at your option) any later version.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
17fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt
18fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt#undef DEBUG
19fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
21eefa9cfc891d18aa83744353d2a3fbe95a86ee2dPaul Gortmaker#include <linux/module.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
234e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/string.h>
24b4a26be9f6f8bb72998e445cc75fc6dc0c29513aBenjamin Herrenschmidt#include <linux/vmalloc.h>
254e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pci-bridge.h>
2714cc3e2b633bb64063698980974df4535368e98fIngo Molnar#include <linux/mutex.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/rtas.h>
295eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose#include <asm/vio.h>
304e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../pci.h"
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "rpaphp.h"
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "rpadlpar.h"
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3514cc3e2b633bb64063698980974df4535368e98fIngo Molnarstatic DEFINE_MUTEX(rpadlpar_mutex);
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3756d8456b06ad1316bff3c75caed5e06e786f20d8John Rose#define DLPAR_MODULE_NAME "rpadlpar_io"
3856d8456b06ad1316bff3c75caed5e06e786f20d8John Rose
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NODE_TYPE_VIO  1
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NODE_TYPE_SLOT 2
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NODE_TYPE_PHB  3
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
435eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rosestatic struct device_node *find_vio_slot_node(char *drc_name)
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
465eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	struct device_node *dn = NULL;
475eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	char *name;
485eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	int rc;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!parent)
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
535eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	while ((dn = of_get_next_child(parent, dn))) {
545eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose		rc = rpaphp_get_drc_props(dn, NULL, &name, NULL, NULL);
555eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose		if ((rc == 0) && (!strcmp(drc_name, name)))
565eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose			break;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
595eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	return dn;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find dlpar-capable pci node that contains the specified name and type */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct device_node *find_php_slot_pci_node(char *drc_name,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  char *drc_type)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device_node *np = NULL;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *name;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *type;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71a57ed79ef1b71f6da44ebeabb41d019d172fb261John Rose	while ((np = of_find_node_by_name(np, "pci"))) {
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = rpaphp_get_drc_props(np, NULL, &name, &type, NULL);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rc == 0)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!strcmp(drc_name, name) && !strcmp(drc_type, type))
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return np;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
815eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rosestatic struct device_node *find_dlpar_node(char *drc_name, int *node_type)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device_node *dn;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn = find_php_slot_pci_node(drc_name, "SLOT");
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dn) {
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*node_type = NODE_TYPE_SLOT;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return dn;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn = find_php_slot_pci_node(drc_name, "PHB");
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dn) {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*node_type = NODE_TYPE_PHB;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return dn;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
975eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	dn = find_vio_slot_node(drc_name);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dn) {
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*node_type = NODE_TYPE_VIO;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return dn;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1068485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas/**
1078485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas * find_php_slot - return hotplug slot structure for device node
10826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @dn: target &device_node
1098485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas *
1108485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas * This routine will return the hotplug slot structure
1118485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas * for a given device node. Note that built-in PCI slots
1128485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas * may be dlpar-able, but not hot-pluggable, so this routine
1138485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas * will return NULL for built-in PCI slots.
1148485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas */
1158485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstasstatic struct slot *find_php_slot(struct device_node *dn)
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head *tmp, *n;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slot *slot;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1208737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	list_for_each_safe(tmp, n, &rpaphp_slot_head) {
1218737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
1228737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas		if (slot->dn == dn)
1238737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas			return slot;
1248737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1268737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	return NULL;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1290945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rosestatic struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
1300945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose					struct device_node *dev_dn)
1310945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose{
1320945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose	struct pci_dev *tmp = NULL;
1330945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose	struct device_node *child_dn;
1340945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose
1350945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose	list_for_each_entry(tmp, &parent->devices, bus_list) {
1360945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose		child_dn = pci_device_to_OF_node(tmp);
1370945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose		if (child_dn == dev_dn)
1380945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose			return tmp;
1390945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose	}
1400945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose	return NULL;
1410945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose}
1420945cd5f908a09ad99bf42d7ded16f26f24f317dJohn Rose
1438737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstasstatic void dlpar_pci_add_bus(struct device_node *dn)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1458737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	struct pci_dn *pdn = PCI_DN(dn);
1465fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose	struct pci_controller *phb = pdn->phb;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_dev *dev = NULL;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
149d681db4aed4453c7d34adfbb64956271186514e9Linas Vepstas	eeh_add_device_tree_early(dn);
150d681db4aed4453c7d34adfbb64956271186514e9Linas Vepstas
1515fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose	/* Add EADS device to PHB bus, adding new entry to bus->devices */
1525fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose	dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
1535fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose	if (!dev) {
1545fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose		printk(KERN_ERR "%s: failed to create pci dev for %s\n",
15566bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison				__func__, dn->full_name);
1568737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas		return;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	/* Scan below the new bridge */
1605fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
1615fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose	    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
16298d9f30c820d509145757e6ecbc36013aa02f7bcBenjamin Herrenschmidt		of_scan_pci_bridge(dev);
1635fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose
1643d5134ee8341bffc4f539049abb9e90d469b448dBenjamin Herrenschmidt	/* Map IO space for child bus, which may or may not succeed */
1653d5134ee8341bffc4f539049abb9e90d469b448dBenjamin Herrenschmidt	pcibios_map_io_space(dev->subordinate);
1665fa80fcdca9d20d30c9ecec30d4dbff4ed93a5c6John Rose
167fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	/* Finish adding it : resource allocation, adding devices, etc...
168fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	 * Note that we need to perform the finish pass on the -parent-
169fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	 * bus of the EADS bridge so the bridge device itself gets
170fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	 * properly added
171fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	 */
172fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	pcibios_finish_adding_to_bus(phb->bus);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175940903c5a5a906c622a79b3101586deb1a1b3480John Rosestatic int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_dev *dev;
1788737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	struct pci_controller *phb;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18001657868be1c21b2b8b0e683ea24bdcc2331d522Linas Vepstas	if (pcibios_find_pci_bus(dn))
18156d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EINVAL;
18256d8456b06ad1316bff3c75caed5e06e786f20d8John Rose
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Add pci bus */
1848737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	dlpar_pci_add_bus(dn);
1858737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas
1868737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	/* Confirm new bridge dev was created */
1878737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	phb = PCI_DN(dn)->phb;
1888737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	dev = dlpar_find_new_dev(phb->bus, dn);
1898737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev) {
19166bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison		printk(KERN_ERR "%s: unable to add bus %s\n", __func__,
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drc_name);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1968737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
1978737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas		printk(KERN_ERR "%s: unexpected header type %d, unable to add bus %s\n",
19866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			__func__, dev->hdr_type, drc_name);
1998737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas		return -EIO;
2008737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas	}
2018737d6a90cd8b085c2ea9cb4c7443c87f86c3429Linas Vepstas
2025eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	/* Add hotplug slot */
2035eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	if (rpaphp_add_slot(dn)) {
2045eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
20566bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			__func__, drc_name);
2065eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose		return -EIO;
2075eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21156d8456b06ad1316bff3c75caed5e06e786f20d8John Rosestatic int dlpar_remove_phb(char *drc_name, struct device_node *dn)
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21356d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	struct slot *slot;
2141635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras	struct pci_dn *pdn;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21701657868be1c21b2b8b0e683ea24bdcc2331d522Linas Vepstas	if (!pcibios_find_pci_bus(dn))
21856d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EINVAL;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2208485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas	/* If pci slot is hotplugable, use hotplug to remove it */
2218485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas	slot = find_php_slot(dn);
222fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	if (slot && rpaphp_deregister_slot(slot)) {
223fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
224fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt		       __func__, drc_name);
225fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt		return -EIO;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras	pdn = dn->data;
2291635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras	BUG_ON(!pdn || !pdn->phb);
230fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	rc = remove_phb_dynamic(pdn->phb);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc < 0)
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341635317facea3094ddf34082cd86797efb1d9f7ePaul Mackerras	pdn->phb = NULL;
23556d8456b06ad1316bff3c75caed5e06e786f20d8John Rose
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2395eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rosestatic int dlpar_add_phb(char *drc_name, struct device_node *dn)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_controller *phb;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243fe98aeab8494cf431ef62e080cbe1dc1b6f5bd49Linas Vepstas	if (PCI_DN(dn) && PCI_DN(dn)->phb) {
24456d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		/* PHB already exists */
24556d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EINVAL;
24656d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	}
24756d8456b06ad1316bff3c75caed5e06e786f20d8John Rose
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	phb = init_phb_dynamic(dn);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!phb)
25056d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EIO;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2525eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	if (rpaphp_add_slot(dn)) {
2535eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
25466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			__func__, drc_name);
2555eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose		return -EIO;
2565eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26056d8456b06ad1316bff3c75caed5e06e786f20d8John Rosestatic int dlpar_add_vio_slot(char *drc_name, struct device_node *dn)
26156d8456b06ad1316bff3c75caed5e06e786f20d8John Rose{
26256d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	if (vio_find_node(dn))
26356d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EINVAL;
26456d8456b06ad1316bff3c75caed5e06e786f20d8John Rose
26556d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	if (!vio_register_device_node(dn)) {
26656d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		printk(KERN_ERR
26756d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			"%s: failed to register vio node %s\n",
26866bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			__func__, drc_name);
26956d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EIO;
27056d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	}
27156d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	return 0;
27256d8456b06ad1316bff3c75caed5e06e786f20d8John Rose}
27356d8456b06ad1316bff3c75caed5e06e786f20d8John Rose
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dlpar_add_slot - DLPAR add an I/O Slot
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drc_name: drc-name of newly added slot
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
27826e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Make the hotplug module and the kernel aware of a newly added I/O Slot.
27926e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Return Codes:
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0			Success
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -ENODEV		Not a valid drc_name
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EINVAL		Slot already added
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -ERESTARTSYS		Signalled before obtaining lock
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EIO			Internal PCI Error
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dlpar_add_slot(char *drc_name)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct device_node *dn = NULL;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int node_type;
29056d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	int rc = -EIO;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29214cc3e2b633bb64063698980974df4535368e98fIngo Molnar	if (mutex_lock_interruptible(&rpadlpar_mutex))
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ERESTARTSYS;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2955eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	/* Find newly added node */
2965eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	dn = find_dlpar_node(drc_name, &node_type);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dn) {
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -ENODEV;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (node_type) {
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case NODE_TYPE_VIO:
30456d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			rc = dlpar_add_vio_slot(drc_name, dn);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case NODE_TYPE_SLOT:
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = dlpar_add_pci_slot(drc_name, dn);
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case NODE_TYPE_PHB:
3105eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose			rc = dlpar_add_phb(drc_name, dn);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31456d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
31614cc3e2b633bb64063698980974df4535368e98fIngo Molnar	mutex_unlock(&rpadlpar_mutex);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drc_name: drc-name of newly added slot
32326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @dn: &device_node
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
32526e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Remove the kernel and hotplug representations of an I/O Slot.
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return Codes:
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0			Success
32856d8456b06ad1316bff3c75caed5e06e786f20d8John Rose * -EINVAL		Vio dev doesn't exist
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
33056d8456b06ad1316bff3c75caed5e06e786f20d8John Rosestatic int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn)
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3325eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	struct vio_dev *vio_dev;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3345eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	vio_dev = vio_find_node(dn);
33556d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	if (!vio_dev)
33656d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EINVAL;
3375eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose
3385eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	vio_unregister_device(vio_dev);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
34326e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * dlpar_remove_pci_slot - DLPAR remove a PCI I/O Slot
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drc_name: drc-name of newly added slot
34526e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * @dn: &device_node
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
34726e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Remove the kernel and hotplug representations of a PCI I/O Slot.
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return Codes:
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0			Success
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -ENODEV		Not a valid drc_name
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EIO			Internal PCI Error
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
35356d8456b06ad1316bff3c75caed5e06e786f20d8John Roseint dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
35556d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	struct pci_bus *bus;
35656d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	struct slot *slot;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35801657868be1c21b2b8b0e683ea24bdcc2331d522Linas Vepstas	bus = pcibios_find_pci_bus(dn);
35956d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	if (!bus)
36056d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		return -EINVAL;
36156d8456b06ad1316bff3c75caed5e06e786f20d8John Rose
362fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
363fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt		 bus->self ? pci_name(bus->self) : "<!PHB!>");
364fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt
3658485d1a123e0d367bbcbfec36acf134e6895f39aLinas Vepstas	slot = find_php_slot(dn);
36656d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	if (slot) {
367fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt		pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
368fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt			 pci_domain_nr(bus), bus->number);
369fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt
370f6afbad82c6b7bab0198442592b110341fb419baLinas Vepstas		if (rpaphp_deregister_slot(slot)) {
37156d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			printk(KERN_ERR
37256d8456b06ad1316bff3c75caed5e06e786f20d8John Rose				"%s: unable to remove hotplug slot %s\n",
37366bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison				__func__, drc_name);
37456d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			return -EIO;
37556d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		}
376fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	}
377fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt
378fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	/* Remove all devices below slot */
379fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	pcibios_remove_pci_devices(bus);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	/* Unmap PCI IO space */
3823d5134ee8341bffc4f539049abb9e90d469b448dBenjamin Herrenschmidt	if (pcibios_unmap_io_space(bus)) {
3839c209c919df95f83aa042b3352c43841ad15a02bJohn Rose		printk(KERN_ERR "%s: failed to unmap bus range\n",
38466bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			__func__);
3859c209c919df95f83aa042b3352c43841ad15a02bJohn Rose		return -ERANGE;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3879c209c919df95f83aa042b3352c43841ad15a02bJohn Rose
388fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	/* Remove the EADS bridge device itself */
3899c209c919df95f83aa042b3352c43841ad15a02bJohn Rose	BUG_ON(!bus->self);
390fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
391fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt	eeh_remove_bus_device(bus->self);
392210647af897af8ef2d00828aa2a6b1b42206aae6Yinghai Lu	pci_stop_and_remove_bus_device(bus->self);
393fd6852c8fa060bd45c82a2593e18f933f6c6204fBenjamin Herrenschmidt
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dlpar_remove_slot - DLPAR remove an I/O Slot
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drc_name: drc-name of newly added slot
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
40126e6c66e47fe7f69ef6ddb078e312204a1f17823Randy Dunlap * Remove the kernel and hotplug representations of an I/O Slot.
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return Codes:
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0			Success
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -ENODEV		Not a valid drc_name
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EINVAL		Slot already removed
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -ERESTARTSYS		Signalled before obtaining lock
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EIO			Internal Error
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dlpar_remove_slot(char *drc_name)
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4115eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	struct device_node *dn;
4125eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	int node_type;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41514cc3e2b633bb64063698980974df4535368e98fIngo Molnar	if (mutex_lock_interruptible(&rpadlpar_mutex))
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ERESTARTSYS;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4185eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	dn = find_dlpar_node(drc_name, &node_type);
4195eeb8c63a38ff20285f3bbe7bcfe5e7c33c8ba14John Rose	if (!dn) {
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -ENODEV;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto exit;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42456d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	switch (node_type) {
42556d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		case NODE_TYPE_VIO:
42656d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			rc = dlpar_remove_vio_slot(drc_name, dn);
42756d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			break;
42856d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		case NODE_TYPE_PHB:
42956d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			rc = dlpar_remove_phb(drc_name, dn);
43056d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			break;
43156d8456b06ad1316bff3c75caed5e06e786f20d8John Rose		case NODE_TYPE_SLOT:
43256d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			rc = dlpar_remove_pci_slot(drc_name, dn);
43356d8456b06ad1316bff3c75caed5e06e786f20d8John Rose			break;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
435b4a26be9f6f8bb72998e445cc75fc6dc0c29513aBenjamin Herrenschmidt	vm_unmap_aliases();
436b4a26be9f6f8bb72998e445cc75fc6dc0c29513aBenjamin Herrenschmidt
43756d8456b06ad1316bff3c75caed5e06e786f20d8John Rose	printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit:
43914cc3e2b633bb64063698980974df4535368e98fIngo Molnar	mutex_unlock(&rpadlpar_mutex);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int is_dlpar_capable(void)
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = rtas_token("ibm,configure-connector");
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (int) (rc != RTAS_UNKNOWN_SERVICE);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init rpadlpar_io_init(void)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc = 0;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!is_dlpar_capable()) {
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: partition not DLPAR capable\n",
45666bef8c059015ba2b36bb5759080336feb01e680Harvey Harrison			__func__);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPERM;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = dlpar_sysfs_init();
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid rpadlpar_io_exit(void)
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dlpar_sysfs_exit();
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(rpadlpar_io_init);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(rpadlpar_io_exit);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
473