diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2013-07-23 22:25:01 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-07-24 00:18:49 -0400 |
commit | ab55d2187da27414f78056810713c92f9a4350c2 (patch) | |
tree | 49df4aa27f4e6b946ef1c7e892478502a9d7bee6 /arch | |
parent | 91150af3adf67463c4ca7d72d4fe1a84da37792c (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.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh_sysfs.c | 16 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/eeh-powernv.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_pseries.c | 2 |
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 | |||
93 | struct eeh_dev { | 95 | struct 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 | ||
1021 | static int proc_eeh_show(struct seq_file *m, void *v) | 1023 | static 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 | ||
57 | void eeh_sysfs_add_device(struct pci_dev *pdev) | 57 | void 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 | ||
69 | void eeh_sysfs_remove_device(struct pci_dev *pdev) | 75 | void 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) { |