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 444bee2a5dSSebastian Ott static inline int slot_configure(struct slot *slot) 454bee2a5dSSebastian Ott { 464bee2a5dSSebastian Ott int ret = sclp_pci_configure(slot->zdev->fid); 474bee2a5dSSebastian Ott 484bee2a5dSSebastian Ott zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret); 494bee2a5dSSebastian Ott if (!ret) 504bee2a5dSSebastian Ott slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; 514bee2a5dSSebastian Ott 524bee2a5dSSebastian Ott return ret; 534bee2a5dSSebastian Ott } 544bee2a5dSSebastian Ott 554bee2a5dSSebastian Ott static inline int slot_deconfigure(struct slot *slot) 564bee2a5dSSebastian Ott { 574bee2a5dSSebastian Ott int ret = sclp_pci_deconfigure(slot->zdev->fid); 584bee2a5dSSebastian Ott 594bee2a5dSSebastian Ott zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret); 604bee2a5dSSebastian Ott if (!ret) 614bee2a5dSSebastian Ott slot->zdev->state = ZPCI_FN_STATE_STANDBY; 624bee2a5dSSebastian Ott 634bee2a5dSSebastian Ott return ret; 644bee2a5dSSebastian Ott } 654bee2a5dSSebastian 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 744bee2a5dSSebastian Ott rc = slot_configure(slot); 754bee2a5dSSebastian Ott if (rc) 764bee2a5dSSebastian Ott return rc; 774bee2a5dSSebastian Ott 784bee2a5dSSebastian Ott rc = zpci_enable_device(slot->zdev); 794bee2a5dSSebastian Ott if (rc) 804bee2a5dSSebastian Ott goto out_deconfigure; 814bee2a5dSSebastian Ott 824bee2a5dSSebastian Ott slot->zdev->state = ZPCI_FN_STATE_ONLINE; 834bee2a5dSSebastian Ott 844bee2a5dSSebastian Ott pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); 854bee2a5dSSebastian Ott pci_bus_add_devices(slot->zdev->bus); 864bee2a5dSSebastian Ott 874bee2a5dSSebastian Ott return rc; 884bee2a5dSSebastian Ott 894bee2a5dSSebastian Ott out_deconfigure: 904bee2a5dSSebastian 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 102*8b2a7e60SSebastian Ott if (slot->zdev->pdev) 103*8b2a7e60SSebastian Ott pci_stop_and_remove_bus_device(slot->zdev->pdev); 104*8b2a7e60SSebastian Ott 105cb65a669SSebastian Ott rc = zpci_disable_device(slot->zdev); 106cb65a669SSebastian Ott if (rc) 107cb65a669SSebastian Ott return rc; 108*8b2a7e60SSebastian Ott 1094bee2a5dSSebastian Ott return slot_deconfigure(slot); 1107441b062SJan Glauber } 1117441b062SJan Glauber 1127441b062SJan Glauber static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) 1137441b062SJan Glauber { 1147441b062SJan Glauber struct slot *slot = hotplug_slot->private; 1157441b062SJan Glauber 1167441b062SJan Glauber switch (slot->zdev->state) { 1177441b062SJan Glauber case ZPCI_FN_STATE_STANDBY: 1187441b062SJan Glauber *value = 0; 1197441b062SJan Glauber break; 1207441b062SJan Glauber default: 1217441b062SJan Glauber *value = 1; 1227441b062SJan Glauber break; 1237441b062SJan Glauber } 1247441b062SJan Glauber return 0; 1257441b062SJan Glauber } 1267441b062SJan Glauber 1277441b062SJan Glauber static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) 1287441b062SJan Glauber { 1297441b062SJan Glauber /* if the slot exits it always contains a function */ 1307441b062SJan Glauber *value = 1; 1317441b062SJan Glauber return 0; 1327441b062SJan Glauber } 1337441b062SJan Glauber 1347441b062SJan Glauber static void release_slot(struct hotplug_slot *hotplug_slot) 1357441b062SJan Glauber { 1367441b062SJan Glauber struct slot *slot = hotplug_slot->private; 1377441b062SJan Glauber 1387441b062SJan Glauber pr_debug("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); 1397441b062SJan Glauber kfree(slot->hotplug_slot->info); 1407441b062SJan Glauber kfree(slot->hotplug_slot); 1417441b062SJan Glauber kfree(slot); 1427441b062SJan Glauber } 1437441b062SJan Glauber 1447441b062SJan Glauber static struct hotplug_slot_ops s390_hotplug_slot_ops = { 1457441b062SJan Glauber .enable_slot = enable_slot, 1467441b062SJan Glauber .disable_slot = disable_slot, 1477441b062SJan Glauber .get_power_status = get_power_status, 1487441b062SJan Glauber .get_adapter_status = get_adapter_status, 1497441b062SJan Glauber }; 1507441b062SJan Glauber 1517441b062SJan Glauber static int init_pci_slot(struct zpci_dev *zdev) 1527441b062SJan Glauber { 1537441b062SJan Glauber struct hotplug_slot *hotplug_slot; 1547441b062SJan Glauber struct hotplug_slot_info *info; 1557441b062SJan Glauber char name[SLOT_NAME_SIZE]; 1567441b062SJan Glauber struct slot *slot; 1577441b062SJan Glauber int rc; 1587441b062SJan Glauber 1597441b062SJan Glauber if (!zdev) 1607441b062SJan Glauber return 0; 1617441b062SJan Glauber 1627441b062SJan Glauber slot = kzalloc(sizeof(*slot), GFP_KERNEL); 1637441b062SJan Glauber if (!slot) 1647441b062SJan Glauber goto error; 1657441b062SJan Glauber 1667441b062SJan Glauber hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); 1677441b062SJan Glauber if (!hotplug_slot) 1687441b062SJan Glauber goto error_hp; 1697441b062SJan Glauber hotplug_slot->private = slot; 1707441b062SJan Glauber 1717441b062SJan Glauber slot->hotplug_slot = hotplug_slot; 1727441b062SJan Glauber slot->zdev = zdev; 1737441b062SJan Glauber 1747441b062SJan Glauber info = kzalloc(sizeof(*info), GFP_KERNEL); 1757441b062SJan Glauber if (!info) 1767441b062SJan Glauber goto error_info; 1777441b062SJan Glauber hotplug_slot->info = info; 1787441b062SJan Glauber 1797441b062SJan Glauber hotplug_slot->ops = &s390_hotplug_slot_ops; 1807441b062SJan Glauber hotplug_slot->release = &release_slot; 1817441b062SJan Glauber 1827441b062SJan Glauber get_power_status(hotplug_slot, &info->power_status); 1837441b062SJan Glauber get_adapter_status(hotplug_slot, &info->adapter_status); 1847441b062SJan Glauber 1857441b062SJan Glauber snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); 1867441b062SJan Glauber rc = pci_hp_register(slot->hotplug_slot, zdev->bus, 1877441b062SJan Glauber ZPCI_DEVFN, name); 1887441b062SJan Glauber if (rc) { 1897441b062SJan Glauber pr_err("pci_hp_register failed with error %d\n", rc); 1907441b062SJan Glauber goto error_reg; 1917441b062SJan Glauber } 1927441b062SJan Glauber list_add(&slot->slot_list, &s390_hotplug_slot_list); 1937441b062SJan Glauber return 0; 1947441b062SJan Glauber 1957441b062SJan Glauber error_reg: 1967441b062SJan Glauber kfree(info); 1977441b062SJan Glauber error_info: 1987441b062SJan Glauber kfree(hotplug_slot); 1997441b062SJan Glauber error_hp: 2007441b062SJan Glauber kfree(slot); 2017441b062SJan Glauber error: 2027441b062SJan Glauber return -ENOMEM; 2037441b062SJan Glauber } 2047441b062SJan Glauber 2057441b062SJan Glauber static void exit_pci_slot(struct zpci_dev *zdev) 2067441b062SJan Glauber { 2077441b062SJan Glauber struct list_head *tmp, *n; 2087441b062SJan Glauber struct slot *slot; 2097441b062SJan Glauber 2107441b062SJan Glauber list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { 2117441b062SJan Glauber slot = list_entry(tmp, struct slot, slot_list); 2127441b062SJan Glauber if (slot->zdev != zdev) 2137441b062SJan Glauber continue; 2147441b062SJan Glauber list_del(&slot->slot_list); 2157441b062SJan Glauber pci_hp_deregister(slot->hotplug_slot); 2167441b062SJan Glauber } 2177441b062SJan Glauber } 2187441b062SJan Glauber 21953923354SSebastian Ott static struct pci_hp_callback_ops hp_ops = { 22053923354SSebastian Ott .create_slot = init_pci_slot, 22153923354SSebastian Ott .remove_slot = exit_pci_slot, 22253923354SSebastian Ott }; 22353923354SSebastian Ott 22453923354SSebastian Ott static void __init init_pci_slots(void) 22553923354SSebastian Ott { 22653923354SSebastian Ott struct zpci_dev *zdev; 22753923354SSebastian Ott 22853923354SSebastian Ott /* 22953923354SSebastian Ott * Create a structure for each slot, and register that slot 23053923354SSebastian Ott * with the pci_hotplug subsystem. 23153923354SSebastian Ott */ 23253923354SSebastian Ott mutex_lock(&zpci_list_lock); 23353923354SSebastian Ott list_for_each_entry(zdev, &zpci_list, entry) { 23453923354SSebastian Ott init_pci_slot(zdev); 23553923354SSebastian Ott } 23653923354SSebastian Ott mutex_unlock(&zpci_list_lock); 23753923354SSebastian Ott } 23853923354SSebastian Ott 2397441b062SJan Glauber static void __exit exit_pci_slots(void) 2407441b062SJan Glauber { 2417441b062SJan Glauber struct list_head *tmp, *n; 2427441b062SJan Glauber struct slot *slot; 2437441b062SJan Glauber 2447441b062SJan Glauber /* 2457441b062SJan Glauber * Unregister all of our slots with the pci_hotplug subsystem. 2467441b062SJan Glauber * Memory will be freed in release_slot() callback after slot's 2477441b062SJan Glauber * lifespan is finished. 2487441b062SJan Glauber */ 2497441b062SJan Glauber list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { 2507441b062SJan Glauber slot = list_entry(tmp, struct slot, slot_list); 2517441b062SJan Glauber list_del(&slot->slot_list); 2527441b062SJan Glauber pci_hp_deregister(slot->hotplug_slot); 2537441b062SJan Glauber } 2547441b062SJan Glauber } 2557441b062SJan Glauber 2567441b062SJan Glauber static int __init pci_hotplug_s390_init(void) 2577441b062SJan Glauber { 2581e5635d1SHeiko Carstens if (!s390_pci_probe) 2597441b062SJan Glauber return -EOPNOTSUPP; 2607441b062SJan Glauber 26153923354SSebastian Ott zpci_register_hp_ops(&hp_ops); 26253923354SSebastian Ott init_pci_slots(); 26353923354SSebastian Ott 26453923354SSebastian Ott return 0; 2657441b062SJan Glauber } 2667441b062SJan Glauber 2677441b062SJan Glauber static void __exit pci_hotplug_s390_exit(void) 2687441b062SJan Glauber { 2697441b062SJan Glauber exit_pci_slots(); 27053923354SSebastian Ott zpci_deregister_hp_ops(); 2717441b062SJan Glauber } 2727441b062SJan Glauber 2737441b062SJan Glauber module_init(pci_hotplug_s390_init); 2747441b062SJan Glauber module_exit(pci_hotplug_s390_exit); 275