17441b062SJan Glauber /* 27441b062SJan Glauber * PCI Hot Plug Controller Driver for System z 37441b062SJan Glauber * 47441b062SJan Glauber * Copyright 2012 IBM Corp. 57441b062SJan Glauber * 67441b062SJan Glauber * Author(s): 77441b062SJan Glauber * Jan Glauber <jang@linux.vnet.ibm.com> 87441b062SJan Glauber */ 97441b062SJan Glauber 107441b062SJan Glauber #define COMPONENT "zPCI hpc" 117441b062SJan Glauber #define pr_fmt(fmt) COMPONENT ": " fmt 127441b062SJan Glauber 137441b062SJan Glauber #include <linux/module.h> 147441b062SJan Glauber #include <linux/kernel.h> 157441b062SJan Glauber #include <linux/slab.h> 167441b062SJan Glauber #include <linux/pci.h> 177441b062SJan Glauber #include <linux/pci_hotplug.h> 187441b062SJan Glauber #include <linux/init.h> 19a2ab8333SSebastian Ott #include <asm/pci_debug.h> 207441b062SJan Glauber #include <asm/sclp.h> 217441b062SJan Glauber 227441b062SJan Glauber #define SLOT_NAME_SIZE 10 237441b062SJan Glauber static LIST_HEAD(s390_hotplug_slot_list); 247441b062SJan Glauber 257441b062SJan Glauber MODULE_AUTHOR("Jan Glauber <jang@linux.vnet.ibm.com"); 267441b062SJan Glauber MODULE_DESCRIPTION("Hot Plug PCI Controller for System z"); 277441b062SJan Glauber MODULE_LICENSE("GPL"); 287441b062SJan Glauber 297441b062SJan Glauber static int zpci_fn_configured(enum zpci_state state) 307441b062SJan Glauber { 317441b062SJan Glauber return state == ZPCI_FN_STATE_CONFIGURED || 327441b062SJan Glauber state == ZPCI_FN_STATE_ONLINE; 337441b062SJan Glauber } 347441b062SJan Glauber 357441b062SJan Glauber /* 367441b062SJan Glauber * struct slot - slot information for each *physical* slot 377441b062SJan Glauber */ 387441b062SJan Glauber struct slot { 397441b062SJan Glauber struct list_head slot_list; 407441b062SJan Glauber struct hotplug_slot *hotplug_slot; 417441b062SJan Glauber struct zpci_dev *zdev; 427441b062SJan Glauber }; 437441b062SJan Glauber 44*4bee2a5dSSebastian Ott static inline int slot_configure(struct slot *slot) 45*4bee2a5dSSebastian Ott { 46*4bee2a5dSSebastian Ott int ret = sclp_pci_configure(slot->zdev->fid); 47*4bee2a5dSSebastian Ott 48*4bee2a5dSSebastian Ott zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret); 49*4bee2a5dSSebastian Ott if (!ret) 50*4bee2a5dSSebastian Ott slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; 51*4bee2a5dSSebastian Ott 52*4bee2a5dSSebastian Ott return ret; 53*4bee2a5dSSebastian Ott } 54*4bee2a5dSSebastian Ott 55*4bee2a5dSSebastian Ott static inline int slot_deconfigure(struct slot *slot) 56*4bee2a5dSSebastian Ott { 57*4bee2a5dSSebastian Ott int ret = sclp_pci_deconfigure(slot->zdev->fid); 58*4bee2a5dSSebastian Ott 59*4bee2a5dSSebastian Ott zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret); 60*4bee2a5dSSebastian Ott if (!ret) 61*4bee2a5dSSebastian Ott slot->zdev->state = ZPCI_FN_STATE_STANDBY; 62*4bee2a5dSSebastian Ott 63*4bee2a5dSSebastian Ott return ret; 64*4bee2a5dSSebastian Ott } 65*4bee2a5dSSebastian Ott 667441b062SJan Glauber static int enable_slot(struct hotplug_slot *hotplug_slot) 677441b062SJan Glauber { 687441b062SJan Glauber struct slot *slot = hotplug_slot->private; 697441b062SJan Glauber int rc; 707441b062SJan Glauber 717441b062SJan Glauber if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) 727441b062SJan Glauber return -EIO; 737441b062SJan Glauber 74*4bee2a5dSSebastian Ott rc = slot_configure(slot); 75*4bee2a5dSSebastian Ott if (rc) 76*4bee2a5dSSebastian Ott return rc; 77*4bee2a5dSSebastian Ott 78*4bee2a5dSSebastian Ott rc = zpci_enable_device(slot->zdev); 79*4bee2a5dSSebastian Ott if (rc) 80*4bee2a5dSSebastian Ott goto out_deconfigure; 81*4bee2a5dSSebastian Ott 82*4bee2a5dSSebastian Ott slot->zdev->state = ZPCI_FN_STATE_ONLINE; 83*4bee2a5dSSebastian Ott 84*4bee2a5dSSebastian Ott pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); 85*4bee2a5dSSebastian Ott pci_bus_add_devices(slot->zdev->bus); 86*4bee2a5dSSebastian Ott 87*4bee2a5dSSebastian Ott return rc; 88*4bee2a5dSSebastian Ott 89*4bee2a5dSSebastian Ott out_deconfigure: 90*4bee2a5dSSebastian Ott slot_deconfigure(slot); 917441b062SJan Glauber return rc; 927441b062SJan Glauber } 937441b062SJan Glauber 947441b062SJan Glauber static int disable_slot(struct hotplug_slot *hotplug_slot) 957441b062SJan Glauber { 967441b062SJan Glauber struct slot *slot = hotplug_slot->private; 977441b062SJan Glauber int rc; 987441b062SJan Glauber 997441b062SJan Glauber if (!zpci_fn_configured(slot->zdev->state)) 1007441b062SJan Glauber return -EIO; 1017441b062SJan Glauber 102cb65a669SSebastian Ott rc = zpci_disable_device(slot->zdev); 103cb65a669SSebastian Ott if (rc) 104cb65a669SSebastian Ott return rc; 1057441b062SJan Glauber /* TODO: we rely on the user to unbind/remove the device, is that plausible 1067441b062SJan Glauber * or do we need to trigger that here? 1077441b062SJan Glauber */ 108*4bee2a5dSSebastian Ott return slot_deconfigure(slot); 1097441b062SJan Glauber } 1107441b062SJan Glauber 1117441b062SJan Glauber static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) 1127441b062SJan Glauber { 1137441b062SJan Glauber struct slot *slot = hotplug_slot->private; 1147441b062SJan Glauber 1157441b062SJan Glauber switch (slot->zdev->state) { 1167441b062SJan Glauber case ZPCI_FN_STATE_STANDBY: 1177441b062SJan Glauber *value = 0; 1187441b062SJan Glauber break; 1197441b062SJan Glauber default: 1207441b062SJan Glauber *value = 1; 1217441b062SJan Glauber break; 1227441b062SJan Glauber } 1237441b062SJan Glauber return 0; 1247441b062SJan Glauber } 1257441b062SJan Glauber 1267441b062SJan Glauber static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) 1277441b062SJan Glauber { 1287441b062SJan Glauber /* if the slot exits it always contains a function */ 1297441b062SJan Glauber *value = 1; 1307441b062SJan Glauber return 0; 1317441b062SJan Glauber } 1327441b062SJan Glauber 1337441b062SJan Glauber static void release_slot(struct hotplug_slot *hotplug_slot) 1347441b062SJan Glauber { 1357441b062SJan Glauber struct slot *slot = hotplug_slot->private; 1367441b062SJan Glauber 1377441b062SJan Glauber pr_debug("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); 1387441b062SJan Glauber kfree(slot->hotplug_slot->info); 1397441b062SJan Glauber kfree(slot->hotplug_slot); 1407441b062SJan Glauber kfree(slot); 1417441b062SJan Glauber } 1427441b062SJan Glauber 1437441b062SJan Glauber static struct hotplug_slot_ops s390_hotplug_slot_ops = { 1447441b062SJan Glauber .enable_slot = enable_slot, 1457441b062SJan Glauber .disable_slot = disable_slot, 1467441b062SJan Glauber .get_power_status = get_power_status, 1477441b062SJan Glauber .get_adapter_status = get_adapter_status, 1487441b062SJan Glauber }; 1497441b062SJan Glauber 1507441b062SJan Glauber static int init_pci_slot(struct zpci_dev *zdev) 1517441b062SJan Glauber { 1527441b062SJan Glauber struct hotplug_slot *hotplug_slot; 1537441b062SJan Glauber struct hotplug_slot_info *info; 1547441b062SJan Glauber char name[SLOT_NAME_SIZE]; 1557441b062SJan Glauber struct slot *slot; 1567441b062SJan Glauber int rc; 1577441b062SJan Glauber 1587441b062SJan Glauber if (!zdev) 1597441b062SJan Glauber return 0; 1607441b062SJan Glauber 1617441b062SJan Glauber slot = kzalloc(sizeof(*slot), GFP_KERNEL); 1627441b062SJan Glauber if (!slot) 1637441b062SJan Glauber goto error; 1647441b062SJan Glauber 1657441b062SJan Glauber hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); 1667441b062SJan Glauber if (!hotplug_slot) 1677441b062SJan Glauber goto error_hp; 1687441b062SJan Glauber hotplug_slot->private = slot; 1697441b062SJan Glauber 1707441b062SJan Glauber slot->hotplug_slot = hotplug_slot; 1717441b062SJan Glauber slot->zdev = zdev; 1727441b062SJan Glauber 1737441b062SJan Glauber info = kzalloc(sizeof(*info), GFP_KERNEL); 1747441b062SJan Glauber if (!info) 1757441b062SJan Glauber goto error_info; 1767441b062SJan Glauber hotplug_slot->info = info; 1777441b062SJan Glauber 1787441b062SJan Glauber hotplug_slot->ops = &s390_hotplug_slot_ops; 1797441b062SJan Glauber hotplug_slot->release = &release_slot; 1807441b062SJan Glauber 1817441b062SJan Glauber get_power_status(hotplug_slot, &info->power_status); 1827441b062SJan Glauber get_adapter_status(hotplug_slot, &info->adapter_status); 1837441b062SJan Glauber 1847441b062SJan Glauber snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); 1857441b062SJan Glauber rc = pci_hp_register(slot->hotplug_slot, zdev->bus, 1867441b062SJan Glauber ZPCI_DEVFN, name); 1877441b062SJan Glauber if (rc) { 1887441b062SJan Glauber pr_err("pci_hp_register failed with error %d\n", rc); 1897441b062SJan Glauber goto error_reg; 1907441b062SJan Glauber } 1917441b062SJan Glauber list_add(&slot->slot_list, &s390_hotplug_slot_list); 1927441b062SJan Glauber return 0; 1937441b062SJan Glauber 1947441b062SJan Glauber error_reg: 1957441b062SJan Glauber kfree(info); 1967441b062SJan Glauber error_info: 1977441b062SJan Glauber kfree(hotplug_slot); 1987441b062SJan Glauber error_hp: 1997441b062SJan Glauber kfree(slot); 2007441b062SJan Glauber error: 2017441b062SJan Glauber return -ENOMEM; 2027441b062SJan Glauber } 2037441b062SJan Glauber 2047441b062SJan Glauber static void exit_pci_slot(struct zpci_dev *zdev) 2057441b062SJan Glauber { 2067441b062SJan Glauber struct list_head *tmp, *n; 2077441b062SJan Glauber struct slot *slot; 2087441b062SJan Glauber 2097441b062SJan Glauber list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { 2107441b062SJan Glauber slot = list_entry(tmp, struct slot, slot_list); 2117441b062SJan Glauber if (slot->zdev != zdev) 2127441b062SJan Glauber continue; 2137441b062SJan Glauber list_del(&slot->slot_list); 2147441b062SJan Glauber pci_hp_deregister(slot->hotplug_slot); 2157441b062SJan Glauber } 2167441b062SJan Glauber } 2177441b062SJan Glauber 21853923354SSebastian Ott static struct pci_hp_callback_ops hp_ops = { 21953923354SSebastian Ott .create_slot = init_pci_slot, 22053923354SSebastian Ott .remove_slot = exit_pci_slot, 22153923354SSebastian Ott }; 22253923354SSebastian Ott 22353923354SSebastian Ott static void __init init_pci_slots(void) 22453923354SSebastian Ott { 22553923354SSebastian Ott struct zpci_dev *zdev; 22653923354SSebastian Ott 22753923354SSebastian Ott /* 22853923354SSebastian Ott * Create a structure for each slot, and register that slot 22953923354SSebastian Ott * with the pci_hotplug subsystem. 23053923354SSebastian Ott */ 23153923354SSebastian Ott mutex_lock(&zpci_list_lock); 23253923354SSebastian Ott list_for_each_entry(zdev, &zpci_list, entry) { 23353923354SSebastian Ott init_pci_slot(zdev); 23453923354SSebastian Ott } 23553923354SSebastian Ott mutex_unlock(&zpci_list_lock); 23653923354SSebastian Ott } 23753923354SSebastian Ott 2387441b062SJan Glauber static void __exit exit_pci_slots(void) 2397441b062SJan Glauber { 2407441b062SJan Glauber struct list_head *tmp, *n; 2417441b062SJan Glauber struct slot *slot; 2427441b062SJan Glauber 2437441b062SJan Glauber /* 2447441b062SJan Glauber * Unregister all of our slots with the pci_hotplug subsystem. 2457441b062SJan Glauber * Memory will be freed in release_slot() callback after slot's 2467441b062SJan Glauber * lifespan is finished. 2477441b062SJan Glauber */ 2487441b062SJan Glauber list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { 2497441b062SJan Glauber slot = list_entry(tmp, struct slot, slot_list); 2507441b062SJan Glauber list_del(&slot->slot_list); 2517441b062SJan Glauber pci_hp_deregister(slot->hotplug_slot); 2527441b062SJan Glauber } 2537441b062SJan Glauber } 2547441b062SJan Glauber 2557441b062SJan Glauber static int __init pci_hotplug_s390_init(void) 2567441b062SJan Glauber { 2571e5635d1SHeiko Carstens if (!s390_pci_probe) 2587441b062SJan Glauber return -EOPNOTSUPP; 2597441b062SJan Glauber 26053923354SSebastian Ott zpci_register_hp_ops(&hp_ops); 26153923354SSebastian Ott init_pci_slots(); 26253923354SSebastian Ott 26353923354SSebastian Ott return 0; 2647441b062SJan Glauber } 2657441b062SJan Glauber 2667441b062SJan Glauber static void __exit pci_hotplug_s390_exit(void) 2677441b062SJan Glauber { 2687441b062SJan Glauber exit_pci_slots(); 26953923354SSebastian Ott zpci_deregister_hp_ops(); 2707441b062SJan Glauber } 2717441b062SJan Glauber 2727441b062SJan Glauber module_init(pci_hotplug_s390_init); 2737441b062SJan Glauber module_exit(pci_hotplug_s390_exit); 274