aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2013-07-23 22:25:01 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-07-24 00:18:49 -0400
commitab55d2187da27414f78056810713c92f9a4350c2 (patch)
tree49df4aa27f4e6b946ef1c7e892478502a9d7bee6 /arch
parent91150af3adf67463c4ca7d72d4fe1a84da37792c (diff)
powerpc/eeh: Introdce flag to protect sysfs
The patch introduces flag EEH_DEV_SYSFS to keep track that the sysfs entries for the corresponding EEH device (then PCI device) has been added or removed, in order to avoid race condition. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/eeh.h2
-rw-r--r--arch/powerpc/kernel/eeh.c2
-rw-r--r--arch/powerpc/kernel/eeh_sysfs.c16
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c4
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c2
5 files changed, 22 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 4199d9943277..d3e5e9bc8f94 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -90,6 +90,8 @@ struct eeh_pe {
90#define EEH_DEV_IRQ_DISABLED (1 << 3) /* Interrupt disabled */ 90#define EEH_DEV_IRQ_DISABLED (1 << 3) /* Interrupt disabled */
91#define EEH_DEV_DISCONNECTED (1 << 4) /* Removing from PE */ 91#define EEH_DEV_DISCONNECTED (1 << 4) /* Removing from PE */
92 92
93#define EEH_DEV_SYSFS (1 << 8) /* Sysfs created */
94
93struct eeh_dev { 95struct eeh_dev {
94 int mode; /* EEH mode */ 96 int mode; /* EEH mode */
95 int class_code; /* Class code of the device */ 97 int class_code; /* Class code of the device */
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index a5783f1a7a96..ea9414c8088d 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -911,6 +911,7 @@ void eeh_add_device_late(struct pci_dev *dev)
911 eeh_rmv_from_parent_pe(edev); 911 eeh_rmv_from_parent_pe(edev);
912 eeh_addr_cache_rmv_dev(edev->pdev); 912 eeh_addr_cache_rmv_dev(edev->pdev);
913 eeh_sysfs_remove_device(edev->pdev); 913 eeh_sysfs_remove_device(edev->pdev);
914 edev->mode &= ~EEH_DEV_SYSFS;
914 915
915 edev->pdev = NULL; 916 edev->pdev = NULL;
916 dev->dev.archdata.edev = NULL; 917 dev->dev.archdata.edev = NULL;
@@ -1016,6 +1017,7 @@ void eeh_remove_device(struct pci_dev *dev)
1016 1017
1017 eeh_addr_cache_rmv_dev(dev); 1018 eeh_addr_cache_rmv_dev(dev);
1018 eeh_sysfs_remove_device(dev); 1019 eeh_sysfs_remove_device(dev);
1020 edev->mode &= ~EEH_DEV_SYSFS;
1019} 1021}
1020 1022
1021static int proc_eeh_show(struct seq_file *m, void *v) 1023static int proc_eeh_show(struct seq_file *m, void *v)
diff --git a/arch/powerpc/kernel/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c
index 61e2a1452131..5d753d4f2c75 100644
--- a/arch/powerpc/kernel/eeh_sysfs.c
+++ b/arch/powerpc/kernel/eeh_sysfs.c
@@ -56,26 +56,40 @@ EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x");
56 56
57void eeh_sysfs_add_device(struct pci_dev *pdev) 57void eeh_sysfs_add_device(struct pci_dev *pdev)
58{ 58{
59 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
59 int rc=0; 60 int rc=0;
60 61
62 if (edev && (edev->mode & EEH_DEV_SYSFS))
63 return;
64
61 rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); 65 rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
62 rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); 66 rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr);
63 rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); 67 rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
64 68
65 if (rc) 69 if (rc)
66 printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); 70 printk(KERN_WARNING "EEH: Unable to create sysfs entries\n");
71 else if (edev)
72 edev->mode |= EEH_DEV_SYSFS;
67} 73}
68 74
69void eeh_sysfs_remove_device(struct pci_dev *pdev) 75void eeh_sysfs_remove_device(struct pci_dev *pdev)
70{ 76{
77 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
78
71 /* 79 /*
72 * The parent directory might have been removed. We needn't 80 * The parent directory might have been removed. We needn't
73 * continue for that case. 81 * continue for that case.
74 */ 82 */
75 if (!pdev->dev.kobj.sd) 83 if (!pdev->dev.kobj.sd) {
84 if (edev)
85 edev->mode &= ~EEH_DEV_SYSFS;
76 return; 86 return;
87 }
77 88
78 device_remove_file(&pdev->dev, &dev_attr_eeh_mode); 89 device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
79 device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); 90 device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr);
80 device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); 91 device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
92
93 if (edev)
94 edev->mode &= ~EEH_DEV_SYSFS;
81} 95}
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index 4361a5c7f3ab..79663d26e6ea 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -122,8 +122,8 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
122 return 0; 122 return 0;
123 123
124 /* Initialize eeh device */ 124 /* Initialize eeh device */
125 edev->class_code = dev->class; 125 edev->class_code = dev->class;
126 edev->mode = 0; 126 edev->mode &= 0xFFFFFF00;
127 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 127 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
128 edev->mode |= EEH_DEV_BRIDGE; 128 edev->mode |= EEH_DEV_BRIDGE;
129 if (pci_is_pcie(dev)) { 129 if (pci_is_pcie(dev)) {
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 9e80f0af311f..7fbc25b1813f 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -218,7 +218,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
218 */ 218 */
219 edev->class_code = *class_code; 219 edev->class_code = *class_code;
220 edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP); 220 edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP);
221 edev->mode = 0; 221 edev->mode &= 0xFFFFFF00;
222 if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { 222 if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
223 edev->mode |= EEH_DEV_BRIDGE; 223 edev->mode |= EEH_DEV_BRIDGE;
224 if (edev->pcie_cap) { 224 if (edev->pcie_cap) {