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