1184902Srwatson// SPDX-License-Identifier: GPL-2.0+
2191273Srwatson/*
3184902Srwatson * Interface for Dynamic Logical Partitioning of I/O Slots on
4184902Srwatson * RPA-compliant PPC64 platform.
5184902Srwatson *
6184902Srwatson * John Rose <johnrose@austin.ibm.com>
7184902Srwatson * Linda Xie <lxie@us.ibm.com>
8184902Srwatson *
9184902Srwatson * October 2003
10184902Srwatson *
11184902Srwatson * Copyright (C) 2003 IBM.
12184902Srwatson */
13184902Srwatson
14184902Srwatson#undef DEBUG
15184902Srwatson
16184902Srwatson#include <linux/init.h>
17184902Srwatson#include <linux/module.h>
18184902Srwatson#include <linux/of.h>
19184902Srwatson#include <linux/pci.h>
20184902Srwatson#include <linux/string.h>
21184902Srwatson#include <linux/vmalloc.h>
22184902Srwatson
23184902Srwatson#include <asm/pci-bridge.h>
24184902Srwatson#include <linux/mutex.h>
25184902Srwatson#include <asm/rtas.h>
26184902Srwatson#include <asm/vio.h>
27184902Srwatson#include <linux/firmware.h>
28184902Srwatson
29244265Srwatson#include "../pci.h"
30184902Srwatson#include "rpaphp.h"
31184902Srwatson#include "rpadlpar.h"
32184902Srwatson
33184902Srwatsonstatic DEFINE_MUTEX(rpadlpar_mutex);
34184902Srwatson
35184902Srwatson#define DLPAR_MODULE_NAME "rpadlpar_io"
36191273Srwatson
37191273Srwatson#define NODE_TYPE_VIO  1
38191273Srwatson#define NODE_TYPE_SLOT 2
39191273Srwatson#define NODE_TYPE_PHB  3
40191273Srwatson
41191273Srwatsonstatic struct device_node *find_vio_slot_node(char *drc_name)
42184902Srwatson{
43184902Srwatson	struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
44184902Srwatson	struct device_node *dn;
45184902Srwatson	int rc;
46184902Srwatson
47184902Srwatson	if (!parent)
48184902Srwatson		return NULL;
49184902Srwatson
50184902Srwatson	for_each_child_of_node(parent, dn) {
51184902Srwatson		rc = rpaphp_check_drc_props(dn, drc_name, NULL);
52184902Srwatson		if (rc == 0)
53184902Srwatson			break;
54184902Srwatson	}
55184902Srwatson	of_node_put(parent);
56184902Srwatson
57184902Srwatson	return dn;
58184902Srwatson}
59184902Srwatson
60184902Srwatson/* Find dlpar-capable pci node that contains the specified name and type */
61184902Srwatsonstatic struct device_node *find_php_slot_pci_node(char *drc_name,
62184902Srwatson						  char *drc_type)
63184902Srwatson{
64184902Srwatson	struct device_node *np;
65184902Srwatson	int rc;
66184902Srwatson
67184902Srwatson	for_each_node_by_name(np, "pci") {
68184902Srwatson		rc = rpaphp_check_drc_props(np, drc_name, drc_type);
69184902Srwatson		if (rc == 0)
70184902Srwatson			break;
71184902Srwatson	}
72184902Srwatson
73184902Srwatson	return np;
74184902Srwatson}
75184902Srwatson
76184902Srwatson/* Returns a device_node with its reference count incremented */
77184902Srwatsonstatic struct device_node *find_dlpar_node(char *drc_name, int *node_type)
78184902Srwatson{
79184902Srwatson	struct device_node *dn;
80184902Srwatson
81184902Srwatson	dn = find_php_slot_pci_node(drc_name, "SLOT");
82184902Srwatson	if (dn) {
83184902Srwatson		*node_type = NODE_TYPE_SLOT;
84184902Srwatson		return dn;
85184902Srwatson	}
86184902Srwatson
87184902Srwatson	dn = find_php_slot_pci_node(drc_name, "PHB");
88184902Srwatson	if (dn) {
89184902Srwatson		*node_type = NODE_TYPE_PHB;
90184902Srwatson		return dn;
91184902Srwatson	}
92184902Srwatson
93184902Srwatson	dn = find_vio_slot_node(drc_name);
94184902Srwatson	if (dn) {
95184902Srwatson		*node_type = NODE_TYPE_VIO;
96184902Srwatson		return dn;
97184902Srwatson	}
98184902Srwatson
99184902Srwatson	return NULL;
100184902Srwatson}
101184902Srwatson
102184902Srwatson/**
103184902Srwatson * find_php_slot - return hotplug slot structure for device node
104184902Srwatson * @dn: target &device_node
105184902Srwatson *
106184902Srwatson * This routine will return the hotplug slot structure
107184902Srwatson * for a given device node. Note that built-in PCI slots
108184902Srwatson * may be dlpar-able, but not hot-pluggable, so this routine
109184902Srwatson * will return NULL for built-in PCI slots.
110184902Srwatson */
111184902Srwatsonstatic struct slot *find_php_slot(struct device_node *dn)
112184902Srwatson{
113184902Srwatson	struct slot *slot, *next;
114184902Srwatson
115184902Srwatson	list_for_each_entry_safe(slot, next, &rpaphp_slot_head,
116184902Srwatson				 rpaphp_slot_list) {
117184902Srwatson		if (slot->dn == dn)
118184902Srwatson			return slot;
119184902Srwatson	}
120184902Srwatson
121184902Srwatson	return NULL;
122184902Srwatson}
123184902Srwatson
124184902Srwatsonstatic struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
125184902Srwatson					struct device_node *dev_dn)
126184902Srwatson{
127184902Srwatson	struct pci_dev *tmp = NULL;
128184902Srwatson	struct device_node *child_dn;
129184902Srwatson
130184902Srwatson	list_for_each_entry(tmp, &parent->devices, bus_list) {
131184902Srwatson		child_dn = pci_device_to_OF_node(tmp);
132184902Srwatson		if (child_dn == dev_dn)
133184902Srwatson			return tmp;
134184902Srwatson	}
135184902Srwatson	return NULL;
136184902Srwatson}
137184902Srwatson
138184902Srwatsonstatic void dlpar_pci_add_bus(struct device_node *dn)
139184902Srwatson{
140184902Srwatson	struct pci_dn *pdn = PCI_DN(dn);
141184902Srwatson	struct pci_controller *phb = pdn->phb;
142184902Srwatson	struct pci_dev *dev = NULL;
143184902Srwatson
144184902Srwatson	pseries_eeh_init_edev_recursive(pdn);
145184902Srwatson
146184902Srwatson	/* Add EADS device to PHB bus, adding new entry to bus->devices */
147184902Srwatson	dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
148184902Srwatson	if (!dev) {
149184902Srwatson		printk(KERN_ERR "%s: failed to create pci dev for %pOF\n",
150184902Srwatson				__func__, dn);
151184902Srwatson		return;
152184902Srwatson	}
153184902Srwatson
154184902Srwatson	/* Scan below the new bridge */
155184902Srwatson	if (pci_is_bridge(dev))
156184902Srwatson		of_scan_pci_bridge(dev);
157184902Srwatson
158184902Srwatson	/* Map IO space for child bus, which may or may not succeed */
159184902Srwatson	pcibios_map_io_space(dev->subordinate);
160184902Srwatson
161184902Srwatson	/* Finish adding it : resource allocation, adding devices, etc...
162184902Srwatson	 * Note that we need to perform the finish pass on the -parent-
163184902Srwatson	 * bus of the EADS bridge so the bridge device itself gets
164184902Srwatson	 * properly added
165184902Srwatson	 */
166184902Srwatson	pcibios_finish_adding_to_bus(phb->bus);
167184902Srwatson}
168184902Srwatson
169184902Srwatsonstatic int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
170184902Srwatson{
171184902Srwatson	struct pci_dev *dev;
172184902Srwatson	struct pci_controller *phb;
173184902Srwatson
174184902Srwatson	if (pci_find_bus_by_node(dn))
175184902Srwatson		return -EINVAL;
176184902Srwatson
177184902Srwatson	/* Add pci bus */
178184902Srwatson	dlpar_pci_add_bus(dn);
179184902Srwatson
180184902Srwatson	/* Confirm new bridge dev was created */
181184902Srwatson	phb = PCI_DN(dn)->phb;
182184902Srwatson	dev = dlpar_find_new_dev(phb->bus, dn);
183184902Srwatson
184184902Srwatson	if (!dev) {
185184902Srwatson		printk(KERN_ERR "%s: unable to add bus %s\n", __func__,
186184902Srwatson			drc_name);
187184902Srwatson		return -EIO;
188184902Srwatson	}
189184902Srwatson
190184902Srwatson	if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
191184902Srwatson		printk(KERN_ERR "%s: unexpected header type %d, unable to add bus %s\n",
192184902Srwatson			__func__, dev->hdr_type, drc_name);
193184902Srwatson		return -EIO;
194184902Srwatson	}
195184902Srwatson
196184902Srwatson	/* Add hotplug slot */
197184902Srwatson	if (rpaphp_add_slot(dn)) {
198184902Srwatson		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
199184902Srwatson			__func__, drc_name);
200184902Srwatson		return -EIO;
201184902Srwatson	}
202184902Srwatson	return 0;
203184902Srwatson}
204184902Srwatson
205184902Srwatsonstatic int dlpar_remove_phb(char *drc_name, struct device_node *dn)
206184902Srwatson{
207184902Srwatson	struct slot *slot;
208184902Srwatson	struct pci_dn *pdn;
209184902Srwatson	int rc = 0;
210184902Srwatson
211184902Srwatson	if (!pci_find_bus_by_node(dn))
212184902Srwatson		return -EINVAL;
213184902Srwatson
214184902Srwatson	/* If pci slot is hotpluggable, use hotplug to remove it */
215184902Srwatson	slot = find_php_slot(dn);
216184902Srwatson	if (slot && rpaphp_deregister_slot(slot)) {
217184902Srwatson		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
218184902Srwatson		       __func__, drc_name);
219184902Srwatson		return -EIO;
220184902Srwatson	}
221184902Srwatson
222184902Srwatson	pdn = dn->data;
223184902Srwatson	BUG_ON(!pdn || !pdn->phb);
224184902Srwatson	rc = remove_phb_dynamic(pdn->phb);
225184902Srwatson	if (rc < 0)
226184902Srwatson		return rc;
227184902Srwatson
228184902Srwatson	pdn->phb = NULL;
229184902Srwatson
230184902Srwatson	return 0;
231184902Srwatson}
232184902Srwatson
233184902Srwatsonstatic int dlpar_add_phb(char *drc_name, struct device_node *dn)
234184902Srwatson{
235184902Srwatson	struct pci_controller *phb;
236184902Srwatson
237184902Srwatson	if (PCI_DN(dn) && PCI_DN(dn)->phb) {
238184902Srwatson		/* PHB already exists */
239184902Srwatson		return -EINVAL;
240184902Srwatson	}
241184902Srwatson
242184902Srwatson	phb = init_phb_dynamic(dn);
243184902Srwatson	if (!phb)
244184902Srwatson		return -EIO;
245184902Srwatson
246184902Srwatson	if (rpaphp_add_slot(dn)) {
247184902Srwatson		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
248184902Srwatson			__func__, drc_name);
249184902Srwatson		return -EIO;
250184902Srwatson	}
251184902Srwatson	return 0;
252184902Srwatson}
253184902Srwatson
254184902Srwatsonstatic int dlpar_add_vio_slot(char *drc_name, struct device_node *dn)
255184902Srwatson{
256184902Srwatson	struct vio_dev *vio_dev;
257184902Srwatson
258184902Srwatson	vio_dev = vio_find_node(dn);
259184902Srwatson	if (vio_dev) {
260184902Srwatson		put_device(&vio_dev->dev);
261184902Srwatson		return -EINVAL;
262184902Srwatson	}
263184902Srwatson
264184902Srwatson	if (!vio_register_device_node(dn)) {
265184902Srwatson		printk(KERN_ERR
266184902Srwatson			"%s: failed to register vio node %s\n",
267184902Srwatson			__func__, drc_name);
268184902Srwatson		return -EIO;
269184902Srwatson	}
270184902Srwatson	return 0;
271184902Srwatson}
272184902Srwatson
273184902Srwatson/**
274184902Srwatson * dlpar_add_slot - DLPAR add an I/O Slot
275184902Srwatson * @drc_name: drc-name of newly added slot
276184902Srwatson *
277184902Srwatson * Make the hotplug module and the kernel aware of a newly added I/O Slot.
278184902Srwatson * Return Codes:
279184902Srwatson * 0			Success
280184902Srwatson * -ENODEV		Not a valid drc_name
281184902Srwatson * -EINVAL		Slot already added
282184902Srwatson * -ERESTARTSYS		Signalled before obtaining lock
283184902Srwatson * -EIO			Internal PCI Error
284184902Srwatson */
285184902Srwatsonint dlpar_add_slot(char *drc_name)
286184902Srwatson{
287184902Srwatson	struct device_node *dn = NULL;
288184902Srwatson	int node_type;
289184902Srwatson	int rc = -EIO;
290184902Srwatson
291184902Srwatson	if (mutex_lock_interruptible(&rpadlpar_mutex))
292184902Srwatson		return -ERESTARTSYS;
293184902Srwatson
294184902Srwatson	/* Find newly added node */
295184902Srwatson	dn = find_dlpar_node(drc_name, &node_type);
296184902Srwatson	if (!dn) {
297184902Srwatson		rc = -ENODEV;
298184902Srwatson		goto exit;
299184902Srwatson	}
300184902Srwatson
301184902Srwatson	switch (node_type) {
302184902Srwatson		case NODE_TYPE_VIO:
303184902Srwatson			rc = dlpar_add_vio_slot(drc_name, dn);
304184902Srwatson			break;
305184902Srwatson		case NODE_TYPE_SLOT:
306184902Srwatson			rc = dlpar_add_pci_slot(drc_name, dn);
307184902Srwatson			break;
308184902Srwatson		case NODE_TYPE_PHB:
309184902Srwatson			rc = dlpar_add_phb(drc_name, dn);
310184902Srwatson			break;
311184902Srwatson	}
312184902Srwatson	of_node_put(dn);
313184902Srwatson
314184902Srwatson	printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
315184902Srwatsonexit:
316184902Srwatson	mutex_unlock(&rpadlpar_mutex);
317184902Srwatson	return rc;
318184902Srwatson}
319184902Srwatson
320184902Srwatson/**
321184902Srwatson * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
322184902Srwatson * @drc_name: drc-name of newly added slot
323184902Srwatson * @dn: &device_node
324184902Srwatson *
325184902Srwatson * Remove the kernel and hotplug representations of an I/O Slot.
326184902Srwatson * Return Codes:
327184902Srwatson * 0			Success
328184902Srwatson * -EINVAL		Vio dev doesn't exist
329184902Srwatson */
330184902Srwatsonstatic int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn)
331184902Srwatson{
332184902Srwatson	struct vio_dev *vio_dev;
333184902Srwatson
334184902Srwatson	vio_dev = vio_find_node(dn);
335184902Srwatson	if (!vio_dev)
336184902Srwatson		return -EINVAL;
337184902Srwatson
338184902Srwatson	vio_unregister_device(vio_dev);
339184902Srwatson
340184902Srwatson	put_device(&vio_dev->dev);
341184902Srwatson
342184902Srwatson	return 0;
343184902Srwatson}
344184902Srwatson
345184902Srwatson/**
346184902Srwatson * dlpar_remove_pci_slot - DLPAR remove a PCI I/O Slot
347184902Srwatson * @drc_name: drc-name of newly added slot
348184902Srwatson * @dn: &device_node
349184902Srwatson *
350184902Srwatson * Remove the kernel and hotplug representations of a PCI I/O Slot.
351184902Srwatson * Return Codes:
352184902Srwatson * 0			Success
353184902Srwatson * -ENODEV		Not a valid drc_name
354184902Srwatson * -EIO			Internal PCI Error
355184902Srwatson */
356184902Srwatsonstatic int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
357184902Srwatson{
358184902Srwatson	struct pci_bus *bus;
359184902Srwatson	struct slot *slot;
360184902Srwatson	int ret = 0;
361184902Srwatson
362184902Srwatson	pci_lock_rescan_remove();
363184902Srwatson
364184902Srwatson	bus = pci_find_bus_by_node(dn);
365184902Srwatson	if (!bus) {
366184902Srwatson		ret = -EINVAL;
367184902Srwatson		goto out;
368184902Srwatson	}
369184902Srwatson
370184902Srwatson	pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
371184902Srwatson		 bus->self ? pci_name(bus->self) : "<!PHB!>");
372184902Srwatson
373184902Srwatson	slot = find_php_slot(dn);
374184902Srwatson	if (slot) {
375184902Srwatson		pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
376184902Srwatson			 pci_domain_nr(bus), bus->number);
377184902Srwatson
378184902Srwatson		if (rpaphp_deregister_slot(slot)) {
379184902Srwatson			printk(KERN_ERR
380184902Srwatson				"%s: unable to remove hotplug slot %s\n",
381184902Srwatson				__func__, drc_name);
382184902Srwatson			ret = -EIO;
383184902Srwatson			goto out;
384184902Srwatson		}
385184902Srwatson	}
386184902Srwatson
387184902Srwatson	/* Remove all devices below slot */
388184902Srwatson	pci_hp_remove_devices(bus);
389184902Srwatson
390184902Srwatson	/* Unmap PCI IO space */
391184902Srwatson	if (pcibios_unmap_io_space(bus)) {
392184902Srwatson		printk(KERN_ERR "%s: failed to unmap bus range\n",
393184902Srwatson			__func__);
394184902Srwatson		ret = -ERANGE;
395184902Srwatson		goto out;
396184902Srwatson	}
397184902Srwatson
398184902Srwatson	/* Remove the EADS bridge device itself */
399184902Srwatson	BUG_ON(!bus->self);
400184902Srwatson	pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
401184902Srwatson	pci_stop_and_remove_bus_device(bus->self);
402184902Srwatson
403184902Srwatson out:
404184902Srwatson	pci_unlock_rescan_remove();
405184902Srwatson	return ret;
406184902Srwatson}
407184902Srwatson
408184902Srwatson/**
409184902Srwatson * dlpar_remove_slot - DLPAR remove an I/O Slot
410184902Srwatson * @drc_name: drc-name of newly added slot
411184902Srwatson *
412184902Srwatson * Remove the kernel and hotplug representations of an I/O Slot.
413184902Srwatson * Return Codes:
414184902Srwatson * 0			Success
415184902Srwatson * -ENODEV		Not a valid drc_name
416184902Srwatson * -EINVAL		Slot already removed
417184902Srwatson * -ERESTARTSYS		Signalled before obtaining lock
418184902Srwatson * -EIO			Internal Error
419184902Srwatson */
420184902Srwatsonint dlpar_remove_slot(char *drc_name)
421184902Srwatson{
422184902Srwatson	struct device_node *dn;
423184902Srwatson	int node_type;
424184902Srwatson	int rc = 0;
425184902Srwatson
426184902Srwatson	if (mutex_lock_interruptible(&rpadlpar_mutex))
427184902Srwatson		return -ERESTARTSYS;
428184902Srwatson
429184902Srwatson	dn = find_dlpar_node(drc_name, &node_type);
430184902Srwatson	if (!dn) {
431184902Srwatson		rc = -ENODEV;
432184902Srwatson		goto exit;
433184902Srwatson	}
434184902Srwatson
435184902Srwatson	switch (node_type) {
436184902Srwatson		case NODE_TYPE_VIO:
437184902Srwatson			rc = dlpar_remove_vio_slot(drc_name, dn);
438184902Srwatson			break;
439184902Srwatson		case NODE_TYPE_PHB:
440184902Srwatson			rc = dlpar_remove_phb(drc_name, dn);
441184902Srwatson			break;
442184902Srwatson		case NODE_TYPE_SLOT:
443184902Srwatson			rc = dlpar_remove_pci_slot(drc_name, dn);
444184902Srwatson			break;
445184902Srwatson	}
446184902Srwatson	of_node_put(dn);
447184902Srwatson	vm_unmap_aliases();
448184902Srwatson
449184902Srwatson	printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
450184902Srwatsonexit:
451184902Srwatson	mutex_unlock(&rpadlpar_mutex);
452184902Srwatson	return rc;
453184902Srwatson}
454184902Srwatson
455184902Srwatsonstatic inline int is_dlpar_capable(void)
456184902Srwatson{
457184902Srwatson	int rc = rtas_token("ibm,configure-connector");
458184902Srwatson
459184902Srwatson	return (int) (rc != RTAS_UNKNOWN_SERVICE);
460184902Srwatson}
461184902Srwatson
462184902Srwatsonstatic int __init rpadlpar_io_init(void)
463184902Srwatson{
464184902Srwatson
465184902Srwatson	if (!is_dlpar_capable()) {
466184902Srwatson		printk(KERN_WARNING "%s: partition not DLPAR capable\n",
467184902Srwatson			__func__);
468184902Srwatson		return -EPERM;
469184902Srwatson	}
470184902Srwatson
471184902Srwatson	return dlpar_sysfs_init();
472184902Srwatson}
473184902Srwatson
474184902Srwatsonstatic void __exit rpadlpar_io_exit(void)
475184902Srwatson{
476184902Srwatson	dlpar_sysfs_exit();
477184902Srwatson}
478184902Srwatson
479184902Srwatsonmodule_init(rpadlpar_io_init);
480184902Srwatsonmodule_exit(rpadlpar_io_exit);
481184902SrwatsonMODULE_LICENSE("GPL");
482184902SrwatsonMODULE_DESCRIPTION("RPA Dynamic Logical Partitioning driver for I/O slots");
483184902Srwatson