xref: /openbmc/linux/drivers/pci/hotplug/rpaphp_slot.c (revision 125450f814418b9f889c9885831467d1b2e25a7d)
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>
141da177e4SLinus Torvalds #include <linux/pci.h>
154e57b681STim Schmielau #include <linux/string.h>
164e57b681STim Schmielau #include <linux/slab.h>
174e57b681STim Schmielau 
181da177e4SLinus Torvalds #include <asm/rtas.h>
191da177e4SLinus Torvalds #include "rpaphp.h"
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds /* free up the memory used by a slot */
221da177e4SLinus Torvalds void dealloc_slot_struct(struct slot *slot)
231da177e4SLinus Torvalds {
24b2132fecSAlex Chiang 	kfree(slot->name);
251da177e4SLinus Torvalds 	kfree(slot);
261da177e4SLinus Torvalds }
271da177e4SLinus Torvalds 
285fd39c35SLinas Vepstas struct slot *alloc_slot_struct(struct device_node *dn,
295fd39c35SLinas Vepstas 		int drc_index, char *drc_name, int power_domain)
301da177e4SLinus Torvalds {
311da177e4SLinus Torvalds 	struct slot *slot;
321da177e4SLinus Torvalds 
33f5afe806SEric Sesterhenn 	slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
341da177e4SLinus Torvalds 	if (!slot)
351da177e4SLinus Torvalds 		goto error_nomem;
36b2132fecSAlex Chiang 	slot->name = kstrdup(drc_name, GFP_KERNEL);
37b2132fecSAlex Chiang 	if (!slot->name)
38*125450f8SLukas Wunner 		goto error_slot;
391da177e4SLinus Torvalds 	slot->dn = dn;
401da177e4SLinus Torvalds 	slot->index = drc_index;
411da177e4SLinus Torvalds 	slot->power_domain = power_domain;
42*125450f8SLukas Wunner 	slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops;
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds 	return (slot);
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds error_slot:
471da177e4SLinus Torvalds 	kfree(slot);
481da177e4SLinus Torvalds error_nomem:
491da177e4SLinus Torvalds 	return NULL;
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds static int is_registered(struct slot *slot)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds 	struct slot *tmp_slot;
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 	list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
571da177e4SLinus Torvalds 		if (!strcmp(tmp_slot->name, slot->name))
581da177e4SLinus Torvalds 			return 1;
591da177e4SLinus Torvalds 	}
601da177e4SLinus Torvalds 	return 0;
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
63f6afbad8Slinas@austin.ibm.com int rpaphp_deregister_slot(struct slot *slot)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	int retval = 0;
66*125450f8SLukas Wunner 	struct hotplug_slot *php_slot = &slot->hotplug_slot;
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	 dbg("%s - Entry: deregistering slot=%s\n",
6966bef8c0SHarvey Harrison 		__func__, slot->name);
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	list_del(&slot->rpaphp_slot_list);
7251bbf9beSLukas Wunner 	pci_hp_deregister(php_slot);
7351bbf9beSLukas Wunner 	dealloc_slot_struct(slot);
741da177e4SLinus Torvalds 
7566bef8c0SHarvey Harrison 	dbg("%s - Exit: rc[%d]\n", __func__, retval);
761da177e4SLinus Torvalds 	return retval;
771da177e4SLinus Torvalds }
7861ee9cd5SLinas Vepstas EXPORT_SYMBOL_GPL(rpaphp_deregister_slot);
791da177e4SLinus Torvalds 
80f6afbad8Slinas@austin.ibm.com int rpaphp_register_slot(struct slot *slot)
811da177e4SLinus Torvalds {
82*125450f8SLukas Wunner 	struct hotplug_slot *php_slot = &slot->hotplug_slot;
83e2413a7dSTyrel Datwyler 	struct device_node *child;
84e2413a7dSTyrel Datwyler 	u32 my_index;
851da177e4SLinus Torvalds 	int retval;
86e2413a7dSTyrel Datwyler 	int slotno = -1;
871da177e4SLinus Torvalds 
88b63773a8SRob Herring 	dbg("%s registering slot:path[%pOF] index[%x], name[%s] pdomain[%x] type[%d]\n",
89b63773a8SRob Herring 		__func__, slot->dn, slot->index, slot->name,
901da177e4SLinus Torvalds 		slot->power_domain, slot->type);
91f1e79092SLinas Vepstas 
921da177e4SLinus Torvalds 	/* should not try to register the same slot twice */
93f1e79092SLinas Vepstas 	if (is_registered(slot)) {
94f6afbad8Slinas@austin.ibm.com 		err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
953499f072SLinas Vepstas 		return -EAGAIN;
961da177e4SLinus Torvalds 	}
97f1e79092SLinas Vepstas 
98e2413a7dSTyrel Datwyler 	for_each_child_of_node(slot->dn, child) {
99e2413a7dSTyrel Datwyler 		retval = of_property_read_u32(child, "ibm,my-drc-index", &my_index);
100e2413a7dSTyrel Datwyler 		if (my_index == slot->index) {
101e2413a7dSTyrel Datwyler 			slotno = PCI_SLOT(PCI_DN(child)->devfn);
102e2413a7dSTyrel Datwyler 			of_node_put(child);
103e2413a7dSTyrel Datwyler 			break;
104e2413a7dSTyrel Datwyler 		}
105e2413a7dSTyrel Datwyler 	}
106e2413a7dSTyrel Datwyler 
1071359f270SAlex Chiang 	retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name);
1081da177e4SLinus Torvalds 	if (retval) {
1091da177e4SLinus Torvalds 		err("pci_hp_register failed with error %d\n", retval);
1103499f072SLinas Vepstas 		return retval;
1111da177e4SLinus Torvalds 	}
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	/* add slot to our internal list */
1141da177e4SLinus Torvalds 	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
1151b7c9fcaSLinas Vepstas 	info("Slot [%s] registered\n", slot->name);
1161da177e4SLinus Torvalds 	return 0;
1171da177e4SLinus Torvalds }
118