xref: /openbmc/linux/drivers/pci/hotplug/rpaphp_slot.c (revision e2413a7dae52fab290b7a8d11ec8579657bab95b)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * RPA Virtual I/O device functions
31da177e4SLinus Torvalds  * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * All rights reserved.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
81da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
91da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or (at
101da177e4SLinus Torvalds  * your option) any later version.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful, but
131da177e4SLinus Torvalds  * WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4SLinus Torvalds  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
151da177e4SLinus Torvalds  * NON INFRINGEMENT.  See the GNU General Public License for more
161da177e4SLinus Torvalds  * details.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
191da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
201da177e4SLinus Torvalds  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * Send feedback to <lxie@us.ibm.com>
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  */
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/module.h>
271da177e4SLinus Torvalds #include <linux/sysfs.h>
281da177e4SLinus Torvalds #include <linux/pci.h>
294e57b681STim Schmielau #include <linux/string.h>
304e57b681STim Schmielau #include <linux/slab.h>
314e57b681STim Schmielau 
321da177e4SLinus Torvalds #include <asm/rtas.h>
331da177e4SLinus Torvalds #include "rpaphp.h"
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds /* free up the memory used by a slot */
361da177e4SLinus Torvalds static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
371da177e4SLinus Torvalds {
381da177e4SLinus Torvalds 	struct slot *slot = (struct slot *) hotplug_slot->private;
391da177e4SLinus Torvalds 	dealloc_slot_struct(slot);
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds void dealloc_slot_struct(struct slot *slot)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->info);
45b2132fecSAlex Chiang 	kfree(slot->name);
461da177e4SLinus Torvalds 	kfree(slot->hotplug_slot);
471da177e4SLinus Torvalds 	kfree(slot);
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds 
505fd39c35SLinas Vepstas struct slot *alloc_slot_struct(struct device_node *dn,
515fd39c35SLinas Vepstas 		int drc_index, char *drc_name, int power_domain)
521da177e4SLinus Torvalds {
531da177e4SLinus Torvalds 	struct slot *slot;
541da177e4SLinus Torvalds 
55f5afe806SEric Sesterhenn 	slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
561da177e4SLinus Torvalds 	if (!slot)
571da177e4SLinus Torvalds 		goto error_nomem;
58f5afe806SEric Sesterhenn 	slot->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
591da177e4SLinus Torvalds 	if (!slot->hotplug_slot)
601da177e4SLinus Torvalds 		goto error_slot;
61f5afe806SEric Sesterhenn 	slot->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
621da177e4SLinus Torvalds 					   GFP_KERNEL);
631da177e4SLinus Torvalds 	if (!slot->hotplug_slot->info)
641da177e4SLinus Torvalds 		goto error_hpslot;
65b2132fecSAlex Chiang 	slot->name = kstrdup(drc_name, GFP_KERNEL);
66b2132fecSAlex Chiang 	if (!slot->name)
671da177e4SLinus Torvalds 		goto error_info;
681da177e4SLinus Torvalds 	slot->dn = dn;
691da177e4SLinus Torvalds 	slot->index = drc_index;
701da177e4SLinus Torvalds 	slot->power_domain = power_domain;
711da177e4SLinus Torvalds 	slot->hotplug_slot->private = slot;
721da177e4SLinus Torvalds 	slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
731da177e4SLinus Torvalds 	slot->hotplug_slot->release = &rpaphp_release_slot;
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	return (slot);
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds error_info:
781da177e4SLinus Torvalds 	kfree(slot->hotplug_slot->info);
791da177e4SLinus Torvalds error_hpslot:
801da177e4SLinus Torvalds 	kfree(slot->hotplug_slot);
811da177e4SLinus Torvalds error_slot:
821da177e4SLinus Torvalds 	kfree(slot);
831da177e4SLinus Torvalds error_nomem:
841da177e4SLinus Torvalds 	return NULL;
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds static int is_registered(struct slot *slot)
881da177e4SLinus Torvalds {
891da177e4SLinus Torvalds 	struct slot *tmp_slot;
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
921da177e4SLinus Torvalds 		if (!strcmp(tmp_slot->name, slot->name))
931da177e4SLinus Torvalds 			return 1;
941da177e4SLinus Torvalds 	}
951da177e4SLinus Torvalds 	return 0;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
98f6afbad8Slinas@austin.ibm.com int rpaphp_deregister_slot(struct slot *slot)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	int retval = 0;
1011da177e4SLinus Torvalds 	struct hotplug_slot *php_slot = slot->hotplug_slot;
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 	 dbg("%s - Entry: deregistering slot=%s\n",
10466bef8c0SHarvey Harrison 		__func__, slot->name);
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	list_del(&slot->rpaphp_slot_list);
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds 	retval = pci_hp_deregister(php_slot);
1091da177e4SLinus Torvalds 	if (retval)
1101da177e4SLinus Torvalds 		err("Problem unregistering a slot %s\n", slot->name);
1111da177e4SLinus Torvalds 
11266bef8c0SHarvey Harrison 	dbg("%s - Exit: rc[%d]\n", __func__, retval);
1131da177e4SLinus Torvalds 	return retval;
1141da177e4SLinus Torvalds }
11561ee9cd5SLinas Vepstas EXPORT_SYMBOL_GPL(rpaphp_deregister_slot);
1161da177e4SLinus Torvalds 
117f6afbad8Slinas@austin.ibm.com int rpaphp_register_slot(struct slot *slot)
1181da177e4SLinus Torvalds {
119f1e79092SLinas Vepstas 	struct hotplug_slot *php_slot = slot->hotplug_slot;
120*e2413a7dSTyrel Datwyler 	struct device_node *child;
121*e2413a7dSTyrel Datwyler 	u32 my_index;
1221da177e4SLinus Torvalds 	int retval;
123*e2413a7dSTyrel Datwyler 	int slotno = -1;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
12666bef8c0SHarvey Harrison 		__func__, slot->dn->full_name, slot->index, slot->name,
1271da177e4SLinus Torvalds 		slot->power_domain, slot->type);
128f1e79092SLinas Vepstas 
1291da177e4SLinus Torvalds 	/* should not try to register the same slot twice */
130f1e79092SLinas Vepstas 	if (is_registered(slot)) {
131f6afbad8Slinas@austin.ibm.com 		err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
1323499f072SLinas Vepstas 		return -EAGAIN;
1331da177e4SLinus Torvalds 	}
134f1e79092SLinas Vepstas 
135*e2413a7dSTyrel Datwyler 	for_each_child_of_node(slot->dn, child) {
136*e2413a7dSTyrel Datwyler 		retval = of_property_read_u32(child, "ibm,my-drc-index", &my_index);
137*e2413a7dSTyrel Datwyler 		if (my_index == slot->index) {
138*e2413a7dSTyrel Datwyler 			slotno = PCI_SLOT(PCI_DN(child)->devfn);
139*e2413a7dSTyrel Datwyler 			of_node_put(child);
140*e2413a7dSTyrel Datwyler 			break;
141*e2413a7dSTyrel Datwyler 		}
142*e2413a7dSTyrel Datwyler 	}
143*e2413a7dSTyrel Datwyler 
1441359f270SAlex Chiang 	retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name);
1451da177e4SLinus Torvalds 	if (retval) {
1461da177e4SLinus Torvalds 		err("pci_hp_register failed with error %d\n", retval);
1473499f072SLinas Vepstas 		return retval;
1481da177e4SLinus Torvalds 	}
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	/* add slot to our internal list */
1511da177e4SLinus Torvalds 	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
1521b7c9fcaSLinas Vepstas 	info("Slot [%s] registered\n", slot->name);
1531da177e4SLinus Torvalds 	return 0;
1541da177e4SLinus Torvalds }
155