1*7441b062SJan Glauber /* 2*7441b062SJan Glauber * PCI Hot Plug Controller Driver for System z 3*7441b062SJan Glauber * 4*7441b062SJan Glauber * Copyright 2012 IBM Corp. 5*7441b062SJan Glauber * 6*7441b062SJan Glauber * Author(s): 7*7441b062SJan Glauber * Jan Glauber <jang@linux.vnet.ibm.com> 8*7441b062SJan Glauber */ 9*7441b062SJan Glauber 10*7441b062SJan Glauber #define COMPONENT "zPCI hpc" 11*7441b062SJan Glauber #define pr_fmt(fmt) COMPONENT ": " fmt 12*7441b062SJan Glauber 13*7441b062SJan Glauber #include <linux/module.h> 14*7441b062SJan Glauber #include <linux/kernel.h> 15*7441b062SJan Glauber #include <linux/slab.h> 16*7441b062SJan Glauber #include <linux/pci.h> 17*7441b062SJan Glauber #include <linux/pci_hotplug.h> 18*7441b062SJan Glauber #include <linux/init.h> 19*7441b062SJan Glauber #include <asm/sclp.h> 20*7441b062SJan Glauber 21*7441b062SJan Glauber #define SLOT_NAME_SIZE 10 22*7441b062SJan Glauber static LIST_HEAD(s390_hotplug_slot_list); 23*7441b062SJan Glauber 24*7441b062SJan Glauber MODULE_AUTHOR("Jan Glauber <jang@linux.vnet.ibm.com"); 25*7441b062SJan Glauber MODULE_DESCRIPTION("Hot Plug PCI Controller for System z"); 26*7441b062SJan Glauber MODULE_LICENSE("GPL"); 27*7441b062SJan Glauber 28*7441b062SJan Glauber static int zpci_fn_configured(enum zpci_state state) 29*7441b062SJan Glauber { 30*7441b062SJan Glauber return state == ZPCI_FN_STATE_CONFIGURED || 31*7441b062SJan Glauber state == ZPCI_FN_STATE_ONLINE; 32*7441b062SJan Glauber } 33*7441b062SJan Glauber 34*7441b062SJan Glauber /* 35*7441b062SJan Glauber * struct slot - slot information for each *physical* slot 36*7441b062SJan Glauber */ 37*7441b062SJan Glauber struct slot { 38*7441b062SJan Glauber struct list_head slot_list; 39*7441b062SJan Glauber struct hotplug_slot *hotplug_slot; 40*7441b062SJan Glauber struct zpci_dev *zdev; 41*7441b062SJan Glauber }; 42*7441b062SJan Glauber 43*7441b062SJan Glauber static int enable_slot(struct hotplug_slot *hotplug_slot) 44*7441b062SJan Glauber { 45*7441b062SJan Glauber struct slot *slot = hotplug_slot->private; 46*7441b062SJan Glauber int rc; 47*7441b062SJan Glauber 48*7441b062SJan Glauber if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) 49*7441b062SJan Glauber return -EIO; 50*7441b062SJan Glauber 51*7441b062SJan Glauber rc = sclp_pci_configure(slot->zdev->fid); 52*7441b062SJan Glauber if (!rc) { 53*7441b062SJan Glauber slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; 54*7441b062SJan Glauber /* automatically scan the device after is was configured */ 55*7441b062SJan Glauber zpci_enable_device(slot->zdev); 56*7441b062SJan Glauber zpci_scan_device(slot->zdev); 57*7441b062SJan Glauber } 58*7441b062SJan Glauber return rc; 59*7441b062SJan Glauber } 60*7441b062SJan Glauber 61*7441b062SJan Glauber static int disable_slot(struct hotplug_slot *hotplug_slot) 62*7441b062SJan Glauber { 63*7441b062SJan Glauber struct slot *slot = hotplug_slot->private; 64*7441b062SJan Glauber int rc; 65*7441b062SJan Glauber 66*7441b062SJan Glauber if (!zpci_fn_configured(slot->zdev->state)) 67*7441b062SJan Glauber return -EIO; 68*7441b062SJan Glauber 69*7441b062SJan Glauber /* TODO: we rely on the user to unbind/remove the device, is that plausible 70*7441b062SJan Glauber * or do we need to trigger that here? 71*7441b062SJan Glauber */ 72*7441b062SJan Glauber rc = sclp_pci_deconfigure(slot->zdev->fid); 73*7441b062SJan Glauber if (!rc) { 74*7441b062SJan Glauber /* Fixme: better call List-PCI to find the disabled FH 75*7441b062SJan Glauber for the FID since the FH should be opaque... */ 76*7441b062SJan Glauber slot->zdev->fh &= 0x7fffffff; 77*7441b062SJan Glauber slot->zdev->state = ZPCI_FN_STATE_STANDBY; 78*7441b062SJan Glauber } 79*7441b062SJan Glauber return rc; 80*7441b062SJan Glauber } 81*7441b062SJan Glauber 82*7441b062SJan Glauber static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) 83*7441b062SJan Glauber { 84*7441b062SJan Glauber struct slot *slot = hotplug_slot->private; 85*7441b062SJan Glauber 86*7441b062SJan Glauber switch (slot->zdev->state) { 87*7441b062SJan Glauber case ZPCI_FN_STATE_STANDBY: 88*7441b062SJan Glauber *value = 0; 89*7441b062SJan Glauber break; 90*7441b062SJan Glauber default: 91*7441b062SJan Glauber *value = 1; 92*7441b062SJan Glauber break; 93*7441b062SJan Glauber } 94*7441b062SJan Glauber return 0; 95*7441b062SJan Glauber } 96*7441b062SJan Glauber 97*7441b062SJan Glauber static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) 98*7441b062SJan Glauber { 99*7441b062SJan Glauber /* if the slot exits it always contains a function */ 100*7441b062SJan Glauber *value = 1; 101*7441b062SJan Glauber return 0; 102*7441b062SJan Glauber } 103*7441b062SJan Glauber 104*7441b062SJan Glauber static void release_slot(struct hotplug_slot *hotplug_slot) 105*7441b062SJan Glauber { 106*7441b062SJan Glauber struct slot *slot = hotplug_slot->private; 107*7441b062SJan Glauber 108*7441b062SJan Glauber pr_debug("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); 109*7441b062SJan Glauber kfree(slot->hotplug_slot->info); 110*7441b062SJan Glauber kfree(slot->hotplug_slot); 111*7441b062SJan Glauber kfree(slot); 112*7441b062SJan Glauber } 113*7441b062SJan Glauber 114*7441b062SJan Glauber static struct hotplug_slot_ops s390_hotplug_slot_ops = { 115*7441b062SJan Glauber .enable_slot = enable_slot, 116*7441b062SJan Glauber .disable_slot = disable_slot, 117*7441b062SJan Glauber .get_power_status = get_power_status, 118*7441b062SJan Glauber .get_adapter_status = get_adapter_status, 119*7441b062SJan Glauber }; 120*7441b062SJan Glauber 121*7441b062SJan Glauber static int init_pci_slot(struct zpci_dev *zdev) 122*7441b062SJan Glauber { 123*7441b062SJan Glauber struct hotplug_slot *hotplug_slot; 124*7441b062SJan Glauber struct hotplug_slot_info *info; 125*7441b062SJan Glauber char name[SLOT_NAME_SIZE]; 126*7441b062SJan Glauber struct slot *slot; 127*7441b062SJan Glauber int rc; 128*7441b062SJan Glauber 129*7441b062SJan Glauber if (!zdev) 130*7441b062SJan Glauber return 0; 131*7441b062SJan Glauber 132*7441b062SJan Glauber slot = kzalloc(sizeof(*slot), GFP_KERNEL); 133*7441b062SJan Glauber if (!slot) 134*7441b062SJan Glauber goto error; 135*7441b062SJan Glauber 136*7441b062SJan Glauber hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); 137*7441b062SJan Glauber if (!hotplug_slot) 138*7441b062SJan Glauber goto error_hp; 139*7441b062SJan Glauber hotplug_slot->private = slot; 140*7441b062SJan Glauber 141*7441b062SJan Glauber slot->hotplug_slot = hotplug_slot; 142*7441b062SJan Glauber slot->zdev = zdev; 143*7441b062SJan Glauber 144*7441b062SJan Glauber info = kzalloc(sizeof(*info), GFP_KERNEL); 145*7441b062SJan Glauber if (!info) 146*7441b062SJan Glauber goto error_info; 147*7441b062SJan Glauber hotplug_slot->info = info; 148*7441b062SJan Glauber 149*7441b062SJan Glauber hotplug_slot->ops = &s390_hotplug_slot_ops; 150*7441b062SJan Glauber hotplug_slot->release = &release_slot; 151*7441b062SJan Glauber 152*7441b062SJan Glauber get_power_status(hotplug_slot, &info->power_status); 153*7441b062SJan Glauber get_adapter_status(hotplug_slot, &info->adapter_status); 154*7441b062SJan Glauber 155*7441b062SJan Glauber snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); 156*7441b062SJan Glauber rc = pci_hp_register(slot->hotplug_slot, zdev->bus, 157*7441b062SJan Glauber ZPCI_DEVFN, name); 158*7441b062SJan Glauber if (rc) { 159*7441b062SJan Glauber pr_err("pci_hp_register failed with error %d\n", rc); 160*7441b062SJan Glauber goto error_reg; 161*7441b062SJan Glauber } 162*7441b062SJan Glauber list_add(&slot->slot_list, &s390_hotplug_slot_list); 163*7441b062SJan Glauber return 0; 164*7441b062SJan Glauber 165*7441b062SJan Glauber error_reg: 166*7441b062SJan Glauber kfree(info); 167*7441b062SJan Glauber error_info: 168*7441b062SJan Glauber kfree(hotplug_slot); 169*7441b062SJan Glauber error_hp: 170*7441b062SJan Glauber kfree(slot); 171*7441b062SJan Glauber error: 172*7441b062SJan Glauber return -ENOMEM; 173*7441b062SJan Glauber } 174*7441b062SJan Glauber 175*7441b062SJan Glauber static int __init init_pci_slots(void) 176*7441b062SJan Glauber { 177*7441b062SJan Glauber struct zpci_dev *zdev; 178*7441b062SJan Glauber int device = 0; 179*7441b062SJan Glauber 180*7441b062SJan Glauber /* 181*7441b062SJan Glauber * Create a structure for each slot, and register that slot 182*7441b062SJan Glauber * with the pci_hotplug subsystem. 183*7441b062SJan Glauber */ 184*7441b062SJan Glauber mutex_lock(&zpci_list_lock); 185*7441b062SJan Glauber list_for_each_entry(zdev, &zpci_list, entry) { 186*7441b062SJan Glauber init_pci_slot(zdev); 187*7441b062SJan Glauber device++; 188*7441b062SJan Glauber } 189*7441b062SJan Glauber 190*7441b062SJan Glauber mutex_unlock(&zpci_list_lock); 191*7441b062SJan Glauber return (device) ? 0 : -ENODEV; 192*7441b062SJan Glauber } 193*7441b062SJan Glauber 194*7441b062SJan Glauber static void exit_pci_slot(struct zpci_dev *zdev) 195*7441b062SJan Glauber { 196*7441b062SJan Glauber struct list_head *tmp, *n; 197*7441b062SJan Glauber struct slot *slot; 198*7441b062SJan Glauber 199*7441b062SJan Glauber list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { 200*7441b062SJan Glauber slot = list_entry(tmp, struct slot, slot_list); 201*7441b062SJan Glauber if (slot->zdev != zdev) 202*7441b062SJan Glauber continue; 203*7441b062SJan Glauber list_del(&slot->slot_list); 204*7441b062SJan Glauber pci_hp_deregister(slot->hotplug_slot); 205*7441b062SJan Glauber } 206*7441b062SJan Glauber } 207*7441b062SJan Glauber 208*7441b062SJan Glauber static void __exit exit_pci_slots(void) 209*7441b062SJan Glauber { 210*7441b062SJan Glauber struct list_head *tmp, *n; 211*7441b062SJan Glauber struct slot *slot; 212*7441b062SJan Glauber 213*7441b062SJan Glauber /* 214*7441b062SJan Glauber * Unregister all of our slots with the pci_hotplug subsystem. 215*7441b062SJan Glauber * Memory will be freed in release_slot() callback after slot's 216*7441b062SJan Glauber * lifespan is finished. 217*7441b062SJan Glauber */ 218*7441b062SJan Glauber list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { 219*7441b062SJan Glauber slot = list_entry(tmp, struct slot, slot_list); 220*7441b062SJan Glauber list_del(&slot->slot_list); 221*7441b062SJan Glauber pci_hp_deregister(slot->hotplug_slot); 222*7441b062SJan Glauber } 223*7441b062SJan Glauber } 224*7441b062SJan Glauber 225*7441b062SJan Glauber static int __init pci_hotplug_s390_init(void) 226*7441b062SJan Glauber { 227*7441b062SJan Glauber /* 228*7441b062SJan Glauber * Do specific initialization stuff for your driver here 229*7441b062SJan Glauber * like initializing your controller hardware (if any) and 230*7441b062SJan Glauber * determining the number of slots you have in the system 231*7441b062SJan Glauber * right now. 232*7441b062SJan Glauber */ 233*7441b062SJan Glauber 234*7441b062SJan Glauber if (!pci_probe) 235*7441b062SJan Glauber return -EOPNOTSUPP; 236*7441b062SJan Glauber 237*7441b062SJan Glauber /* register callbacks for slot handling from arch code */ 238*7441b062SJan Glauber mutex_lock(&zpci_list_lock); 239*7441b062SJan Glauber hotplug_ops.create_slot = init_pci_slot; 240*7441b062SJan Glauber hotplug_ops.remove_slot = exit_pci_slot; 241*7441b062SJan Glauber mutex_unlock(&zpci_list_lock); 242*7441b062SJan Glauber pr_info("registered hotplug slot callbacks\n"); 243*7441b062SJan Glauber return init_pci_slots(); 244*7441b062SJan Glauber } 245*7441b062SJan Glauber 246*7441b062SJan Glauber static void __exit pci_hotplug_s390_exit(void) 247*7441b062SJan Glauber { 248*7441b062SJan Glauber exit_pci_slots(); 249*7441b062SJan Glauber } 250*7441b062SJan Glauber 251*7441b062SJan Glauber module_init(pci_hotplug_s390_init); 252*7441b062SJan Glauber module_exit(pci_hotplug_s390_exit); 253