| .. | .. |
|---|
| 19 | 19 | #include <asm/sclp.h> |
|---|
| 20 | 20 | |
|---|
| 21 | 21 | #define SLOT_NAME_SIZE 10 |
|---|
| 22 | | -static LIST_HEAD(s390_hotplug_slot_list); |
|---|
| 23 | 22 | |
|---|
| 24 | 23 | static int zpci_fn_configured(enum zpci_state state) |
|---|
| 25 | 24 | { |
|---|
| .. | .. |
|---|
| 27 | 26 | state == ZPCI_FN_STATE_ONLINE; |
|---|
| 28 | 27 | } |
|---|
| 29 | 28 | |
|---|
| 30 | | -/* |
|---|
| 31 | | - * struct slot - slot information for each *physical* slot |
|---|
| 32 | | - */ |
|---|
| 33 | | -struct slot { |
|---|
| 34 | | - struct list_head slot_list; |
|---|
| 35 | | - struct hotplug_slot *hotplug_slot; |
|---|
| 36 | | - struct zpci_dev *zdev; |
|---|
| 37 | | -}; |
|---|
| 38 | | - |
|---|
| 39 | | -static inline int slot_configure(struct slot *slot) |
|---|
| 29 | +static inline int zdev_configure(struct zpci_dev *zdev) |
|---|
| 40 | 30 | { |
|---|
| 41 | | - int ret = sclp_pci_configure(slot->zdev->fid); |
|---|
| 31 | + int ret = sclp_pci_configure(zdev->fid); |
|---|
| 42 | 32 | |
|---|
| 43 | | - zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret); |
|---|
| 33 | + zpci_dbg(3, "conf fid:%x, rc:%d\n", zdev->fid, ret); |
|---|
| 44 | 34 | if (!ret) |
|---|
| 45 | | - slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; |
|---|
| 35 | + zdev->state = ZPCI_FN_STATE_CONFIGURED; |
|---|
| 46 | 36 | |
|---|
| 47 | 37 | return ret; |
|---|
| 48 | 38 | } |
|---|
| 49 | 39 | |
|---|
| 50 | | -static inline int slot_deconfigure(struct slot *slot) |
|---|
| 40 | +static inline int zdev_deconfigure(struct zpci_dev *zdev) |
|---|
| 51 | 41 | { |
|---|
| 52 | | - int ret = sclp_pci_deconfigure(slot->zdev->fid); |
|---|
| 42 | + int ret = sclp_pci_deconfigure(zdev->fid); |
|---|
| 53 | 43 | |
|---|
| 54 | | - zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret); |
|---|
| 44 | + zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret); |
|---|
| 55 | 45 | if (!ret) |
|---|
| 56 | | - slot->zdev->state = ZPCI_FN_STATE_STANDBY; |
|---|
| 46 | + zdev->state = ZPCI_FN_STATE_STANDBY; |
|---|
| 57 | 47 | |
|---|
| 58 | 48 | return ret; |
|---|
| 59 | 49 | } |
|---|
| 60 | 50 | |
|---|
| 61 | 51 | static int enable_slot(struct hotplug_slot *hotplug_slot) |
|---|
| 62 | 52 | { |
|---|
| 63 | | - struct slot *slot = hotplug_slot->private; |
|---|
| 53 | + struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, |
|---|
| 54 | + hotplug_slot); |
|---|
| 55 | + struct zpci_bus *zbus = zdev->zbus; |
|---|
| 64 | 56 | int rc; |
|---|
| 65 | 57 | |
|---|
| 66 | | - if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) |
|---|
| 58 | + if (zdev->state != ZPCI_FN_STATE_STANDBY) |
|---|
| 67 | 59 | return -EIO; |
|---|
| 68 | 60 | |
|---|
| 69 | | - rc = slot_configure(slot); |
|---|
| 61 | + rc = zdev_configure(zdev); |
|---|
| 70 | 62 | if (rc) |
|---|
| 71 | 63 | return rc; |
|---|
| 72 | 64 | |
|---|
| 73 | | - rc = zpci_enable_device(slot->zdev); |
|---|
| 65 | + rc = zpci_enable_device(zdev); |
|---|
| 74 | 66 | if (rc) |
|---|
| 75 | 67 | goto out_deconfigure; |
|---|
| 76 | 68 | |
|---|
| 77 | | - pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); |
|---|
| 69 | + pci_scan_slot(zbus->bus, zdev->devfn); |
|---|
| 78 | 70 | pci_lock_rescan_remove(); |
|---|
| 79 | | - pci_bus_add_devices(slot->zdev->bus); |
|---|
| 71 | + pci_bus_add_devices(zbus->bus); |
|---|
| 80 | 72 | pci_unlock_rescan_remove(); |
|---|
| 81 | 73 | |
|---|
| 82 | 74 | return rc; |
|---|
| 83 | 75 | |
|---|
| 84 | 76 | out_deconfigure: |
|---|
| 85 | | - slot_deconfigure(slot); |
|---|
| 77 | + zdev_deconfigure(zdev); |
|---|
| 86 | 78 | return rc; |
|---|
| 87 | 79 | } |
|---|
| 88 | 80 | |
|---|
| 89 | 81 | static int disable_slot(struct hotplug_slot *hotplug_slot) |
|---|
| 90 | 82 | { |
|---|
| 91 | | - struct slot *slot = hotplug_slot->private; |
|---|
| 83 | + struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, |
|---|
| 84 | + hotplug_slot); |
|---|
| 92 | 85 | struct pci_dev *pdev; |
|---|
| 93 | 86 | int rc; |
|---|
| 94 | 87 | |
|---|
| 95 | | - if (!zpci_fn_configured(slot->zdev->state)) |
|---|
| 88 | + if (!zpci_fn_configured(zdev->state)) |
|---|
| 96 | 89 | return -EIO; |
|---|
| 97 | 90 | |
|---|
| 98 | | - pdev = pci_get_slot(slot->zdev->bus, ZPCI_DEVFN); |
|---|
| 99 | | - if (pdev) { |
|---|
| 100 | | - pci_stop_and_remove_bus_device_locked(pdev); |
|---|
| 91 | + pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn); |
|---|
| 92 | + if (pdev && pci_num_vf(pdev)) { |
|---|
| 101 | 93 | pci_dev_put(pdev); |
|---|
| 94 | + return -EBUSY; |
|---|
| 102 | 95 | } |
|---|
| 96 | + pci_dev_put(pdev); |
|---|
| 103 | 97 | |
|---|
| 104 | | - rc = zpci_disable_device(slot->zdev); |
|---|
| 98 | + zpci_remove_device(zdev, false); |
|---|
| 99 | + |
|---|
| 100 | + rc = zpci_disable_device(zdev); |
|---|
| 105 | 101 | if (rc) |
|---|
| 106 | 102 | return rc; |
|---|
| 107 | 103 | |
|---|
| 108 | | - return slot_deconfigure(slot); |
|---|
| 104 | + return zdev_deconfigure(zdev); |
|---|
| 109 | 105 | } |
|---|
| 110 | 106 | |
|---|
| 111 | 107 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) |
|---|
| 112 | 108 | { |
|---|
| 113 | | - struct slot *slot = hotplug_slot->private; |
|---|
| 109 | + struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev, |
|---|
| 110 | + hotplug_slot); |
|---|
| 114 | 111 | |
|---|
| 115 | | - switch (slot->zdev->state) { |
|---|
| 116 | | - case ZPCI_FN_STATE_STANDBY: |
|---|
| 117 | | - *value = 0; |
|---|
| 118 | | - break; |
|---|
| 119 | | - default: |
|---|
| 120 | | - *value = 1; |
|---|
| 121 | | - break; |
|---|
| 122 | | - } |
|---|
| 112 | + *value = zpci_is_device_configured(zdev) ? 1 : 0; |
|---|
| 123 | 113 | return 0; |
|---|
| 124 | 114 | } |
|---|
| 125 | 115 | |
|---|
| .. | .. |
|---|
| 130 | 120 | return 0; |
|---|
| 131 | 121 | } |
|---|
| 132 | 122 | |
|---|
| 133 | | -static struct hotplug_slot_ops s390_hotplug_slot_ops = { |
|---|
| 123 | +static const struct hotplug_slot_ops s390_hotplug_slot_ops = { |
|---|
| 134 | 124 | .enable_slot = enable_slot, |
|---|
| 135 | 125 | .disable_slot = disable_slot, |
|---|
| 136 | 126 | .get_power_status = get_power_status, |
|---|
| .. | .. |
|---|
| 139 | 129 | |
|---|
| 140 | 130 | int zpci_init_slot(struct zpci_dev *zdev) |
|---|
| 141 | 131 | { |
|---|
| 142 | | - struct hotplug_slot *hotplug_slot; |
|---|
| 143 | | - struct hotplug_slot_info *info; |
|---|
| 144 | 132 | char name[SLOT_NAME_SIZE]; |
|---|
| 145 | | - struct slot *slot; |
|---|
| 146 | | - int rc; |
|---|
| 133 | + struct zpci_bus *zbus = zdev->zbus; |
|---|
| 147 | 134 | |
|---|
| 148 | | - if (!zdev) |
|---|
| 149 | | - return 0; |
|---|
| 150 | | - |
|---|
| 151 | | - slot = kzalloc(sizeof(*slot), GFP_KERNEL); |
|---|
| 152 | | - if (!slot) |
|---|
| 153 | | - goto error; |
|---|
| 154 | | - |
|---|
| 155 | | - hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); |
|---|
| 156 | | - if (!hotplug_slot) |
|---|
| 157 | | - goto error_hp; |
|---|
| 158 | | - hotplug_slot->private = slot; |
|---|
| 159 | | - |
|---|
| 160 | | - slot->hotplug_slot = hotplug_slot; |
|---|
| 161 | | - slot->zdev = zdev; |
|---|
| 162 | | - |
|---|
| 163 | | - info = kzalloc(sizeof(*info), GFP_KERNEL); |
|---|
| 164 | | - if (!info) |
|---|
| 165 | | - goto error_info; |
|---|
| 166 | | - hotplug_slot->info = info; |
|---|
| 167 | | - |
|---|
| 168 | | - hotplug_slot->ops = &s390_hotplug_slot_ops; |
|---|
| 169 | | - |
|---|
| 170 | | - get_power_status(hotplug_slot, &info->power_status); |
|---|
| 171 | | - get_adapter_status(hotplug_slot, &info->adapter_status); |
|---|
| 135 | + zdev->hotplug_slot.ops = &s390_hotplug_slot_ops; |
|---|
| 172 | 136 | |
|---|
| 173 | 137 | snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); |
|---|
| 174 | | - rc = pci_hp_register(slot->hotplug_slot, zdev->bus, |
|---|
| 175 | | - ZPCI_DEVFN, name); |
|---|
| 176 | | - if (rc) |
|---|
| 177 | | - goto error_reg; |
|---|
| 178 | | - |
|---|
| 179 | | - list_add(&slot->slot_list, &s390_hotplug_slot_list); |
|---|
| 180 | | - return 0; |
|---|
| 181 | | - |
|---|
| 182 | | -error_reg: |
|---|
| 183 | | - kfree(info); |
|---|
| 184 | | -error_info: |
|---|
| 185 | | - kfree(hotplug_slot); |
|---|
| 186 | | -error_hp: |
|---|
| 187 | | - kfree(slot); |
|---|
| 188 | | -error: |
|---|
| 189 | | - return -ENOMEM; |
|---|
| 138 | + return pci_hp_register(&zdev->hotplug_slot, zbus->bus, |
|---|
| 139 | + zdev->devfn, name); |
|---|
| 190 | 140 | } |
|---|
| 191 | 141 | |
|---|
| 192 | 142 | void zpci_exit_slot(struct zpci_dev *zdev) |
|---|
| 193 | 143 | { |
|---|
| 194 | | - struct slot *slot, *next; |
|---|
| 195 | | - |
|---|
| 196 | | - list_for_each_entry_safe(slot, next, &s390_hotplug_slot_list, |
|---|
| 197 | | - slot_list) { |
|---|
| 198 | | - if (slot->zdev != zdev) |
|---|
| 199 | | - continue; |
|---|
| 200 | | - list_del(&slot->slot_list); |
|---|
| 201 | | - pci_hp_deregister(slot->hotplug_slot); |
|---|
| 202 | | - kfree(slot->hotplug_slot->info); |
|---|
| 203 | | - kfree(slot->hotplug_slot); |
|---|
| 204 | | - kfree(slot); |
|---|
| 205 | | - } |
|---|
| 144 | + pci_hp_deregister(&zdev->hotplug_slot); |
|---|
| 206 | 145 | } |
|---|