xref: /openbmc/linux/drivers/pci/hotplug/rpaphp_slot.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1736759efSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * RPA Virtual I/O device functions
41da177e4SLinus Torvalds  * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * All rights reserved.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Send feedback to <lxie@us.ibm.com>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/sysfs.h>
14*b2851926SChristophe Leroy #include <linux/of.h>
151da177e4SLinus Torvalds #include <linux/pci.h>
164e57b681STim Schmielau #include <linux/string.h>
174e57b681STim Schmielau #include <linux/slab.h>
184e57b681STim Schmielau 
191da177e4SLinus Torvalds #include <asm/rtas.h>
201da177e4SLinus Torvalds #include "rpaphp.h"
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds /* free up the memory used by a slot */
dealloc_slot_struct(struct slot * slot)231da177e4SLinus Torvalds void dealloc_slot_struct(struct slot *slot)
241da177e4SLinus Torvalds {
2591800660STyrel Datwyler 	of_node_put(slot->dn);
26b2132fecSAlex Chiang 	kfree(slot->name);
271da177e4SLinus Torvalds 	kfree(slot);
281da177e4SLinus Torvalds }
291da177e4SLinus Torvalds 
alloc_slot_struct(struct device_node * dn,int drc_index,char * drc_name,int power_domain)305fd39c35SLinas Vepstas struct slot *alloc_slot_struct(struct device_node *dn,
315fd39c35SLinas Vepstas 		int drc_index, char *drc_name, int power_domain)
321da177e4SLinus Torvalds {
331da177e4SLinus Torvalds 	struct slot *slot;
341da177e4SLinus Torvalds 
35f5afe806SEric Sesterhenn 	slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
361da177e4SLinus Torvalds 	if (!slot)
371da177e4SLinus Torvalds 		goto error_nomem;
38b2132fecSAlex Chiang 	slot->name = kstrdup(drc_name, GFP_KERNEL);
39b2132fecSAlex Chiang 	if (!slot->name)
40125450f8SLukas Wunner 		goto error_slot;
4191800660STyrel Datwyler 	slot->dn = of_node_get(dn);
421da177e4SLinus Torvalds 	slot->index = drc_index;
431da177e4SLinus Torvalds 	slot->power_domain = power_domain;
44125450f8SLukas Wunner 	slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops;
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds 	return (slot);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds error_slot:
491da177e4SLinus Torvalds 	kfree(slot);
501da177e4SLinus Torvalds error_nomem:
511da177e4SLinus Torvalds 	return NULL;
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds 
is_registered(struct slot * slot)541da177e4SLinus Torvalds static int is_registered(struct slot *slot)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds 	struct slot *tmp_slot;
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
591da177e4SLinus Torvalds 		if (!strcmp(tmp_slot->name, slot->name))
601da177e4SLinus Torvalds 			return 1;
611da177e4SLinus Torvalds 	}
621da177e4SLinus Torvalds 	return 0;
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
rpaphp_deregister_slot(struct slot * slot)65f6afbad8Slinas@austin.ibm.com int rpaphp_deregister_slot(struct slot *slot)
661da177e4SLinus Torvalds {
671da177e4SLinus Torvalds 	int retval = 0;
68125450f8SLukas Wunner 	struct hotplug_slot *php_slot = &slot->hotplug_slot;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	 dbg("%s - Entry: deregistering slot=%s\n",
7166bef8c0SHarvey Harrison 		__func__, slot->name);
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	list_del(&slot->rpaphp_slot_list);
7451bbf9beSLukas Wunner 	pci_hp_deregister(php_slot);
7551bbf9beSLukas Wunner 	dealloc_slot_struct(slot);
761da177e4SLinus Torvalds 
7766bef8c0SHarvey Harrison 	dbg("%s - Exit: rc[%d]\n", __func__, retval);
781da177e4SLinus Torvalds 	return retval;
791da177e4SLinus Torvalds }
8061ee9cd5SLinas Vepstas EXPORT_SYMBOL_GPL(rpaphp_deregister_slot);
811da177e4SLinus Torvalds 
rpaphp_register_slot(struct slot * slot)82f6afbad8Slinas@austin.ibm.com int rpaphp_register_slot(struct slot *slot)
831da177e4SLinus Torvalds {
84125450f8SLukas Wunner 	struct hotplug_slot *php_slot = &slot->hotplug_slot;
85e2413a7dSTyrel Datwyler 	struct device_node *child;
86e2413a7dSTyrel Datwyler 	u32 my_index;
871da177e4SLinus Torvalds 	int retval;
88e2413a7dSTyrel Datwyler 	int slotno = -1;
891da177e4SLinus Torvalds 
90b63773a8SRob Herring 	dbg("%s registering slot:path[%pOF] index[%x], name[%s] pdomain[%x] type[%d]\n",
91b63773a8SRob Herring 		__func__, slot->dn, slot->index, slot->name,
921da177e4SLinus Torvalds 		slot->power_domain, slot->type);
93f1e79092SLinas Vepstas 
941da177e4SLinus Torvalds 	/* should not try to register the same slot twice */
95f1e79092SLinas Vepstas 	if (is_registered(slot)) {
96f6afbad8Slinas@austin.ibm.com 		err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
973499f072SLinas Vepstas 		return -EAGAIN;
981da177e4SLinus Torvalds 	}
99f1e79092SLinas Vepstas 
100e2413a7dSTyrel Datwyler 	for_each_child_of_node(slot->dn, child) {
101e2413a7dSTyrel Datwyler 		retval = of_property_read_u32(child, "ibm,my-drc-index", &my_index);
102e2413a7dSTyrel Datwyler 		if (my_index == slot->index) {
103e2413a7dSTyrel Datwyler 			slotno = PCI_SLOT(PCI_DN(child)->devfn);
104e2413a7dSTyrel Datwyler 			of_node_put(child);
105e2413a7dSTyrel Datwyler 			break;
106e2413a7dSTyrel Datwyler 		}
107e2413a7dSTyrel Datwyler 	}
108e2413a7dSTyrel Datwyler 
1091359f270SAlex Chiang 	retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name);
1101da177e4SLinus Torvalds 	if (retval) {
1111da177e4SLinus Torvalds 		err("pci_hp_register failed with error %d\n", retval);
1123499f072SLinas Vepstas 		return retval;
1131da177e4SLinus Torvalds 	}
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds 	/* add slot to our internal list */
1161da177e4SLinus Torvalds 	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
1171b7c9fcaSLinas Vepstas 	info("Slot [%s] registered\n", slot->name);
1181da177e4SLinus Torvalds 	return 0;
1191da177e4SLinus Torvalds }
120