1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * RPA Virtual I/O device functions 3*1da177e4SLinus Torvalds * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com> 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * All rights reserved. 6*1da177e4SLinus Torvalds * 7*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 8*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 9*1da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at 10*1da177e4SLinus Torvalds * your option) any later version. 11*1da177e4SLinus Torvalds * 12*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, but 13*1da177e4SLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 14*1da177e4SLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 15*1da177e4SLinus Torvalds * NON INFRINGEMENT. See the GNU General Public License for more 16*1da177e4SLinus Torvalds * details. 17*1da177e4SLinus Torvalds * 18*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 19*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 20*1da177e4SLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*1da177e4SLinus Torvalds * 22*1da177e4SLinus Torvalds * Send feedback to <lxie@us.ibm.com> 23*1da177e4SLinus Torvalds * 24*1da177e4SLinus Torvalds */ 25*1da177e4SLinus Torvalds #include <linux/kernel.h> 26*1da177e4SLinus Torvalds #include <linux/module.h> 27*1da177e4SLinus Torvalds #include <linux/kobject.h> 28*1da177e4SLinus Torvalds #include <linux/sysfs.h> 29*1da177e4SLinus Torvalds #include <linux/pci.h> 30*1da177e4SLinus Torvalds #include <asm/rtas.h> 31*1da177e4SLinus Torvalds #include "rpaphp.h" 32*1da177e4SLinus Torvalds 33*1da177e4SLinus Torvalds static ssize_t removable_read_file (struct hotplug_slot *php_slot, char *buf) 34*1da177e4SLinus Torvalds { 35*1da177e4SLinus Torvalds u8 value; 36*1da177e4SLinus Torvalds int retval = -ENOENT; 37*1da177e4SLinus Torvalds struct slot *slot = (struct slot *)php_slot->private; 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds if (!slot) 40*1da177e4SLinus Torvalds return retval; 41*1da177e4SLinus Torvalds 42*1da177e4SLinus Torvalds value = slot->removable; 43*1da177e4SLinus Torvalds retval = sprintf (buf, "%d\n", value); 44*1da177e4SLinus Torvalds return retval; 45*1da177e4SLinus Torvalds } 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds static struct hotplug_slot_attribute hotplug_slot_attr_removable = { 48*1da177e4SLinus Torvalds .attr = {.name = "phy_removable", .mode = S_IFREG | S_IRUGO}, 49*1da177e4SLinus Torvalds .show = removable_read_file, 50*1da177e4SLinus Torvalds }; 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds static void rpaphp_sysfs_add_attr_removable (struct hotplug_slot *slot) 53*1da177e4SLinus Torvalds { 54*1da177e4SLinus Torvalds sysfs_create_file(&slot->kobj, &hotplug_slot_attr_removable.attr); 55*1da177e4SLinus Torvalds } 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds static void rpaphp_sysfs_remove_attr_removable (struct hotplug_slot *slot) 58*1da177e4SLinus Torvalds { 59*1da177e4SLinus Torvalds sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_removable.attr); 60*1da177e4SLinus Torvalds } 61*1da177e4SLinus Torvalds 62*1da177e4SLinus Torvalds static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf) 63*1da177e4SLinus Torvalds { 64*1da177e4SLinus Torvalds char *value; 65*1da177e4SLinus Torvalds int retval = -ENOENT; 66*1da177e4SLinus Torvalds struct slot *slot = (struct slot *)php_slot->private; 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds if (!slot) 69*1da177e4SLinus Torvalds return retval; 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds value = slot->location; 72*1da177e4SLinus Torvalds retval = sprintf (buf, "%s\n", value); 73*1da177e4SLinus Torvalds return retval; 74*1da177e4SLinus Torvalds } 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds static struct hotplug_slot_attribute hotplug_slot_attr_location = { 77*1da177e4SLinus Torvalds .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO}, 78*1da177e4SLinus Torvalds .show = location_read_file, 79*1da177e4SLinus Torvalds }; 80*1da177e4SLinus Torvalds 81*1da177e4SLinus Torvalds static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot) 82*1da177e4SLinus Torvalds { 83*1da177e4SLinus Torvalds sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr); 84*1da177e4SLinus Torvalds } 85*1da177e4SLinus Torvalds 86*1da177e4SLinus Torvalds static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot) 87*1da177e4SLinus Torvalds { 88*1da177e4SLinus Torvalds sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr); 89*1da177e4SLinus Torvalds } 90*1da177e4SLinus Torvalds 91*1da177e4SLinus Torvalds /* free up the memory used by a slot */ 92*1da177e4SLinus Torvalds static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) 93*1da177e4SLinus Torvalds { 94*1da177e4SLinus Torvalds struct slot *slot = (struct slot *) hotplug_slot->private; 95*1da177e4SLinus Torvalds 96*1da177e4SLinus Torvalds dealloc_slot_struct(slot); 97*1da177e4SLinus Torvalds } 98*1da177e4SLinus Torvalds 99*1da177e4SLinus Torvalds void dealloc_slot_struct(struct slot *slot) 100*1da177e4SLinus Torvalds { 101*1da177e4SLinus Torvalds kfree(slot->hotplug_slot->info); 102*1da177e4SLinus Torvalds kfree(slot->hotplug_slot->name); 103*1da177e4SLinus Torvalds kfree(slot->hotplug_slot); 104*1da177e4SLinus Torvalds kfree(slot); 105*1da177e4SLinus Torvalds return; 106*1da177e4SLinus Torvalds } 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, 109*1da177e4SLinus Torvalds int power_domain) 110*1da177e4SLinus Torvalds { 111*1da177e4SLinus Torvalds struct slot *slot; 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds slot = kmalloc(sizeof (struct slot), GFP_KERNEL); 114*1da177e4SLinus Torvalds if (!slot) 115*1da177e4SLinus Torvalds goto error_nomem; 116*1da177e4SLinus Torvalds memset(slot, 0, sizeof (struct slot)); 117*1da177e4SLinus Torvalds slot->hotplug_slot = kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); 118*1da177e4SLinus Torvalds if (!slot->hotplug_slot) 119*1da177e4SLinus Torvalds goto error_slot; 120*1da177e4SLinus Torvalds memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); 121*1da177e4SLinus Torvalds slot->hotplug_slot->info = kmalloc(sizeof (struct hotplug_slot_info), 122*1da177e4SLinus Torvalds GFP_KERNEL); 123*1da177e4SLinus Torvalds if (!slot->hotplug_slot->info) 124*1da177e4SLinus Torvalds goto error_hpslot; 125*1da177e4SLinus Torvalds memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); 126*1da177e4SLinus Torvalds slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL); 127*1da177e4SLinus Torvalds if (!slot->hotplug_slot->name) 128*1da177e4SLinus Torvalds goto error_info; 129*1da177e4SLinus Torvalds slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); 130*1da177e4SLinus Torvalds if (!slot->location) 131*1da177e4SLinus Torvalds goto error_name; 132*1da177e4SLinus Torvalds slot->name = slot->hotplug_slot->name; 133*1da177e4SLinus Torvalds slot->dn = dn; 134*1da177e4SLinus Torvalds slot->index = drc_index; 135*1da177e4SLinus Torvalds strcpy(slot->location, drc_name); 136*1da177e4SLinus Torvalds slot->power_domain = power_domain; 137*1da177e4SLinus Torvalds slot->hotplug_slot->private = slot; 138*1da177e4SLinus Torvalds slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops; 139*1da177e4SLinus Torvalds slot->hotplug_slot->release = &rpaphp_release_slot; 140*1da177e4SLinus Torvalds 141*1da177e4SLinus Torvalds return (slot); 142*1da177e4SLinus Torvalds 143*1da177e4SLinus Torvalds error_name: 144*1da177e4SLinus Torvalds kfree(slot->hotplug_slot->name); 145*1da177e4SLinus Torvalds error_info: 146*1da177e4SLinus Torvalds kfree(slot->hotplug_slot->info); 147*1da177e4SLinus Torvalds error_hpslot: 148*1da177e4SLinus Torvalds kfree(slot->hotplug_slot); 149*1da177e4SLinus Torvalds error_slot: 150*1da177e4SLinus Torvalds kfree(slot); 151*1da177e4SLinus Torvalds error_nomem: 152*1da177e4SLinus Torvalds return NULL; 153*1da177e4SLinus Torvalds } 154*1da177e4SLinus Torvalds 155*1da177e4SLinus Torvalds static int is_registered(struct slot *slot) 156*1da177e4SLinus Torvalds { 157*1da177e4SLinus Torvalds struct slot *tmp_slot; 158*1da177e4SLinus Torvalds 159*1da177e4SLinus Torvalds list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) { 160*1da177e4SLinus Torvalds if (!strcmp(tmp_slot->name, slot->name)) 161*1da177e4SLinus Torvalds return 1; 162*1da177e4SLinus Torvalds } 163*1da177e4SLinus Torvalds return 0; 164*1da177e4SLinus Torvalds } 165*1da177e4SLinus Torvalds 166*1da177e4SLinus Torvalds int deregister_slot(struct slot *slot) 167*1da177e4SLinus Torvalds { 168*1da177e4SLinus Torvalds int retval = 0; 169*1da177e4SLinus Torvalds struct hotplug_slot *php_slot = slot->hotplug_slot; 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds dbg("%s - Entry: deregistering slot=%s\n", 172*1da177e4SLinus Torvalds __FUNCTION__, slot->name); 173*1da177e4SLinus Torvalds 174*1da177e4SLinus Torvalds list_del(&slot->rpaphp_slot_list); 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds /* remove "phy_location" file */ 177*1da177e4SLinus Torvalds rpaphp_sysfs_remove_attr_location(php_slot); 178*1da177e4SLinus Torvalds 179*1da177e4SLinus Torvalds /* remove "phy_removable" file */ 180*1da177e4SLinus Torvalds rpaphp_sysfs_remove_attr_removable(php_slot); 181*1da177e4SLinus Torvalds 182*1da177e4SLinus Torvalds retval = pci_hp_deregister(php_slot); 183*1da177e4SLinus Torvalds if (retval) 184*1da177e4SLinus Torvalds err("Problem unregistering a slot %s\n", slot->name); 185*1da177e4SLinus Torvalds else 186*1da177e4SLinus Torvalds num_slots--; 187*1da177e4SLinus Torvalds 188*1da177e4SLinus Torvalds dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval); 189*1da177e4SLinus Torvalds return retval; 190*1da177e4SLinus Torvalds } 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds int register_slot(struct slot *slot) 193*1da177e4SLinus Torvalds { 194*1da177e4SLinus Torvalds int retval; 195*1da177e4SLinus Torvalds 196*1da177e4SLinus Torvalds dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", 197*1da177e4SLinus Torvalds __FUNCTION__, slot->dn->full_name, slot->index, slot->name, 198*1da177e4SLinus Torvalds slot->power_domain, slot->type); 199*1da177e4SLinus Torvalds /* should not try to register the same slot twice */ 200*1da177e4SLinus Torvalds if (is_registered(slot)) { /* should't be here */ 201*1da177e4SLinus Torvalds err("register_slot: slot[%s] is already registered\n", slot->name); 202*1da177e4SLinus Torvalds rpaphp_release_slot(slot->hotplug_slot); 203*1da177e4SLinus Torvalds return -EAGAIN; 204*1da177e4SLinus Torvalds } 205*1da177e4SLinus Torvalds retval = pci_hp_register(slot->hotplug_slot); 206*1da177e4SLinus Torvalds if (retval) { 207*1da177e4SLinus Torvalds err("pci_hp_register failed with error %d\n", retval); 208*1da177e4SLinus Torvalds rpaphp_release_slot(slot->hotplug_slot); 209*1da177e4SLinus Torvalds return retval; 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds 212*1da177e4SLinus Torvalds /* create "phy_locatoin" file */ 213*1da177e4SLinus Torvalds rpaphp_sysfs_add_attr_location(slot->hotplug_slot); 214*1da177e4SLinus Torvalds 215*1da177e4SLinus Torvalds /* create "phy_removable" file */ 216*1da177e4SLinus Torvalds rpaphp_sysfs_add_attr_removable(slot->hotplug_slot); 217*1da177e4SLinus Torvalds 218*1da177e4SLinus Torvalds /* add slot to our internal list */ 219*1da177e4SLinus Torvalds dbg("%s adding slot[%s] to rpaphp_slot_list\n", 220*1da177e4SLinus Torvalds __FUNCTION__, slot->name); 221*1da177e4SLinus Torvalds 222*1da177e4SLinus Torvalds list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); 223*1da177e4SLinus Torvalds 224*1da177e4SLinus Torvalds if (slot->dev_type == VIO_DEV) 225*1da177e4SLinus Torvalds info("Slot [%s](VIO location=%s) registered\n", 226*1da177e4SLinus Torvalds slot->name, slot->location); 227*1da177e4SLinus Torvalds else 228*1da177e4SLinus Torvalds info("Slot [%s](PCI location=%s) registered\n", 229*1da177e4SLinus Torvalds slot->name, slot->location); 230*1da177e4SLinus Torvalds num_slots++; 231*1da177e4SLinus Torvalds return 0; 232*1da177e4SLinus Torvalds } 233*1da177e4SLinus Torvalds 234*1da177e4SLinus Torvalds int rpaphp_get_power_status(struct slot *slot, u8 * value) 235*1da177e4SLinus Torvalds { 236*1da177e4SLinus Torvalds int rc = 0, level; 237*1da177e4SLinus Torvalds 238*1da177e4SLinus Torvalds if (slot->type == HOTPLUG) { 239*1da177e4SLinus Torvalds rc = rtas_get_power_level(slot->power_domain, &level); 240*1da177e4SLinus Torvalds if (!rc) { 241*1da177e4SLinus Torvalds dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n", 242*1da177e4SLinus Torvalds __FUNCTION__, slot->name, slot->power_domain, level); 243*1da177e4SLinus Torvalds *value = level; 244*1da177e4SLinus Torvalds } else 245*1da177e4SLinus Torvalds err("failed to get power-level for slot(%s), rc=0x%x\n", 246*1da177e4SLinus Torvalds slot->location, rc); 247*1da177e4SLinus Torvalds } else { 248*1da177e4SLinus Torvalds dbg("%s report POWER_ON for EMBEDDED or PHB slot %s\n", 249*1da177e4SLinus Torvalds __FUNCTION__, slot->location); 250*1da177e4SLinus Torvalds *value = (u8) POWER_ON; 251*1da177e4SLinus Torvalds } 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds return rc; 254*1da177e4SLinus Torvalds } 255*1da177e4SLinus Torvalds 256*1da177e4SLinus Torvalds int rpaphp_set_attention_status(struct slot *slot, u8 status) 257*1da177e4SLinus Torvalds { 258*1da177e4SLinus Torvalds int rc; 259*1da177e4SLinus Torvalds 260*1da177e4SLinus Torvalds /* status: LED_OFF or LED_ON */ 261*1da177e4SLinus Torvalds rc = rtas_set_indicator(DR_INDICATOR, slot->index, status); 262*1da177e4SLinus Torvalds if (rc < 0) 263*1da177e4SLinus Torvalds err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n", 264*1da177e4SLinus Torvalds slot->name, slot->location, slot->index, status, rc); 265*1da177e4SLinus Torvalds 266*1da177e4SLinus Torvalds return rc; 267*1da177e4SLinus Torvalds } 268