1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * PCI Hot Plug Controller Driver for System z 4 * 5 * Copyright 2012 IBM Corp. 6 * 7 * Author(s): 8 * Jan Glauber <jang@linux.vnet.ibm.com> 9 */ 10 11 #define KMSG_COMPONENT "zpci" 12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 13 14 #include <linux/kernel.h> 15 #include <linux/slab.h> 16 #include <linux/pci.h> 17 #include <linux/pci_hotplug.h> 18 #include <asm/pci_debug.h> 19 #include <asm/sclp.h> 20 21 #define SLOT_NAME_SIZE 10 22 23 static int enable_slot(struct hotplug_slot *hotplug_slot) 24 { 25 struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, 26 hotplug_slot); 27 int rc; 28 29 if (zdev->state != ZPCI_FN_STATE_STANDBY) 30 return -EIO; 31 32 rc = sclp_pci_configure(zdev->fid); 33 zpci_dbg(3, "conf fid:%x, rc:%d\n", zdev->fid, rc); 34 if (rc) 35 return rc; 36 zdev->state = ZPCI_FN_STATE_CONFIGURED; 37 38 return zpci_scan_configured_device(zdev, zdev->fh); 39 } 40 41 static int disable_slot(struct hotplug_slot *hotplug_slot) 42 { 43 struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, 44 hotplug_slot); 45 struct pci_dev *pdev; 46 47 if (zdev->state != ZPCI_FN_STATE_CONFIGURED) 48 return -EIO; 49 50 pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn); 51 if (pdev && pci_num_vf(pdev)) { 52 pci_dev_put(pdev); 53 return -EBUSY; 54 } 55 pci_dev_put(pdev); 56 57 return zpci_deconfigure_device(zdev); 58 } 59 60 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) 61 { 62 struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, 63 hotplug_slot); 64 65 switch (zdev->state) { 66 case ZPCI_FN_STATE_STANDBY: 67 *value = 0; 68 break; 69 default: 70 *value = 1; 71 break; 72 } 73 return 0; 74 } 75 76 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) 77 { 78 /* if the slot exits it always contains a function */ 79 *value = 1; 80 return 0; 81 } 82 83 static const struct hotplug_slot_ops s390_hotplug_slot_ops = { 84 .enable_slot = enable_slot, 85 .disable_slot = disable_slot, 86 .get_power_status = get_power_status, 87 .get_adapter_status = get_adapter_status, 88 }; 89 90 int zpci_init_slot(struct zpci_dev *zdev) 91 { 92 char name[SLOT_NAME_SIZE]; 93 struct zpci_bus *zbus = zdev->zbus; 94 95 zdev->hotplug_slot.ops = &s390_hotplug_slot_ops; 96 97 snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); 98 return pci_hp_register(&zdev->hotplug_slot, zbus->bus, 99 zdev->devfn, name); 100 } 101 102 void zpci_exit_slot(struct zpci_dev *zdev) 103 { 104 pci_hp_deregister(&zdev->hotplug_slot); 105 } 106