Browse Source

s390/pci: update function handle after resume from hibernate

Function handles may change while the system was in hibernation
use list pci functions and update the function handles.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Sebastian Ott 12 years ago
parent
commit
57b5918c33
4 changed files with 45 additions and 5 deletions
  1. 4 0
      arch/s390/include/asm/pci.h
  2. 2 0
      arch/s390/kernel/suspend.c
  3. 10 5
      arch/s390/pci/pci.c
  4. 29 0
      arch/s390/pci/pci_clp.c

+ 4 - 0
arch/s390/include/asm/pci.h

@@ -6,6 +6,7 @@
 /* must be set before including pci_clp.h */
 #define PCI_BAR_COUNT	6
 
+#include <linux/pci.h>
 #include <asm-generic/pci.h>
 #include <asm-generic/pci-dma-compat.h>
 #include <asm/pci_clp.h>
@@ -137,6 +138,7 @@ int zpci_unregister_ioat(struct zpci_dev *, u8);
 /* CLP */
 int clp_scan_pci_devices(void);
 int clp_rescan_pci_devices(void);
+int clp_rescan_pci_devices_simple(void);
 int clp_add_pci_device(u32, u32, int);
 int clp_enable_fh(struct zpci_dev *, u8);
 int clp_disable_fh(struct zpci_dev *);
@@ -145,9 +147,11 @@ int clp_disable_fh(struct zpci_dev *);
 /* Error handling and recovery */
 void zpci_event_error(void *);
 void zpci_event_availability(void *);
+void zpci_rescan(void);
 #else /* CONFIG_PCI */
 static inline void zpci_event_error(void *e) {}
 static inline void zpci_event_availability(void *e) {}
+static inline void zpci_rescan(void) {}
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_HOTPLUG_PCI_S390

+ 2 - 0
arch/s390/kernel/suspend.c

@@ -12,6 +12,7 @@
 #include <asm/ctl_reg.h>
 #include <asm/ipl.h>
 #include <asm/cio.h>
+#include <asm/pci.h>
 
 /*
  * References to section boundaries
@@ -219,4 +220,5 @@ void s390_early_resume(void)
 {
 	lgr_info_log();
 	channel_subsystem_reinit();
+	zpci_rescan();
 }

+ 10 - 5
arch/s390/pci/pci.c

@@ -46,7 +46,7 @@
 
 /* list of all detected zpci devices */
 static LIST_HEAD(zpci_list);
-static DEFINE_MUTEX(zpci_list_lock);
+static DEFINE_SPINLOCK(zpci_list_lock);
 
 static void zpci_enable_irq(struct irq_data *data);
 static void zpci_disable_irq(struct irq_data *data);
@@ -88,14 +88,14 @@ struct zpci_dev *get_zdev_by_fid(u32 fid)
 {
 	struct zpci_dev *tmp, *zdev = NULL;
 
-	mutex_lock(&zpci_list_lock);
+	spin_lock(&zpci_list_lock);
 	list_for_each_entry(tmp, &zpci_list, entry) {
 		if (tmp->fid == fid) {
 			zdev = tmp;
 			break;
 		}
 	}
-	mutex_unlock(&zpci_list_lock);
+	spin_unlock(&zpci_list_lock);
 	return zdev;
 }
 
@@ -821,9 +821,9 @@ int zpci_create_device(struct zpci_dev *zdev)
 	if (rc)
 		goto out_disable;
 
-	mutex_lock(&zpci_list_lock);
+	spin_lock(&zpci_list_lock);
 	list_add_tail(&zdev->entry, &zpci_list);
-	mutex_unlock(&zpci_list_lock);
+	spin_unlock(&zpci_list_lock);
 
 	zpci_init_slot(zdev);
 
@@ -939,3 +939,8 @@ out:
 	return rc;
 }
 subsys_initcall_sync(pci_base_init);
+
+void zpci_rescan(void)
+{
+	clp_rescan_pci_devices_simple();
+}

+ 29 - 0
arch/s390/pci/pci_clp.c

@@ -319,6 +319,20 @@ static void __clp_rescan(struct clp_fh_list_entry *entry)
 	}
 }
 
+static void __clp_update(struct clp_fh_list_entry *entry)
+{
+	struct zpci_dev *zdev;
+
+	if (!entry->vendor_id)
+		return;
+
+	zdev = get_zdev_by_fid(entry->fid);
+	if (!zdev)
+		return;
+
+	zdev->fh = entry->fh;
+}
+
 int clp_scan_pci_devices(void)
 {
 	struct clp_req_rsp_list_pci *rrb;
@@ -348,3 +362,18 @@ int clp_rescan_pci_devices(void)
 	clp_free_block(rrb);
 	return rc;
 }
+
+int clp_rescan_pci_devices_simple(void)
+{
+	struct clp_req_rsp_list_pci *rrb;
+	int rc;
+
+	rrb = clp_alloc_block(GFP_NOWAIT);
+	if (!rrb)
+		return -ENOMEM;
+
+	rc = clp_list_pci(rrb, __clp_update);
+
+	clp_free_block(rrb);
+	return rc;
+}