aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/device.h3
-rw-r--r--arch/powerpc/include/asm/eeh.h57
-rw-r--r--arch/powerpc/kernel/of_platform.c6
-rw-r--r--arch/powerpc/kernel/rtas_pci.c3
-rw-r--r--arch/powerpc/platforms/pseries/Makefile3
-rw-r--r--arch/powerpc/platforms/pseries/eeh_dev.c102
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c3
-rw-r--r--arch/powerpc/platforms/pseries/setup.c6
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
36struct pdev_archdata { 39struct 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
47struct 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
61static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev)
62{
63 return edev->dn;
64}
65
66static 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 {
70extern struct eeh_ops *eeh_ops; 107extern struct eeh_ops *eeh_ops;
71extern int eeh_subsystem_enabled; 108extern 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
116void * __devinit eeh_dev_init(struct device_node *dn, void *data);
117void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb);
118void __init eeh_dev_phb_init(void);
86void __init eeh_init(void); 119void __init eeh_init(void);
87#ifdef CONFIG_PPC_PSERIES 120#ifdef CONFIG_PPC_PSERIES
88int __init eeh_pseries_init(void); 121int __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
150static inline void *eeh_dev_init(struct device_node *dn, void *data)
151{
152 return NULL;
153}
154
155static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { }
156
157static inline void eeh_dev_phb_init(void) { }
158
116static inline void eeh_init(void) { } 159static 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
7obj-$(CONFIG_SMP) += smp.o 7obj-$(CONFIG_SMP) += smp.o
8obj-$(CONFIG_SCANLOG) += scanlog.o 8obj-$(CONFIG_SCANLOG) += scanlog.o
9obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o eeh_pseries.o 9obj-$(CONFIG_EEH) += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \
10 eeh_event.o eeh_sysfs.o eeh_pseries.o
10obj-$(CONFIG_KEXEC) += kexec.o 11obj-$(CONFIG_KEXEC) += kexec.o
11obj-$(CONFIG_PCI) += pci.o pci_dlpar.o 12obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
12obj-$(CONFIG_PSERIES_MSI) += msi.o 13obj-$(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 */
52void * __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 */
79void __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 */
96void __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;