aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2017-06-20 09:56:05 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2017-06-28 01:32:13 -0400
commit01553d9a2ba7c658bf9e9e5c65466508c1bd6db5 (patch)
treee36c325b156531f878a7556b28ac35bd84132909
parent623bd44d3f277b7bbe16e0e091bd361e75964b5d (diff)
s390/pci: fix handling of PEC 306
In contrast to other hotplug events PEC 0x306 isn't about a single but multiple devices. Also there's no information on what happened to these devices. We correctly handled hotplug that way but failed to handle hot-unplug. This patch addresses that and implements hot-unplug of multiple devices via PEC 306. Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/pci.h2
-rw-r--r--arch/s390/pci/pci.c29
-rw-r--r--arch/s390/pci/pci_clp.c25
3 files changed, 24 insertions, 32 deletions
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index 280458c82104..f36b4b726057 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -161,9 +161,9 @@ int zpci_create_device(struct zpci_dev *);
161void zpci_remove_device(struct zpci_dev *zdev); 161void zpci_remove_device(struct zpci_dev *zdev);
162int zpci_enable_device(struct zpci_dev *); 162int zpci_enable_device(struct zpci_dev *);
163int zpci_disable_device(struct zpci_dev *); 163int zpci_disable_device(struct zpci_dev *);
164void zpci_stop_device(struct zpci_dev *);
165int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64); 164int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
166int zpci_unregister_ioat(struct zpci_dev *, u8); 165int zpci_unregister_ioat(struct zpci_dev *, u8);
166void zpci_remove_reserved_devices(void);
167 167
168/* CLP */ 168/* CLP */
169int clp_scan_pci_devices(void); 169int clp_scan_pci_devices(void);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index f4928bc57773..114b390d80f9 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -86,6 +86,25 @@ struct zpci_dev *get_zdev_by_fid(u32 fid)
86 return zdev; 86 return zdev;
87} 87}
88 88
89void zpci_remove_reserved_devices(void)
90{
91 struct zpci_dev *tmp, *zdev;
92 enum zpci_state state;
93 LIST_HEAD(remove);
94
95 spin_lock(&zpci_list_lock);
96 list_for_each_entry_safe(zdev, tmp, &zpci_list, entry) {
97 if (zdev->state == ZPCI_FN_STATE_STANDBY &&
98 !clp_get_state(zdev->fid, &state) &&
99 state == ZPCI_FN_STATE_RESERVED)
100 list_move_tail(&zdev->entry, &remove);
101 }
102 spin_unlock(&zpci_list_lock);
103
104 list_for_each_entry_safe(zdev, tmp, &remove, entry)
105 zpci_remove_device(zdev);
106}
107
89static struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus) 108static struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus)
90{ 109{
91 return (bus && bus->sysdata) ? (struct zpci_dev *) bus->sysdata : NULL; 110 return (bus && bus->sysdata) ? (struct zpci_dev *) bus->sysdata : NULL;
@@ -845,16 +864,6 @@ out:
845 return rc; 864 return rc;
846} 865}
847 866
848void zpci_stop_device(struct zpci_dev *zdev)
849{
850 zpci_dma_exit_device(zdev);
851 /*
852 * Note: SCLP disables fh via set-pci-fn so don't
853 * do that here.
854 */
855}
856EXPORT_SYMBOL_GPL(zpci_stop_device);
857
858void zpci_remove_device(struct zpci_dev *zdev) 867void zpci_remove_device(struct zpci_dev *zdev)
859{ 868{
860 if (!zdev->bus) 869 if (!zdev->bus)
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c
index 267cdd69e6da..3a5cd84e5a3b 100644
--- a/arch/s390/pci/pci_clp.c
+++ b/arch/s390/pci/pci_clp.c
@@ -335,33 +335,14 @@ out:
335 335
336static void __clp_add(struct clp_fh_list_entry *entry, void *data) 336static void __clp_add(struct clp_fh_list_entry *entry, void *data)
337{ 337{
338 if (!entry->vendor_id)
339 return;
340
341 clp_add_pci_device(entry->fid, entry->fh, entry->config_state);
342}
343
344static void __clp_rescan(struct clp_fh_list_entry *entry, void *data)
345{
346 struct zpci_dev *zdev; 338 struct zpci_dev *zdev;
347 339
348 if (!entry->vendor_id) 340 if (!entry->vendor_id)
349 return; 341 return;
350 342
351 zdev = get_zdev_by_fid(entry->fid); 343 zdev = get_zdev_by_fid(entry->fid);
352 if (!zdev) { 344 if (!zdev)
353 clp_add_pci_device(entry->fid, entry->fh, entry->config_state); 345 clp_add_pci_device(entry->fid, entry->fh, entry->config_state);
354 return;
355 }
356
357 if (!entry->config_state) {
358 /*
359 * The handle is already disabled, that means no iota/irq freeing via
360 * the firmware interfaces anymore. Need to free resources manually
361 * (DMA memory, debug, sysfs)...
362 */
363 zpci_stop_device(zdev);
364 }
365} 346}
366 347
367static void __clp_update(struct clp_fh_list_entry *entry, void *data) 348static void __clp_update(struct clp_fh_list_entry *entry, void *data)
@@ -398,11 +379,13 @@ int clp_rescan_pci_devices(void)
398 struct clp_req_rsp_list_pci *rrb; 379 struct clp_req_rsp_list_pci *rrb;
399 int rc; 380 int rc;
400 381
382 zpci_remove_reserved_devices();
383
401 rrb = clp_alloc_block(GFP_KERNEL); 384 rrb = clp_alloc_block(GFP_KERNEL);
402 if (!rrb) 385 if (!rrb)
403 return -ENOMEM; 386 return -ENOMEM;
404 387
405 rc = clp_list_pci(rrb, NULL, __clp_rescan); 388 rc = clp_list_pci(rrb, NULL, __clp_add);
406 389
407 clp_free_block(rrb); 390 clp_free_block(rrb);
408 return rc; 391 return rc;