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 */ 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 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 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 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 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