diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/device.h | 3 | ||||
-rw-r--r-- | arch/powerpc/include/asm/eeh.h | 57 | ||||
-rw-r--r-- | arch/powerpc/kernel/of_platform.c | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/rtas_pci.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/Makefile | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_dev.c | 102 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 6 |
8 files changed, 173 insertions, 10 deletions
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index d57c08acedfc..63d5ca49cece 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h | |||
@@ -31,6 +31,9 @@ struct dev_archdata { | |||
31 | #ifdef CONFIG_SWIOTLB | 31 | #ifdef CONFIG_SWIOTLB |
32 | dma_addr_t max_direct_dma_addr; | 32 | dma_addr_t max_direct_dma_addr; |
33 | #endif | 33 | #endif |
34 | #ifdef CONFIG_EEH | ||
35 | struct eeh_dev *edev; | ||
36 | #endif | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | struct pdev_archdata { | 39 | struct pdev_archdata { |
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index ad8f31834e00..daaad91ed576 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h | |||
@@ -32,6 +32,43 @@ struct device_node; | |||
32 | #ifdef CONFIG_EEH | 32 | #ifdef CONFIG_EEH |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * The struct is used to trace EEH state for the associated | ||
36 | * PCI device node or PCI device. In future, it might | ||
37 | * represent PE as well so that the EEH device to form | ||
38 | * another tree except the currently existing tree of PCI | ||
39 | * buses and PCI devices | ||
40 | */ | ||
41 | #define EEH_MODE_SUPPORTED (1<<0) /* EEH supported on the device */ | ||
42 | #define EEH_MODE_NOCHECK (1<<1) /* EEH check should be skipped */ | ||
43 | #define EEH_MODE_ISOLATED (1<<2) /* The device has been isolated */ | ||
44 | #define EEH_MODE_RECOVERING (1<<3) /* Recovering the device */ | ||
45 | #define EEH_MODE_IRQ_DISABLED (1<<4) /* Interrupt disabled */ | ||
46 | |||
47 | struct eeh_dev { | ||
48 | int mode; /* EEH mode */ | ||
49 | int class_code; /* Class code of the device */ | ||
50 | int config_addr; /* Config address */ | ||
51 | int pe_config_addr; /* PE config address */ | ||
52 | int check_count; /* Times of ignored error */ | ||
53 | int freeze_count; /* Times of froze up */ | ||
54 | int false_positives; /* Times of reported #ff's */ | ||
55 | u32 config_space[16]; /* Saved PCI config space */ | ||
56 | struct pci_controller *phb; /* Associated PHB */ | ||
57 | struct device_node *dn; /* Associated device node */ | ||
58 | struct pci_dev *pdev; /* Associated PCI device */ | ||
59 | }; | ||
60 | |||
61 | static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev) | ||
62 | { | ||
63 | return edev->dn; | ||
64 | } | ||
65 | |||
66 | static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) | ||
67 | { | ||
68 | return edev->pdev; | ||
69 | } | ||
70 | |||
71 | /* | ||
35 | * The struct is used to trace the registered EEH operation | 72 | * The struct is used to trace the registered EEH operation |
36 | * callback functions. Actually, those operation callback | 73 | * callback functions. Actually, those operation callback |
37 | * functions are heavily platform dependent. That means the | 74 | * functions are heavily platform dependent. That means the |
@@ -70,19 +107,15 @@ struct eeh_ops { | |||
70 | extern struct eeh_ops *eeh_ops; | 107 | extern struct eeh_ops *eeh_ops; |
71 | extern int eeh_subsystem_enabled; | 108 | extern int eeh_subsystem_enabled; |
72 | 109 | ||
73 | /* Values for eeh_mode bits in device_node */ | ||
74 | #define EEH_MODE_SUPPORTED (1<<0) | ||
75 | #define EEH_MODE_NOCHECK (1<<1) | ||
76 | #define EEH_MODE_ISOLATED (1<<2) | ||
77 | #define EEH_MODE_RECOVERING (1<<3) | ||
78 | #define EEH_MODE_IRQ_DISABLED (1<<4) | ||
79 | |||
80 | /* | 110 | /* |
81 | * Max number of EEH freezes allowed before we consider the device | 111 | * Max number of EEH freezes allowed before we consider the device |
82 | * to be permanently disabled. | 112 | * to be permanently disabled. |
83 | */ | 113 | */ |
84 | #define EEH_MAX_ALLOWED_FREEZES 5 | 114 | #define EEH_MAX_ALLOWED_FREEZES 5 |
85 | 115 | ||
116 | void * __devinit eeh_dev_init(struct device_node *dn, void *data); | ||
117 | void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); | ||
118 | void __init eeh_dev_phb_init(void); | ||
86 | void __init eeh_init(void); | 119 | void __init eeh_init(void); |
87 | #ifdef CONFIG_PPC_PSERIES | 120 | #ifdef CONFIG_PPC_PSERIES |
88 | int __init eeh_pseries_init(void); | 121 | int __init eeh_pseries_init(void); |
@@ -113,6 +146,16 @@ void eeh_remove_bus_device(struct pci_dev *); | |||
113 | #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) | 146 | #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) |
114 | 147 | ||
115 | #else /* !CONFIG_EEH */ | 148 | #else /* !CONFIG_EEH */ |
149 | |||
150 | static inline void *eeh_dev_init(struct device_node *dn, void *data) | ||
151 | { | ||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { } | ||
156 | |||
157 | static inline void eeh_dev_phb_init(void) { } | ||
158 | |||
116 | static inline void eeh_init(void) { } | 159 | static inline void eeh_init(void) { } |
117 | 160 | ||
118 | #ifdef CONFIG_PPC_PSERIES | 161 | #ifdef CONFIG_PPC_PSERIES |
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index e1612dfb4a93..2049f2d00ffe 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c | |||
@@ -21,12 +21,13 @@ | |||
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_device.h> | 22 | #include <linux/of_device.h> |
23 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
24 | #include <linux/atomic.h> | ||
24 | 25 | ||
25 | #include <asm/errno.h> | 26 | #include <asm/errno.h> |
26 | #include <asm/topology.h> | 27 | #include <asm/topology.h> |
27 | #include <asm/pci-bridge.h> | 28 | #include <asm/pci-bridge.h> |
28 | #include <asm/ppc-pci.h> | 29 | #include <asm/ppc-pci.h> |
29 | #include <linux/atomic.h> | 30 | #include <asm/eeh.h> |
30 | 31 | ||
31 | #ifdef CONFIG_PPC_OF_PLATFORM_PCI | 32 | #ifdef CONFIG_PPC_OF_PLATFORM_PCI |
32 | 33 | ||
@@ -66,6 +67,9 @@ static int __devinit of_pci_phb_probe(struct platform_device *dev) | |||
66 | /* Init pci_dn data structures */ | 67 | /* Init pci_dn data structures */ |
67 | pci_devs_phb_init_dynamic(phb); | 68 | pci_devs_phb_init_dynamic(phb); |
68 | 69 | ||
70 | /* Create EEH devices for the PHB */ | ||
71 | eeh_dev_phb_init_dynamic(phb); | ||
72 | |||
69 | /* Register devices with EEH */ | 73 | /* Register devices with EEH */ |
70 | #ifdef CONFIG_EEH | 74 | #ifdef CONFIG_EEH |
71 | if (dev->dev.of_node->child) | 75 | if (dev->dev.of_node->child) |
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 6cd8f0196b6d..517bd86bc3f0 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -275,6 +275,9 @@ void __init find_and_init_phbs(void) | |||
275 | of_node_put(root); | 275 | of_node_put(root); |
276 | pci_devs_phb_init(); | 276 | pci_devs_phb_init(); |
277 | 277 | ||
278 | /* Create EEH devices for all PHBs */ | ||
279 | eeh_dev_phb_init(); | ||
280 | |||
278 | /* | 281 | /* |
279 | * pci_probe_only and pci_assign_all_buses can be set via properties | 282 | * pci_probe_only and pci_assign_all_buses can be set via properties |
280 | * in chosen. | 283 | * in chosen. |
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index ee873cf4fe46..c222189f5bb2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -6,7 +6,8 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ | |||
6 | firmware.o power.o dlpar.o mobility.o | 6 | firmware.o power.o dlpar.o mobility.o |
7 | obj-$(CONFIG_SMP) += smp.o | 7 | obj-$(CONFIG_SMP) += smp.o |
8 | obj-$(CONFIG_SCANLOG) += scanlog.o | 8 | obj-$(CONFIG_SCANLOG) += scanlog.o |
9 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o eeh_pseries.o | 9 | obj-$(CONFIG_EEH) += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \ |
10 | eeh_event.o eeh_sysfs.o eeh_pseries.o | ||
10 | obj-$(CONFIG_KEXEC) += kexec.o | 11 | obj-$(CONFIG_KEXEC) += kexec.o |
11 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o | 12 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o |
12 | obj-$(CONFIG_PSERIES_MSI) += msi.o | 13 | obj-$(CONFIG_PSERIES_MSI) += msi.o |
diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c new file mode 100644 index 000000000000..f3aed7dcae95 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_dev.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * The file intends to implement dynamic creation of EEH device, which will | ||
3 | * be bound with OF node and PCI device simutaneously. The EEH devices would | ||
4 | * be foundamental information for EEH core components to work proerly. Besides, | ||
5 | * We have to support multiple situations where dynamic creation of EEH device | ||
6 | * is required: | ||
7 | * | ||
8 | * 1) Before PCI emunation starts, we need create EEH devices according to the | ||
9 | * PCI sensitive OF nodes. | ||
10 | * 2) When PCI emunation is done, we need do the binding between PCI device and | ||
11 | * the associated EEH device. | ||
12 | * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device | ||
13 | * will be created while PCI sensitive OF node is detected from DR. | ||
14 | * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If | ||
15 | * PHB is newly inserted, we also need create EEH devices accordingly. | ||
16 | * | ||
17 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify | ||
20 | * it under the terms of the GNU General Public License as published by | ||
21 | * the Free Software Foundation; either version 2 of the License, or | ||
22 | * (at your option) any later version. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | * GNU General Public License for more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License | ||
30 | * along with this program; if not, write to the Free Software | ||
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
32 | */ | ||
33 | |||
34 | #include <linux/export.h> | ||
35 | #include <linux/gfp.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/pci.h> | ||
39 | #include <linux/string.h> | ||
40 | |||
41 | #include <asm/pci-bridge.h> | ||
42 | #include <asm/ppc-pci.h> | ||
43 | |||
44 | /** | ||
45 | * eeh_dev_init - Create EEH device according to OF node | ||
46 | * @dn: device node | ||
47 | * @data: PHB | ||
48 | * | ||
49 | * It will create EEH device according to the given OF node. The function | ||
50 | * might be called by PCI emunation, DR, PHB hotplug. | ||
51 | */ | ||
52 | void * __devinit eeh_dev_init(struct device_node *dn, void *data) | ||
53 | { | ||
54 | struct pci_controller *phb = data; | ||
55 | struct eeh_dev *edev; | ||
56 | |||
57 | /* Allocate EEH device */ | ||
58 | edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL); | ||
59 | if (!edev) { | ||
60 | pr_warning("%s: out of memory\n", __func__); | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | /* Associate EEH device with OF node */ | ||
65 | dn->edev = edev; | ||
66 | edev->dn = dn; | ||
67 | edev->phb = phb; | ||
68 | |||
69 | return NULL; | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB | ||
74 | * @phb: PHB | ||
75 | * | ||
76 | * Scan the PHB OF node and its child association, then create the | ||
77 | * EEH devices accordingly | ||
78 | */ | ||
79 | void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb) | ||
80 | { | ||
81 | struct device_node *dn = phb->dn; | ||
82 | |||
83 | /* EEH device for PHB */ | ||
84 | eeh_dev_init(dn, phb); | ||
85 | |||
86 | /* EEH devices for children OF nodes */ | ||
87 | traverse_pci_devices(dn, eeh_dev_init, phb); | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs | ||
92 | * | ||
93 | * Scan all the existing PHBs and create EEH devices for their OF | ||
94 | * nodes and their children OF nodes | ||
95 | */ | ||
96 | void __init eeh_dev_phb_init(void) | ||
97 | { | ||
98 | struct pci_controller *phb, *tmp; | ||
99 | |||
100 | list_for_each_entry_safe(phb, tmp, &hose_list, list_node) | ||
101 | eeh_dev_phb_init_dynamic(phb); | ||
102 | } | ||
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 55d4ec1bd1ac..fbb21fc3080b 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c | |||
@@ -147,6 +147,9 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | |||
147 | 147 | ||
148 | pci_devs_phb_init_dynamic(phb); | 148 | pci_devs_phb_init_dynamic(phb); |
149 | 149 | ||
150 | /* Create EEH devices for the PHB */ | ||
151 | eeh_dev_phb_init_dynamic(phb); | ||
152 | |||
150 | if (dn->child) | 153 | if (dn->child) |
151 | eeh_add_device_tree_early(dn); | 154 | eeh_add_device_tree_early(dn); |
152 | 155 | ||
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 62b827626ca6..8f137af616af 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -260,8 +260,12 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act | |||
260 | switch (action) { | 260 | switch (action) { |
261 | case PSERIES_RECONFIG_ADD: | 261 | case PSERIES_RECONFIG_ADD: |
262 | pci = np->parent->data; | 262 | pci = np->parent->data; |
263 | if (pci) | 263 | if (pci) { |
264 | update_dn_pci_info(np, pci->phb); | 264 | update_dn_pci_info(np, pci->phb); |
265 | |||
266 | /* Create EEH device for the OF node */ | ||
267 | eeh_dev_init(np, pci->phb); | ||
268 | } | ||
265 | break; | 269 | break; |
266 | default: | 270 | default: |
267 | err = NOTIFY_DONE; | 271 | err = NOTIFY_DONE; |